Update docu for ppHeapTree
[ghc-heap-view.git] / src / GHC / HeapView.hs
index 0016fad..7b03017 100644 (file)
@@ -33,7 +33,9 @@ module GHC.HeapView (
     HeapGraphIndex,
     HeapGraph(..),
     lookupHeapGraph,
+    heapGraphRoot,
     buildHeapGraph,
+    ppHeapGraph,
     -- * Boxes
     Box(..),
     asBox,
@@ -72,6 +74,9 @@ import qualified Data.IntMap as M
 import Control.Monad
 import Control.Monad.Trans.State
 import Control.Monad.Trans.Class
+import Control.Monad.IO.Class
+import Control.Monad.Trans.Writer.Strict
+import Control.Arrow    ( first, second )
 
 #include "ghcautoconf.h"
 
@@ -683,9 +688,10 @@ buildHeapTree n b = do
 
 -- | Pretty-Printing a heap Tree
 -- 
--- Example output for @[Just 4, Nothing]@:
+-- Example output for @[Just 4, Nothing, *something*]@, where *something* is an
+-- unevaluated expression depending on the command line argument.
 --
--- > : (Just (I# 4)) (: Nothing [])
+-- >[Just (I# 4),Nothing,Just (_thunk ["arg1","arg2"])]
 ppHeapTree :: HeapTree -> String
 ppHeapTree = go 0
   where
@@ -725,36 +731,53 @@ newtype HeapGraph = HeapGraph (M.IntMap HeapGraphEntry)
 lookupHeapGraph :: HeapGraphIndex -> HeapGraph -> Maybe HeapGraphEntry
 lookupHeapGraph i (HeapGraph m) = M.lookup i m
 
+heapGraphRoot :: HeapGraphIndex
+heapGraphRoot = 0
+
 -- | Creates a 'HeapGraph' for the value in the box, but not recursing further
--- than the given limit.
+-- than the given limit. The initial value has index 'heapGraphRoot'.
 buildHeapGraph :: Int -> Box -> IO HeapGraph
 buildHeapGraph limit initialBox = do
-    let initialState = (M.empty, [], [0..])
-    (\(m,_,_) -> HeapGraph m) <$> execStateT (add limit initialBox) initialState 
+    let initialState = ([], [0..])
+    HeapGraph <$> execWriterT (runStateT (add limit initialBox) initialState)
   where
     add 0 _ = return Nothing
     add n b = do
         -- If the box is in the map, return the index
-        (_,existing,_) <- get
+        (existing,_) <- get
         case lookup b existing of
             Just i -> return $ Just i
             Nothing -> do
                 -- Otherwise, allocate a new index
                 i <- nextI
                 -- And register it
-                modify (\(m,a,is) -> (m,(b,i):a,is))
-                c <- lift $ getBoxedClosureData b
+                modify (first ((b,i):))
+                c <- liftIO $ getBoxedClosureData b
                 -- Find indicies for all boxes contained in the map
                 c' <- T.mapM (add (n-1)) c
-                w <- lift $ weakBox b
+                w <- liftIO $ weakBox b
                 -- Add add the resulting closure to the map
-                modify (\(m,a,is) -> (M.insert i (HeapGraphEntry w c') m,a,is))
+                lift $ tell (M.singleton i (HeapGraphEntry w c'))
                 return $ Just i
     nextI = do
-        (_,_,i:_) <- get
-        modify (\(m,a,is) -> (m,a,tail is))
+        i <- gets (head . snd)
+        modify (second tail)
         return i
 
+-- | Pretty-prints a HeapGraph. The resulting string contains newlines. Example for @repeat "Ho"@:
+--
+-- >let x0 = x1 : x2
+-- >    x1 = C# 'H'
+-- >    x2 = x3 : x0
+-- >    x3 = C# 'o'
+-- >in x0
+ppHeapGraph :: HeapGraph -> String
+ppHeapGraph (HeapGraph m) = "let " ++ intercalate "\n    " (map ppEntry (M.assocs m)) ++ "\nin x0"
+  where
+    ppEntry (i,HeapGraphEntry _ c) = "x" ++ show i ++ " = " ++ ppPrintClosure go 0 c
+    go _ Nothing = "..."
+    go _ (Just i) = "x" ++ show i
+
 -- | An a variant of 'Box' that does not keep the value alive.
 -- 
 -- Like 'Box', its 'Show' instance is highly unsafe.