Should exhaustiveness testing be on by default?

Simon Marlow marlowsd at gmail.com
Sun Jun 7 10:32:54 EDT 2009


Claus Reinke wrote:

> Perhaps I've been misunderstanding what you mean by "lexical stack"?
> "lexical" to me implies only scope information, nothing related to run
> time call chains, which would be "dynamic". In the "dynamic" case, one
> can then distinguish between call-by-need stack (what actually happens
> in GHC) and call-by-value stack (pretend that everything is strict).

Ah, ok.  Terminology mismatch.  My "lexical call stack" and your 
"pseudo-cbv" are almost the same thing, I think.

The way a cost-centre stack is built is described in the docs:

http://www.haskell.org/ghc/docs/latest/html/users_guide/profiling.html#prof-rules

> What the cost-centre stack delivers appears to be more than scopes,
> and less than a full static call graph (which would have to include non
> deterministic branches, since the actual choice of branches depends on
> runtime information) - it seems to use runtime information to give a 
> slice of the full call graph (eg, not all call sites that could call the 
> current function, but only the one that did so in the current run)?

I'm not sure what you mean here.  e.g. "non-deterministic branches"? 
Obviously the shape of the call stack depends upon values at runtime.

>>> Here are the +RTS -xc and mapException outputs together (..
>>> - they seem to complement each other (-xc has no locations, but names 
>>> for the lexical stack; mapError has no names, but locations for the 
>>> dynamic stack; we're still missing the parameters for either stack):
>>
>> I'm not claiming that +RTS -xc in its present form is what you want. 
>> I'm interested in finding an underlying mechanism that allows the 
>> right information to be obtained; things like source locations and 
>> free variables are just decoration.
> 
> And I'm saying that adding mapException annotations is a way to get
> there, with very little extra effort (just the get-the-source-location part
> of the finding-the-needle transformation would be sufficient).

mapException exposes information about the call-by-need stack, which is 
not what you want (I claim).

>> Now, most of the existing methods have problems with CAFs.  I doubt 
>> that the problems with CAFs are fixable using the source-to-source 
>> transformation methods, but I think they might be fixable using 
>> cost-centre stacks.
> 
> One of the nice things about my suggestion to mix an "annotate
> with mapException" transformation with cost-centre stacks is that
> it would cover CAFs as well. As another example, I tried the
> nofib-buggy:anna test case discussed at
> http://hackage.haskell.org/trac/ghc/wiki/ExplicitCallStack/StackTraceExperience 
> 
> 
> which does have just such a CAF problem (the error is caused in a local 
> CAF, and raised in a standard library CAF), amongst other nasty
> features (no CPP/sed only transformation will handle infix applications,
> the initial error message doesn't even tell us where to start annotating).

The CAF problem I'm referring to is a bit different - the goal is to get 
a good stack trace without affecting performance by more than a constant 
factor.  i.e. CAFs have to be evaluated no more than once, even when 
doing stack tracing.  This turns out to be quite hard, especially when 
using a source-to-source transformation.

The CCS implementation currently errs on the side of not giving you much 
information, but without re-evaluating CAFs.  Hence you get a 
not-very-helpful call stack.  However, it wouldn't be difficult to 
report the call stack from the site that first evaluated the CAF.

> - the initial error is "<GHC.Err.CAF>Main: divide by zero"
> - this doesn't tell us where the issue is, so we have to annotate    all 
> calls to 'div', which we do by wrapping in 'mapException',

So yes, you can use mapException to get the dynamic call stack.  I'm not 
keen on this approach though, because I think the dynamic call stack is 
not what you want.

Also, mapExceptionn is not helpful for doing profiling or displaying the 
call stack at a breakpoint, and I think a general call-stack mechanism 
should enable both of those.

Cheers,
	Simon



More information about the Glasgow-haskell-users mailing list