grades & options for tracing and debugging

Fergus Henderson fjh at cs.mu.OZ.AU
Fri Mar 13 19:11:24 AEDT 1998


Hi all,

I just spent some time with Zoltan discussing which grades and options
we should have for tracing and debugging.  We came up with the
following design to extend/replace the current `--generate-trace' option.

There would be a new debugging grade, enabled with `-g'/`--debug'
(we can scrap the old debugging grade now, I think),
and three mutually exclusive options `--trace-all',
`--trace-interface', and `--no-trace'.

`--trace-all' would be like the old `--generate-trace'.
`--no-trace' would be like the old `--no-generate-trace'.
`--trace-interface' would cause the compiler to generate code
which lets you trace only calls to this module from code
in a different module that was compiled with `--trace-all'.
Calls to this module from itself or from other modules
compiled with `--trace-interface' would not be not traced.
`--grade debug' would imply `--trace-all', unless you
explicitly specify `--trace-interface'.
Specifying both `--grade debug' and `--no-trace' would be an error.
`--trace-all' and `--trace-interface' would both imply the use of
stack layouts.

So, to summarize, the user specifies the grade and possibly some extra
options, and the compiler selects whether to do full, partial or no tracing,
and whether to include stack layouts, as specified below.

GRADE				EXTRA OPTIONS		TRACING	 STACK LAYOUTS

default	(e.g. asm_fast.gc)	none			none	 no
default	(e.g. asm_fast.gc)	--trace-none		none	 yes
default	(e.g. asm_fast.gc)	--trace-interface	partial	 yes
default	(e.g. asm_fast.gc)	--trace-all		full	 yes

--debug				none			full	 yes
--debug				--trace-none		<not allowed>
--debug				--trace-interface	partial	 yes
--debug				--trace-all		full	 yes

Note that code compiled in grade `--debug' is in theory binary compatible
with code not compiled with `--debug', but it is made a separate grade
so that by using that grade you can ensure that stack dumps will always work
and that you can at least debug the interface of everything you call.
To minimize the proliferation of different grades, we should
probably make `--debug' imply `--use-trail'.  The minor extra cost
of having a trail should not be that important when debugging.

We would have two or three global variables, namely `MR_trace_enabled',
`MR_tracing', and (perhaps) `MR_trace_method'.  `MR_trace_enabled'
would be a boolean which specified whether or not to do any tracing at
all.  It would default to true in grade debug and false otherwise, but
this could be overridden by setting a flag in the MERCURY_OPTIONS
environment variable.  `MR_trace_method' would say which tracing method
to use, either the internal Mercury runtime tracer, or the socket-based
external process tracer.   The default would be to use the internal
tracer, unless (a) the runtime was compiled with `-DMR_USE_DEBUGGER',
*and* (b) one of the environment variables MERCURY_DEBUGGER_UNIX_SOCKET
or MERCURY_DEBUGGER_INTERNET_SOCKET was set (these options specify the
path name or the host IP address and port number to use for the socket).
Alternatively we could combine MR_trace_enabled and MR_trace_method
into a single variable; this might be simpler.
`MR_tracing' would be a boolean which specifies whether we're currently
in code compiled with `--trace-all'.  Initially it would be false.

The code generated for say foo/1 with `--trace-all' should look like this:

	foo_1_0:
		MR_tracing = TRUE;
		if (MR_trace_enabled) {
			MR_trace(MR_PORT_CALL, ...)
		}
		...
		if (MR_trace_enabled) {
			MR_trace(some intermediate port, ...)
		}
		...
		if (MR_trace_enabled) {
			MR_trace(MR_PORT_EXIT, ...)
		}
		proceed();

To implement `--trace-interface', then for exported predicates
we would generate the following code:

	bar_1_0:
		if (MR_trace_enabled && MR_tracing) {
			stackvar(N) = MR_tracing;
			MR_trace(MR_PORT_CALL, ...)
			MR_tracing = FALSE;
		}
		...
		... no intermediate calls to MR_trace()
		...
		if (MR_trace_enabled && stackvar(N)) {
			MR_tracing = TRUE;
			MR_trace(MR_PORT_EXIT, ...)
		}
		proceed();

For predicates which are not exported we don't need to generate
any tracing code.

`--trace-interface' requires stack layouts, but for
predicates which are not exported we could generate
abbreviated stack layouts -- we don't need to
know which variables are live, just the size of the
stack, and the location of the succip (this will
always be stackvar(1), I think).  Even exported predicates
might not require as much information in their stack
layouts as with `--trace-all'.

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3        |     -- the last words of T. S. Garp.



More information about the developers mailing list