ghci debugger :trace command does not always extend trace history

Simon Marlow marlowsd at gmail.com
Mon Jan 12 05:58:41 EST 2009


I agree with most of what you say - there should be a way to get access to 
the history after :trace has finished.  Perhaps the right way is just to 
have a single global trace history.

Please submit a feature request, with a proposal for the user interface, to 
the GHC bug tracker:

http://hackage.haskell.org/trac/ghc/newticket?type=feature+request

Cheers,
	Simon

Peter Hercek wrote:
> Hi Simon ... and whoever thinks he/she can help me with the right way of 
> debugging with ghci,
> 
> Sorry for the long post but I cannot explain more shortly what I would 
> like to be able to do ... and maybe you find my ":find" and ":monitor" 
> commands at the end useful ... and maybe you can propose some other 
> useful user defined commands for ghci which were not mentioned in Claus' 
> tutorial :-)
> 
> Ok, so it is not a bug because each trace command creates a new context 
> and trace history is context specific. This means my question now is: 
> How can I get access to trace history of a nested trace command which 
> just finished?
> Here are some explanations so that we understand each other:
> The top level trace of my old example is ":trace test 0".
> The nested trace of my old example is ":trace z".
> I would like to get access to the trace history of the nested trace 
> after the nested trace finishes (e.g. after the command ":trace z" 
> finished by printing the z value).
> Or the other option would be: How to launch ":trace z" so that a new 
> nested trace is not created but the current trace (the one before 
> launching ":trace z") is extended?
> 
> I know I can use ":trace" to continue the current trace but this 
> requires that I have some suitable breakpoint later on a place where 
> value z is already forced and before the interesting trace history is 
> not replaced with newer stuff. It may not be trivial to find such a place.
> Other option would be to place breakpoints on all the interesting places 
> which lead to the computation of the result being forced with ":trace 
> <varName>" and investigate the traces in the nested context. The problem 
> here is that it is more work. If I would know the result first then I 
> could focus only on the places which are the probable reason of the 
> wrong value, moreover the lure of ":find" is tempting (I explain ":find" 
> later). Typically the situation is more complicated (there are more 
> options) than my small example.
> 
> My requests/questions may look strange, but here is reasoning why I 
> think I need the functionality. If you have better approach to debugging 
> please let me know. Maybe there is still some interesting tutorial I did 
> not read about ghc debugging or I just forgot something.
> 
> When I debug, I typically know what is probably wrong based on the 
> program output. So I place a breakpoint at one logical step before the 
> output. When stopped at the breakpoint I force variables which do not 
> need to stay lazy and from which the program output is printed. Then I 
> can see if some part of the force result/output is unexpected. Then I 
> would like to search the trace history to see values of variables which 
> probably contributed to the wrong value of the force result/output. I 
> hoped that using :trace instead of force would append the trace history.
> 
> This backward search for a bug means less work since I need to 
> investigate only the path from the dynamic evaluation tree root (the 
> wrong program result) to a given node where the bug is. An ability to 
> access trace history of a value I just forced would save me some program 
> restarts. How much restarts would be saved depends on the trace history 
> depth and my ability not to get lost in the order of lazy calls. If I do 
> not have access to the trace history, the only option is to put a 
> breakpoint at a place where the variable value I wanted to check is 
> available and restart the program so that I can check the value.
> 
> Since there is no way to print partially applied functions this value 
> based approach is probably the only one working. This is supported by 
> recommendations to use printf debugging.
> 
> One more reason I would like to learn how to access the trace history of 
> a forced value is that my :monitor commands conflict with ghci trace 
> history. I was able to implement :monitor and :find commands based on 
> Claus' ghci scripting tutorial:
> 
> :monitor displays value of a given variable at a given location while 
> discarding all the other output. It is a way to do printf debugging 
> solely from ghci without changing source code (i.e. without adding 
> Debug.Trace.trace calls). :monitor (used together with ":x") is not 
> always better than printf debugging  because it discards program output 
> too, and cannot add an identifier to scope. But often it is ... at least 
> for me because it separates printf debugging (defined using ":monitor" 
> commands in a script I source with ":.") from the source code.
> 
> :find finds a variable name in trace history, prints its value, and a 
> location where it was found. The location is needed here because of name 
> conflicts. The value located may not be the right one. Taking static 
> scopes into account could discard a lot of false finds (not all of 
> them). I think that taking static scopes and (maybe more detailed) trace 
> history into account could rule out all false positives. But nobody 
> wants to implement this in a ghci script ... I guess :-)
> 
> Currently my :monitor command makes holes in trace history, lowering the 
> value of :find command :-(
> 
> If you are interested you can find :find and :monitor implementations 
> here: http://www.hck.sk/users/peter/pub/.ghci
> 
> It looks to me that the way tracing is done is unfortunate from the 
> point of view of scripting custom ghci commands. It would be better to 
> have a global trace history which would be activated/deactivated with 
> command like ":trace on/off" and this would modify the behavior of the 
> rest of the ghci commands appropriately. E.g. :continue would behave 
> like :trace (without arguments) when tracing is on. It would be probably 
> interesting to have more tracing buffers (but I did not think about this 
> much). Now, it is done in a cool functional way which means more 
> complicated user defined ghci commands ... unless I'm missing something :-)
> 
> 
> Thanks,
> Peter.
> 
> 
> Simon Marlow wrote:
>> Peter Hercek wrote:
>>> Hi,
>>>
>>> I expected ":trace expr" to always add data to the trace history but 
>>> it does not do so for CAFs (which are not reduced yet).
>>> My point is that the command ":trace z" did not add anything to the 
>>> trace history and I cannot check why value z is 2, because value of y 
>>> is not in the trace history. Is this the expected behavior? If it is, 
>>> how can I make ghci to extend the trace history when "forcing" 
>>> variables?
>>>
>>> Peter.
>>>
>>> Here is the example:
>>>
>>> status:0 peter at metod [765] ~/tmp
>>> % cat a.hs
>>> test :: Int -> Int
>>> test x =
>>>   let y = x+1 in
>>>   let z = y+1 in
>>>   z
>>> status:0 peter at metod [766] ~/tmp
>>> % ghci a.hs
>>> GHCi, version 6.8.2: http://www.haskell.org/ghc/  :? for help
>>> Loading package base ... linking ... done.
>>> [1 of 1] Compiling Main             ( a.hs, interpreted )
>>> Ok, modules loaded: Main.
>>> *Main> :break Main 5
>>> Breakpoint 0 activated at a.hs:5:2
>>> *Main> :trace test 0
>>> Stopped at a.hs:5:2
>>> _result :: Int = _
>>> z :: Int = _
>>> 4    let z = y+1 in
>>> 5    z
>>> 6
>>> [a.hs:5:2] *Main> :back
>>> Logged breakpoint at a.hs:(2,0)-(5,2)
>>> _result :: Int
>>> 1  test :: Int -> Int
>>> 2  test x =
>>> 3    let y = x+1 in
>>> 4    let z = y+1 in
>>> 5    z
>>> 6
>>> [-1: a.hs:(2,0)-(5,2)] *Main> :back
>>> no more logged breakpoints
>>
>> ok so far - y and z have not been evaluated.
>>
>>> [-1: a.hs:(2,0)-(5,2)] *Main> :forward
>>> Stopped at a.hs:5:2
>>> _result :: Int
>>> z :: Int
>>> 4    let z = y+1 in
>>> 5    z
>>> 6
>>> [a.hs:5:2] *Main> :trace z
>>> 2
>>
>> this evaluates z.
>>
>>> [a.hs:5:2] *Main> :back
>>> Logged breakpoint at a.hs:(2,0)-(5,2)
>>> _result :: Int
>>> 1  test :: Int -> Int
>>> 2  test x =
>>> 3    let y = x+1 in
>>> 4    let z = y+1 in
>>> 5    z
>>> 6
>>
>> You are going back in the original context, but I presume you were 
>> expecting to go back in the evaluation of z.  You can only go back in 
>> the context of the current evaluation, however.
>>
>> Try this:
>>
>> *Main> :break 3
>> Breakpoint 4 activated at trace.hs:3:10-12
>> *Main> :trace test 0
>> Stopped at trace.hs:3:10-12
>> _result :: Int = _
>> x :: Int = 90
>> 2  test x =
>> 3    let y = x+1 in
>> 4    let z = y+1 in
>> [trace.hs:3:10-12] *Main> :history
>> -1  : test (trace.hs:4:10-12)
>> -2  : test (trace.hs:5:2)
>> -3  : test (trace.hs:(2,0)-(5,2))
>> <end of history>
>> [trace.hs:3:10-12] *Main> :back
>> Logged breakpoint at trace.hs:4:10-12
>> _result :: Int
>> y :: Int
>> 3    let y = x+1 in
>> 4    let z = y+1 in
>> 5    z
>> [-1: trace.hs:4:10-12] *Main> :back
>> Logged breakpoint at trace.hs:5:2
>> _result :: Int
>> z :: Int
>> 4    let z = y+1 in
>> 5    z
>> 6
>>
>> Cheers,
>>     Simon
> 
> _______________________________________________
> Glasgow-haskell-users mailing list
> Glasgow-haskell-users at haskell.org
> http://www.haskell.org/mailman/listinfo/glasgow-haskell-users



More information about the Glasgow-haskell-users mailing list