ghc-heap-view now with recursive pretty-printing

Hi, I get the impression that blogs and planet.haskell.org are the best way to disseminate information about new tools any more. Maybe a part of the earlier importance has been taken over by GooglePlus, but not all, leaving both blogs and GooglePlus less useful individually? Anyways, I’d like to tell you about a feature of ghc-heap-view that I have blogged about¹, namely the possibility to inspect heap values recursively in GHCi or in your programs, including thunks, the references between them and sharing: Prelude> :script /home/jojo/.cabal/share/ghc-heap-view-0.4.0.0/ghci Prelude> let x = [1..10] Prelude> x [1,2,3,4,5,6,7,8,9,10] Prelude> :printHeap x _bh [S# 1,S# 2,S# 3,S# 4,S# 5,S# 6,S# 7,S# 8,S# 9,S# 10] Note that the tools shows us that the list is a list of S# constructors, and also that it is still hidden behind a blackhole. After running System.Mem.performGC, this would disappear. Prelude> let x = Just (1 + 1) Prelude> :printHeap x Just _bco Prelude> x Just 2 Prelude> System.Mem.performGC Prelude> :printHeap x Just (S# 2) Here, we see how the calculation was deferred until forced by showing the value of x. The name _bco stands for a bytecode object as used by the interpreter. Getting useful information from them is a bit harder than for compiled thunks, so for more accurate results put the code in a Haskell source file, compile it and use the GHC.HeapView API to print the interesting parts. Prelude> let a = "hi" Prelude> let partial = (a ++) Prelude> partial "" "hi" Prelude> System.Mem.performGC Prelude> let x = (a, partial) Prelude> :printHeap x let x1 = "hi" in (x1,_fun x1) This demonstrates a partial application. The information which function is called there (++ in this case) is lost at runtime, but we still see that the second element of the tuple is a partial application of some value to the first element. Prelude> let s = "ho" Prelude> let x = cycle s Prelude> length (take 100 (show x)) 100 Prelude> System.Mem.performGC Prelude> :printHeap x let x0 = C# 'h' : C# 'o' : x0 in x0 Prelude> let y = map Data.Char.toUpper x Prelude> length (take 100 (show y)) 100 Prelude> :printHeap y C# 'H' : C# 'O' : C# 'H' : C# 'O' : C# 'H' : C# 'O' : C# 'H' : C# 'O' : C# 'H' : C# 'O' : _bh (C# 'H' : C# 'O' : C# 'H' : C# 'O' : C# 'H' : C# 'O' : C# 'H' : C# 'O' : ... : ...) The cyclic, tying-the-knot structure of cycle is very visible. But can also see how easily it is broken, in this case by mapping a function over the list. Prelude> let {x = 'H' : y ; y = 'o' : x } Prelude> length (show (take 10 x, take 10 y)) `seq` return () Prelude> System.Mem.performGC Prelude> :printHeap (x,y) let x1 = C# 'H' : x3 x3 = C# 'o' : x1 in (x1,x3) If you want to look at multiple variables at once, just pass a tuple to printHeap I hope you’ll find it useful, and I am happy to hear about other features that you might be interested in. Also, if you don’t know about it, a graphical and interactive variant of this is available as ghc-vis². Greetings, Joachim ¹ http://www.joachim-breitner.de/blog/archives/580-GHCi-integration-for-GHC.He... ² http://felsin9.de/nnis/ghc-vis/ -- Joachim "nomeata" Breitner mail@joachim-breitner.de | nomeata@debian.org | GPG: 0x4743206C xmpp: nomeata@joachim-breitner.de | http://www.joachim-breitner.de/

On 21 December 2012 11:16, Joachim Breitner
Prelude> :script /home/jojo/.cabal/share/ghc-heap-view-0.4.0.0/ghci Prelude> let x = [1..10] Prelude> x [1,2,3,4,5,6,7,8,9,10] Prelude> :printHeap x _bh [S# 1,S# 2,S# 3,S# 4,S# 5,S# 6,S# 7,S# 8,S# 9,S# 10]
Note that the tools shows us that the list is a list of S# constructors, and also that it is still hidden behind a blackhole. After running System.Mem.performGC, this would disappear.
Why do you call it a "blackhole"? I assume you mean a thunk that has been evaluated and updated with its value. The commonly used term for this is "indirection". A blackhole is used to detect when a thunk's value depends on itself (e.g., in "let x = id x in ..." the thunk for x may get turned into a black hole). It's a minor thing, but I think it's a good idea to stick to existing terminology. Otherwise, it looks like a useful tool. Eventually, we probably want an interactive graph where we can click a node to evaluate it (or to show/hide children nodes). -- Push the envelope. Watch it bend.

Hi, Am Dienstag, den 25.12.2012, 16:58 +0100 schrieb Thomas Schilling:
On 21 December 2012 11:16, Joachim Breitner
wrote: Prelude> :script /home/jojo/.cabal/share/ghc-heap-view-0.4.0.0/ghci Prelude> let x = [1..10] Prelude> x [1,2,3,4,5,6,7,8,9,10] Prelude> :printHeap x _bh [S# 1,S# 2,S# 3,S# 4,S# 5,S# 6,S# 7,S# 8,S# 9,S# 10]
Note that the tools shows us that the list is a list of S# constructors, and also that it is still hidden behind a blackhole. After running System.Mem.performGC, this would disappear.
Why do you call it a "blackhole"? I assume you mean a thunk that has been evaluated and updated with its value. The commonly used term for this is "indirection". A blackhole is used to detect when a thunk's value depends on itself (e.g., in "let x = id x in ..." the thunk for x may get turned into a black hole).
I don’t call it a blackhole, GHC does :-). At least it is a closure of type BLACKHOLE http://hackage.haskell.org/trac/ghc/browser/includes/rts/storage/ClosureType... I assume this is due to lazy blackholing or something, although it still occurs with "ghci -fno-eager-blackholing"... strange.
It's a minor thing, but I think it's a good idea to stick to existing terminology. Otherwise, it looks like a useful tool.
Thanks!
Eventually, we probably want an interactive graph where we can click a node to evaluate it (or to show/hide children nodes).
Looks like I am not as good at advertising my (or my student’s) projects as much as I thought I am: http://felsin9.de/nnis/ghc-vis/ Greetings, Joachim -- Joachim "nomeata" Breitner mail@joachim-breitner.de | nomeata@debian.org | GPG: 0x4743206C xmpp: nomeata@joachim-breitner.de | http://www.joachim-breitner.de/
participants (2)
-
Joachim Breitner
-
Thomas Schilling