Improve demo
[ghc-heap-view.git] / Demo.hs
1 {-# LANGUAGE MagicHash, BangPatterns #-}
2
3 import GHC.Exts
4 import GHC.HeapView
5 import Control.DeepSeq
6
7 import System.Environment
8 import System.Mem
9
10 l = [1,2,3]
11
12 main = do
13     args <- map length `fmap` getArgs
14     let l2 = 4:l
15     (l ++ l2 ++ args) `deepseq` return ()
16
17     let x = l ++ l2 ++ args
18     performGC
19     putStrLn "ghc-heap-view-demo"
20     putStrLn ""
21     putStrLn "Here are a few different lists."
22     putStrLn $ "The first one, l, found at " ++ show (asBox l) ++ " (where the /2 is the pointer tag information) is a module-level constant, and fully evaluated:"
23     getClosureData l >>= print
24     putStrLn $ "The second one, l2, found at " ++ show (asBox l2) ++ " is locally defined as l2 = 4:l. See how the cons-cell references l!"
25     getClosureData l2 >>= print
26     putStrLn $ "And here is the list args (" ++ show (asBox args) ++ ") that is static, but not known at compiletime, as it depends on the command line arguments:"
27     getClosureData args >>= print
28     putStrLn $ "And now we have, at " ++ show (asBox x) ++ ", the concatenation of them, but unevaluated. The thunk keeps a reference to l2 and args, but not l, as that is at a static address, unless you are running this in GHCi:"
29     getClosureData x >>= print
30
31     putStrLn ""
32     putStrLn "Now to some more closure types:"
33     let !(I# m) = length args + 42
34     let !(I# m') = length args + 23
35     let f = \x n -> take (I# m + I# x) n ++ args
36         t = f m' l2
37     putStrLn $ "The following value f (" ++ show (asBox f) ++ ") is a locally defined function that has args as a free variable, as well as an unboxed integer (42):"
38     getClosureData f >>= print
39     putStrLn "And the following is a thunk that applies f (also references here) to an unboxed value (23) and l2:"
40     getClosureData t >>= print
41
42     putStrLn ""
43     putStrLn "Here is the standard example for self reference:"
44     putStrLn "> let x = id (:) () x"
45     let x = id (:) () x
46     putStrLn $ "This is what x (" ++ show (asBox x) ++ ") looks like, at least without -O:"
47     getClosureData x >>= print
48     x `seq` return ()
49     putStrLn $ "So it is unevaluated. Let us evaluate it using seq. Now we have, still at " ++ show (asBox x) ++ ":"
50     getClosureData x >>= print
51     IndClosure {indirectee = target} <- getClosureData x
52     putStrLn $ "The thunk was replaced by an indirection. If we look at the target, " ++ show target ++ ", we see that it is a newly created cons-cell referencing the original location of x:"
53     getBoxedClosureData target >>= print
54     performGC
55     putStrLn $ "After running the garbage collector (performGC), we find that the address of x is now " ++ show (asBox x) ++ " and that the self-reference is without indirections:"
56     getClosureData x >>= print
57
58
59 recurse :: Int -> Box -> IO ()
60 recurse m = go 0
61   where go i b = if i >= m then return () else do
62             putStrLn $ ind ++ show b
63             c <- getBoxedClosureData b
64             putStrLn $ ind ++ show c
65             mapM_ (go (succ i)) (allPtrs c)
66           where
67             ind = concat $ replicate i "  "