Johan Tibell | 8 Nov 06:43 2012
Picon

Status of stack trace work

Hi!


I can't wait until we have some for of stack traces in GHC. What's the current status? Did the semantics you presented at HIW12 work out? Even though the full bells and whistles of full stack traces is something I'd really like to see, even their more impoverished cousins, the lexical stack trace, would be helpful in tracking down just which call to head gave rise to a "head: empty" list error.

Once we do have some sort of stack traces, could we have throw automatically attach it to the exception, so we can get a printed stack trace upon crash? Is that how e.g. Java deals with that? Will that make other uses of exceptions (such as throwing async exceptions to kill threads) get much more expensive if we try to attach stack traces? A frequent user of async exceptions are web servers that start a timeout call per request.

-- Johan

_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Simon Marlow | 8 Nov 12:13 2012
Picon

Re: Status of stack trace work

On 08/11/12 05:43, Johan Tibell wrote:

> I can't wait until we have some for of stack traces in GHC. What's the
> current status? Did the semantics you presented at HIW12 work out? Even
> though the full bells and whistles of full stack traces is something I'd
> really like to see, even their more impoverished cousins, the lexical
> stack trace, would be helpful in tracking down just which call to head
> gave rise to a "head: empty" list error.

The profiler currently uses the stack tracing scheme I described in that 
talk, and you can use it to chase "head []" right now (with +RTS -xc).

You can also use the GHC.Stack.errorWithStackTrace function that I 
demonstrated in the talk; I added it to GHC.Stack after 7.6.1, but the 
code should work with 7.6.1 if you import GHC.Stack:

-- | Like the function 'error', but appends a stack trace to the error
-- message if one is available.
errorWithStackTrace :: String -> a
errorWithStackTrace x = unsafeDupablePerformIO $ do
    stack <- ccsToStrings =<< getCurrentCCS x
    if null stack
       then throwIO (ErrorCall x)
       else throwIO (ErrorCall (x ++ '\n' : renderStack stack))

I realise that compiling with profiling is not always practical, and not 
as immediate as we'd like, and also it doesn't work in GHCi.  What I 
think we should do is

  (a) add stack trace support to GHCi, so we would get stack traces
      for interpreted code

  (b) incorporate the work of Peter Wortmann and Nathan Howell to get
      DWARF information into GHC binaries, and use this to get
      execution stacks without needing to compile for profiling

I'd love to see people working on (b) especially, and I'll be happy to 
provide direction or pointers to anyone who's interested (I'm no DWARF 
expert though).  The stacks you get this way won't be as nice as the 
ones we get from the profiler, and there will be absolutely no 
guarantees about the quality of the information, or even that you'll get 
the same stack with -O as you get without.  But some information is 
better than no information for debugging purposes.

> Once we do have some sort of stack traces, could we have throw
> automatically attach it to the exception, so we can get a printed stack
> trace upon crash? Is that how e.g. Java deals with that? Will that make
> other uses of exceptions (such as throwing async exceptions to kill
> threads) get much more expensive if we try to attach stack traces? A
> frequent user of async exceptions are web servers that start a timeout
> call per request.

One way to do this is to provide a variant of catch that grabs the stack 
trace, e.g.

   catchStack :: Exception e => IO a -> (e -> Stack -> IO a) -> IO a

and this could be implemented cheaply, because the stack only needs to 
be constructed when it is being caught by catchStack.  However, this 
doesn't work well when an exception is rethrown, such as when it passes 
through a nest of brackets.  To make that work, you really have to 
attach the stack trace to the exception.  We could change our 
SomeException type to include a stack trace, and that would be fairly 
cheap to use with profiling (because capturing the current stack is 
free), but it would be more expensive with DWARF stacks so you'd want a 
runtime option to enable it.

Cheers,
	Simon

Gmane