Running compiled programs

Program flags

A Haskell program compiled with hbc automatically decodes a number of flags:

If the runtime system was compiled with dumping enabled there are some additional flags:

If the runtime system was compiled with GC statistics enabled there are some additional flags:

The file ``STAT.program'' (when produced) will contain various (selfexplanatory?) statistics.

Heap profiling (Authors: Colin Runciman and David Wakeling)

If the program has been compiled with the heap profiling turned of (the -ph flag to the compiler) it decodes the following flags: Two or more of the -g, -m, -p, and -c flags may be used together. In this case, the first flag specifies what kind of profile is to be produced, and the remainder are used to specify restrictions.

During reduction the graph is periodically sampled and the samples are written to a file whose name is that of the program, extended with a ``.hp'' suffix. This file can be converted to a PostScript file by the hp2ps program.

A notable feature is that there is absolutely no concept of scope. Profiles do not distinguish between nested functions with the same name, or between functions in different modules with the same name. The only way to make such distinctions is to copy and rename function bodies. Some names get lost during compilation, and obscure identifiers appear in their place. This happens most often in programs that make heavy use of higher-order functions; my apologies.

Examples:

Running the program ``a.out -p'' gives a producer profile.

``a.out -p -c{(.)}'' gives a producer profile, in which the only producers of interest are those of ``(.)'' nodes.

``a.out -c -m{lex,parse,typecheck}'' gives a construction profile, but only for constructions produced by the modules ``lex'', ``parse'' and ``typecheck''.

``a.out -c -m{lex,parse,typecheck} -p{tokeniser,syntax,tcheck}'' gives a construction profile, but only for constructions produced by the modules ``lex'', ``parse'' and ``typecheck'', and only for the functions ``tokeniser'', ``syntax'' and ``tcheck'' within these modules.

Tracing

There is no debugger available that can handle programs produced by lmlc/hbc, but if programs are compiled with the ``-T'' flag there is a simple interactive tracer that can be used. The tracer is invoked by giving the ``-T'' flag to a compiled program. Unfortunately the tracer cannot be used together with the interactive system (yet). The tracer has an interactive interface where the user can turn tracing of and off, run till a certain point etc.

The following commands are available:

Identifier may be prefixed by their file (module) name followed by a dot to make them unique. An empty command will repeat the previous command. Any kind of error or call to fail will cause the tracer to be entered. The tracer prints the following messages: Each message is indented with a depth corresponding to the call stack depth. In the case of a tail called the function which is called can be seen from the following ``Enter'' message, provided that function has been compiled with the trace flag on. The enter and exit messages always come in pairs, even if tracing is turned off for a particular function between.

The tracer is not able to determine the type for all constructed values. If it cannot then it uses the name CONn for the n:th constructor of a type.

Traced and non-traced modules can be mixed, but only calls to traced code can be observed. Each module in a program can be compiled for tracing, but then the trace flag can be omitted when linking the program. In this case the program will run with a moderate slowdown (it will take about 25\% longer). If it is linked for tracing, but run without the ``-T'' flag it may run as much as 5 times slower.

A problem with understanding the trace messages is that they refer to the program after the extensive transformations performed by the compiler. An aid to understanding is to look at the program after all transformations; given the ``-ftransformed'' flag the compiler will show this.

Memory allocation

The current strategy for memory allocation is as follows: On startup a heap is allocated, the size of this never changes during execution. The size is the heapsize given as argument, or a default of 8 megabytes.

Only part of this memory is used during exection to lower the working set of the program. How large part is determined after each garbage collection. The amount is used (i.e., available for allocation) is the amount that was copied when the collection occured multiplied by 4. In this way the working set is adapted to the amount of heap that is actually in use.

Tips to get efficient programs

NOTHING MUCH WRITTEN YET (maybe it's impossible?)!!!

Haskell overloading

Overloaded Haskell functions are nice but slow. The compiler tries to remove overloading where the types are known, so type signatures help to improve efficiency. It is a good idea, both from efficiency and also from a programming point of view, to include type signatures for all top level functions in a module. With optimization turned on the compiler tries to make specialized functions for all possible types it is used at. This is currently impossible across module boundaries, so for exported functions the SPECIALIZE pragma should be used.

It is generally not a good idea to worry too much about what the compiler does, but here are a few general tips. Elementary functions, as well as certain idioms, on simple data basic types turn into a few machine instructions. The number of machine instructions cited below does not include those that compute the value, check if it is computed, loads it into a register etc. These instructions usually take much longer than the operation itself, but the table gives an indication of which operations you can expect reasonable efficiency.

There are a few things that should be currently avoided because they are very slow: Most Prelude functions involving numeric types have specialized instances for all the numeric types in the Prelude, e.g. sum can sum lists of any Prelude numeric type efficiently.


Last modified: Mon Jul 22 01:15:26 MET DST 1996