packages feed

vacuum 0.0.94 → 0.0.95

raw patch · 8 files changed

+581/−329 lines, 8 filesdep −haskell-src-metaPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: haskell-src-meta

API changes (from Hackage documentation)

- GHC.Vacuum: instance (Eq e, Eq v) => Eq (G e v)
- GHC.Vacuum: instance (Ord e, Ord v) => Ord (G e v)
- GHC.Vacuum: instance (Read e, Read v) => Read (G e v)
- GHC.Vacuum: instance (Show e, Show v) => Show (G e v)
- GHC.Vacuum: instance Eq HNode
- GHC.Vacuum: instance Eq InfoTab
- GHC.Vacuum: instance Ord HNode
- GHC.Vacuum: instance Ord InfoTab
- GHC.Vacuum: instance Read HNode
- GHC.Vacuum: instance Read InfoTab
- GHC.Vacuum: instance Show Closure
- GHC.Vacuum: instance Show HNode
- GHC.Vacuum: instance Show HValue
- GHC.Vacuum: instance Show InfoTab
- GHC.Vacuum: ppHs :: (Show a) => a -> Doc
- GHC.Vacuum.Dot: gStyle :: String
- GHC.Vacuum.Dot: graphToDot :: (a -> String) -> [(a, [a])] -> Doc
- GHC.Vacuum.Dot: ppEdge :: (String, [String]) -> Doc
- GHC.Vacuum.Dot: ppGraph :: [(String, [String])] -> Doc
+ GHC.Vacuum: summary :: HNode -> ([String], [HNodeId], [Word])
+ GHC.Vacuum: toAdjPair :: (HNodeId, HNode) -> (Int, [Int])
+ GHC.Vacuum: vacuumDebug :: a -> IntMap [(StableName HValue, HNodeId)]
+ GHC.Vacuum: vacuumStream :: a -> [(HNodeId, HNode)]
+ GHC.Vacuum.Pretty: Draw :: (Int -> a -> m v) -> (v -> v -> m e) -> (a -> [Int]) -> Draw e v m a
+ GHC.Vacuum.Pretty: G :: IntMap (v, IntMap e) -> G e v
+ GHC.Vacuum.Pretty: ShowHNode :: (Int -> HNode -> String) -> (Int -> String) -> ShowHNode
+ GHC.Vacuum.Pretty: data Draw e v m a
+ GHC.Vacuum.Pretty: data ShowHNode
+ GHC.Vacuum.Pretty: draw :: (Monad m) => Draw e v m a -> IntMap a -> m (G e v)
+ GHC.Vacuum.Pretty: externHNode :: ShowHNode -> Int -> String
+ GHC.Vacuum.Pretty: instance (Eq e, Eq v) => Eq (G e v)
+ GHC.Vacuum.Pretty: instance (Ord e, Ord v) => Ord (G e v)
+ GHC.Vacuum.Pretty: instance (Read e, Read v) => Read (G e v)
+ GHC.Vacuum.Pretty: instance (Show e, Show v) => Show (G e v)
+ GHC.Vacuum.Pretty: mkE :: Draw e v m a -> v -> v -> m e
+ GHC.Vacuum.Pretty: mkV :: Draw e v m a -> Int -> a -> m v
+ GHC.Vacuum.Pretty: nameGraph :: IntMap HNode -> [(String, [String])]
+ GHC.Vacuum.Pretty: newtype G e v
+ GHC.Vacuum.Pretty: ppDot :: [(String, [String])] -> Doc
+ GHC.Vacuum.Pretty: printDraw :: Draw (Int, Int) Int IO HNode
+ GHC.Vacuum.Pretty: renderDot :: [(String, [String])] -> String
+ GHC.Vacuum.Pretty: showHNode :: ShowHNode -> Int -> HNode -> String
+ GHC.Vacuum.Pretty: showHNodes :: ShowHNode -> IntMap HNode -> [(String, [String])]
+ GHC.Vacuum.Pretty: split :: (a -> [Int]) -> IntMap a -> IntMap ([Int], [Int])
+ GHC.Vacuum.Pretty: succs :: Draw e v m a -> a -> [Int]
+ GHC.Vacuum.Pretty: toAdjList :: IntMap HNode -> [(Int, [Int])]
+ GHC.Vacuum.Pretty: toAdjPair :: (HNodeId, HNode) -> (Int, [Int])
+ GHC.Vacuum.Pretty: unG :: G e v -> IntMap (v, IntMap e)
+ GHC.Vacuum.Pretty.Dot: gStyle :: String
+ GHC.Vacuum.Pretty.Dot: graphToDot :: (a -> String) -> [(a, [a])] -> Doc
+ GHC.Vacuum.Pretty.Dot: ppEdge :: (String, [String]) -> Doc
+ GHC.Vacuum.Pretty.Dot: ppGraph :: [(String, [String])] -> Doc
+ GHC.Vacuum.Q: (!) :: Ref a -> IO a
+ GHC.Vacuum.Q: (!=) :: Ref a -> (a -> (a, b)) -> IO b
+ GHC.Vacuum.Q: (.=) :: Ref a -> a -> IO ()
+ GHC.Vacuum.Q: data Q a
+ GHC.Vacuum.Q: data Ref a
+ GHC.Vacuum.Q: drainQ :: Q a -> IO [a]
+ GHC.Vacuum.Q: getQContents :: Q a -> IO [a]
+ GHC.Vacuum.Q: isEmptyQ :: Q a -> IO Bool
+ GHC.Vacuum.Q: newQ :: IO (Q a)
+ GHC.Vacuum.Q: putQ :: Q a -> a -> IO ()
+ GHC.Vacuum.Q: ref :: a -> IO (Ref a)
+ GHC.Vacuum.Q: takeQ :: Q a -> IO a
+ GHC.Vacuum.Q: takeWhileQ :: (a -> Bool) -> Q a -> IO [a]
+ GHC.Vacuum.Q: tryTakeQ :: Q a -> IO (Maybe a)
+ GHC.Vacuum.Types: Closure :: [HValue] -> [Word] -> InfoTab -> Closure
+ GHC.Vacuum.Types: ConInfo :: String -> String -> String -> Word -> Word -> ClosureType -> Word -> [Word] -> InfoTab
+ GHC.Vacuum.Types: Env :: HNodeId -> IntMap [(StableName HValue, HNodeId)] -> IntMap HValue -> IntMap HNode -> Env
+ GHC.Vacuum.Types: HNode :: [HNodeId] -> [Word] -> InfoTab -> HNode
+ GHC.Vacuum.Types: OtherInfo :: Word -> Word -> ClosureType -> Word -> [Word] -> InfoTab
+ GHC.Vacuum.Types: closITab :: Closure -> InfoTab
+ GHC.Vacuum.Types: closLits :: Closure -> [Word]
+ GHC.Vacuum.Types: closPtrs :: Closure -> [HValue]
+ GHC.Vacuum.Types: data Closure
+ GHC.Vacuum.Types: data Env
+ GHC.Vacuum.Types: data HNode
+ GHC.Vacuum.Types: data InfoTab
+ GHC.Vacuum.Types: emptyEnv :: Env
+ GHC.Vacuum.Types: emptyHNode :: ClosureType -> HNode
+ GHC.Vacuum.Types: graph :: Env -> IntMap HNode
+ GHC.Vacuum.Types: hvals :: Env -> IntMap HValue
+ GHC.Vacuum.Types: instance Eq HNode
+ GHC.Vacuum.Types: instance Eq InfoTab
+ GHC.Vacuum.Types: instance Ord HNode
+ GHC.Vacuum.Types: instance Ord InfoTab
+ GHC.Vacuum.Types: instance Read HNode
+ GHC.Vacuum.Types: instance Read InfoTab
+ GHC.Vacuum.Types: instance Show Closure
+ GHC.Vacuum.Types: instance Show HNode
+ GHC.Vacuum.Types: instance Show HValue
+ GHC.Vacuum.Types: instance Show InfoTab
+ GHC.Vacuum.Types: itabCode :: InfoTab -> [Word]
+ GHC.Vacuum.Types: itabCon :: InfoTab -> String
+ GHC.Vacuum.Types: itabLits :: InfoTab -> Word
+ GHC.Vacuum.Types: itabMod :: InfoTab -> String
+ GHC.Vacuum.Types: itabName :: InfoTab -> (String, String, String)
+ GHC.Vacuum.Types: itabPkg :: InfoTab -> String
+ GHC.Vacuum.Types: itabPtrs :: InfoTab -> Word
+ GHC.Vacuum.Types: itabSrtLen :: InfoTab -> Word
+ GHC.Vacuum.Types: itabType :: InfoTab -> ClosureType
+ GHC.Vacuum.Types: nodeInfo :: HNode -> InfoTab
+ GHC.Vacuum.Types: nodeLits :: HNode -> [Word]
+ GHC.Vacuum.Types: nodeMod :: HNode -> String
+ GHC.Vacuum.Types: nodeName :: HNode -> String
+ GHC.Vacuum.Types: nodePkg :: HNode -> String
+ GHC.Vacuum.Types: nodePtrs :: HNode -> [HNodeId]
+ GHC.Vacuum.Types: seen :: Env -> IntMap [(StableName HValue, HNodeId)]
+ GHC.Vacuum.Types: summary :: HNode -> ([String], [HNodeId], [Word])
+ GHC.Vacuum.Types: type HNodeId = Int
+ GHC.Vacuum.Types: uniq :: Env -> HNodeId
+ GHC.Vacuum.Util: dumpArray :: Array Int a -> [a]
+ GHC.Vacuum.Util: hash :: String -> Int

Files

src/GHC/Vacuum.hs view
@@ -33,17 +33,20 @@ > } -} + module GHC.Vacuum (    HNodeId   ,HNode(..)   ,emptyHNode-  ,vacuum,vacuumTo,vacuumLazy+  ,summary+  ,vacuum,vacuumTo,vacuumLazy,vacuumStream,vacuumDebug   ,dump,dumpTo,dumpLazy-  ,toAdjList+  ,toAdjList,toAdjPair   ,nameGraph   ,ShowHNode(..)   ,showHNodes-  ,ppHs,ppDot+  --,ppHs+  ,ppDot   ,Draw(..),G(..)   ,draw,printDraw,split   ,Closure(..)@@ -56,39 +59,54 @@   ,nodePkg,nodeMod   ,nodeName,itabName   ,HValue+  --,module GHC.Vacuum.Q ) where -import Prelude hiding(catch)-import GHC.Vacuum.Dot as Dot++import GHC.Vacuum.Q+import GHC.Vacuum.Util+import GHC.Vacuum.Types+import GHC.Vacuum.Pretty import GHC.Vacuum.ClosureType import GHC.Vacuum.Internal as GHC++import Data.List import Data.Char import Data.Word-import Data.List+import Data.Bits import Data.Map(Map) import Data.IntMap(IntMap) import qualified Data.IntMap as IM import qualified Data.Map as M import Data.Monoid(Monoid(..))-import Data.Array.IArray+import Data.Array.IArray hiding ((!))+import qualified Data.Array.IArray as A import System.IO.Unsafe import Control.Monad-import Data.Bits-import Text.PrettyPrint(Doc,text)-import Language.Haskell.Meta.Utils(pretty) import Control.Applicative import Control.Exception+import Prelude hiding(catch)+import Control.Concurrent  import Foreign import GHC.Arr(Array(..)) import GHC.Exts +import System.Mem.StableName+ -----------------------------------------------------------------------------  -- | Suck up @a@. vacuum :: a -> IntMap HNode vacuum a = unsafePerformIO (dump a) +-- | Returns nodes as it encounters them.+vacuumStream :: a -> [(HNodeId, HNode)]+vacuumStream a = unsafePerformIO (dumpStream a)++vacuumDebug :: a -> IntMap [(StableName HValue, HNodeId)]+vacuumDebug a = unsafePerformIO (dumpDebug a)+ -- | Stop after a given depth. vacuumTo :: Int -> a -> IntMap HNode vacuumTo n a = unsafePerformIO (dumpTo n a)@@ -104,6 +122,12 @@ dump :: a -> IO (IntMap HNode) dump a = execH (dumpH a) +dumpStream :: a -> IO [(HNodeId, HNode)]+dumpStream a = streamH (dumpStreamH a)++dumpDebug :: a -> IO (IntMap [(StableName HValue, HNodeId)])+dumpDebug a = debugH (dumpH a)+ dumpTo :: Int -> a -> IO (IntMap HNode) dumpTo n a = execH (dumpToH n a) @@ -112,135 +136,6 @@  ----------------------------------------------------------------------------- -toAdjList :: IntMap HNode -> [(Int, [Int])]-toAdjList = fmap (mapsnd nodePtrs) . IM.toList--nameGraph :: IntMap HNode -> [(String, [String])]-nameGraph m = let g = toAdjList m-                  pp i = maybe "..."-                          (\n -> nodeName n ++ "|" ++ show i)-                          (IM.lookup i m)-              in fmap (\(x,xs) -> (pp x, fmap pp xs)) g--data ShowHNode = ShowHNode-  {showHNode   :: Int -> HNode -> String-  ,externHNode :: Int -> String}--showHNodes :: ShowHNode -> IntMap HNode -> [(String, [String])]-showHNodes (ShowHNode showN externN) m-  = let g = toAdjList m-        pp i = maybe (externN i) (showN i) (IM.lookup i m)-    in fmap (\(x,xs) -> (pp x, fmap pp xs)) g---------------------------------------------------------------------------------ppHs :: (Show a) => a -> Doc-ppHs = text . pretty--ppDot :: [(String, [String])] -> Doc-ppDot = Dot.graphToDot id---------------------------------------------------------------------------------type HNodeId = Int--data HNode = HNode-  {nodePtrs  :: [HNodeId]-  ,nodeLits  :: [Word]-  ,nodeInfo  :: InfoTab}-  deriving(Eq,Ord,Read,Show)--data InfoTab-  = ConInfo   {itabPkg    :: String-              ,itabMod    :: String-              ,itabCon    :: String-              ,itabPtrs   ::  Word-              ,itabLits   ::  Word-              ,itabType   ::  ClosureType-              ,itabSrtLen ::  Word-              ,itabCode   :: [Word]}-  | OtherInfo {itabPtrs   ::  Word-              ,itabLits   ::  Word-              ,itabType   ::  ClosureType-              ,itabSrtLen ::  Word-              ,itabCode   :: [Word]}-  deriving(Eq,Ord,Read,Show)--data Closure = Closure-  {closPtrs :: [HValue]-  ,closLits :: [Word]-  ,closITab :: InfoTab}-  deriving(Show)---- So we can derive Show for Closure-instance Show HValue where show _ = "(HValue)"------------------------------------------------------ | To assist in \"rendering\"---  the graph to some source.-data Draw e v m a = Draw-  {mkV   :: Int -> a -> m v-  ,mkE   :: v -> v -> m e-  ,succs :: a -> [Int]}--newtype G e v = G {unG :: IntMap (v, IntMap e)}-  deriving(Eq,Ord,Read,Show)--draw :: (Monad m) => Draw e v m a -> IntMap a -> m (G e v)-draw (Draw mkV mkE succs) g = do-  vs <- IM.fromList `liftM` forM (IM.toList g)-          (\(i,a) -> do v <- mkV i a-                        return (i,(v,succs a)))-  (G . IM.fromList) `liftM` forM (IM.toList vs)-    (\(i,(v,ps)) -> do let us = fmap (vs IM.!) ps-                       es <- IM.fromList `liftM` forM ps-                               (\p -> do e <- mkE v (fst (vs IM.! p))-                                         return (p,e))-                       return (i,(v,es)))---- | An example @Draw@-printDraw :: Draw (Int,Int) Int IO HNode-printDraw = Draw-  {mkV   = \i _ -> print i >> return i-  ,mkE   = \u v -> print (u,v) >> return (u,v)-  ,succs = nodePtrs}---- | Build a map to @(preds,succs)@-split :: (a -> [Int]) -> IntMap a -> IntMap ([Int],[Int])-split f = flip IM.foldWithKey mempty (\i a m ->-            let ps = f a-            in foldl' (\m p -> IM.insertWith mappend p ([i],[]) m)-                      (IM.insertWith mappend i ([],ps) m)-                      ps)----------------------------------------------------emptyHNode :: ClosureType -> HNode-emptyHNode ct = HNode-  {nodePtrs   = []-  ,nodeLits   = []-  ,nodeInfo   = if isCon ct-                  then ConInfo [] [] [] 0 0 ct 0 []-                  else OtherInfo 0 0 ct 0 []}--nodePkg   :: HNode -> String-nodeMod   :: HNode -> String-nodeName  :: HNode -> String-nodePkg   = fst3 . itabName . nodeInfo-nodeMod   = snd3 . itabName . nodeInfo-nodeName  = trd3 . itabName . nodeInfo--fst3 (x,_,_) = x-snd3 (_,x,_) = x-trd3 (_,_,x) = x--itabName :: InfoTab -> (String, String, String)-itabName i@(ConInfo{}) = (itabPkg i, itabMod i, itabCon i)-itabName  _            = ([], [], [])--------------------------------------------------- getInfoPtr :: a -> Ptr StgInfoTable getInfoPtr a = let b = a `seq` Box a                 in b `seq` case unpackClosure# a of@@ -268,11 +163,6 @@         ,nptrs #) -> do           let iptr' | ghciTablesNextToCode = Ptr iptr                     | otherwise = Ptr iptr `plusPtr` negate wORD_SIZE-                        -- the info pointer we get back from unpackClosure#-                        -- is to the beginning of the standard info table,-                        -- but the Storable instance for info tables takes-                        -- into account the extra entry pointer when-                        -- !ghciTablesNextToCode, so we must adjust here.           itab <- peekInfoTab iptr'           let elems = fromIntegral (itabPtrs itab)               ptrs0 = if elems < 1@@ -294,14 +184,8 @@       ,_ #) -> do         let iptr' | ghciTablesNextToCode = Ptr iptr                   | otherwise = Ptr iptr `plusPtr` negate wORD_SIZE-                      -- the info pointer we get back from unpackClosure#-                      -- is to the beginning of the standard info table,-                      -- but the Storable instance for info tables takes-                      -- into account the extra entry pointer when-                      -- !ghciTablesNextToCode, so we must adjust here.         peekInfoTab iptr' - peekInfoTab :: Ptr StgInfoTable -> IO InfoTab peekInfoTab p = do   stg <- peek p@@ -351,19 +235,27 @@   (a, s) <- runS m emptyEnv   return (a, graph s) -data Env = Env-  {uniq  :: HNodeId-  ,seen  :: [(HValue, HNodeId)]-  ,hvals :: IntMap HValue-  ,graph :: IntMap HNode}+runH_ :: H a -> IO ()+runH_ m = do+  _ <- runS m emptyEnv+  return () -emptyEnv :: Env-emptyEnv = Env-  {uniq = 0-  ,seen = []-  ,hvals = mempty-  ,graph = mempty}+debugH :: H a -> IO (IntMap [(StableName HValue,HNodeId)])+debugH m = (seen . snd) <$> runS m emptyEnv +streamH :: (Q (Maybe a) -> H b) -> IO [a]+streamH m = do+  q <- newQ+  tid <- forkIO (runH_ (m q) `finally` putQ q Nothing)+  fmap fromJust <$> takeWhileQ isJust q++fromJust :: Maybe a -> a+fromJust (Just a) = a++isJust :: Maybe a -> Bool+isJust (Just{}) = True+isJust  _       = False+ ------------------------------------------------  -- | Walk the reachable heap (sub)graph rooted at @a@,@@ -388,6 +280,16 @@             [] -> return ()             _  -> mapM_ (go (n-1)) =<< mapM getHVal ids +dumpStreamH :: a -> Q (Maybe (HNodeId,HNode)) -> H ()+dumpStreamH a q = do+  go =<< rootH a+  where go :: HValue -> H ()+        go a = do+          ids <- nodeStreamH q a+          case ids of+            [] -> return ()+            _  -> mapM_ go =<< mapM getHVal ids+ dumpLazyH :: a -> H () dumpLazyH !a = go =<< rootH a   where go :: HValue -> H ()@@ -416,9 +318,10 @@ --  return the @HNodeId@'s of these newly-seen nodes --  (which we've added to the graph in @H@'s state). --  CURRENTLY GHC COERCES UNPOINTED CLOSURES TO---  @HVALUE@, which is a bug in the sense that---  unpointed closures cannot be entered, which HValues---  can.+--  @HVALUE@, which means that if we enter (==force/eval)+--  such a closure we'll crash. Also, there's no way+--  to know if the closure we're about to enter is+--  such a closure. nodeH :: HValue -> H [HNodeId] nodeH a = do   clos <- io (getClosure $! a)@@ -437,6 +340,25 @@   insertG i n   return news +nodeStreamH :: Q (Maybe (HNodeId, HNode)) -> HValue -> H [HNodeId]+nodeStreamH q a = do+  clos <- io (getClosure $! a)+  (i, _) <- getId a+  let itab = closITab clos+      ptrs = closPtrs clos+  ptrs' <- case itabType itab of+              t | isCon t -> return (avoid (itabCon itab) ptrs)+                | otherwise -> return ptrs+  ptrs'' <- io (mapM defined ptrs')+  xs <- mapM getId ptrs''+  let news = (fmap fst . fst . partition snd) xs+      n    = HNode (fmap fst xs)+                    (closLits clos)+                    (closITab clos)+  --insertG i n+  io (putQ q (Just (i,n)))+  return news+ nodeLazyH :: HValue -> H [HNodeId] nodeLazyH a = do   clos <- io (getClosure a)@@ -445,8 +367,8 @@       ptrs = closPtrs clos   ptrs' <- case itabType itab of               t | isCon t -> return (avoid (itabCon itab) ptrs)-                  -- IMPORTANT: Following either (or both) of-                  -- the pointer inside a @THUNK@ results in a segfault.+                  -- IMPORTANT: Following any of the pointer(s)+                  -- inside a @THUNK@ results in the chop (aka segfault).                 | isThunk t -> return []                 | otherwise -> return ptrs   xs <- mapM getIdLazy ptrs'@@ -481,37 +403,6 @@   --,("",                 id)   ] -hash :: String -> Int-hash [] = 0-hash  s = go 0 (fmap ord s)-  where go !h [] = h-        go !h (n:ns) =-          let a = (h `shiftL` 4)-              b = a + n-              c = b .&. 0xf0000000-              !d = case c==0 of-                    False -> let !e = c `shiftR` 24-                              in b `xor` e-                    True  -> b-              !e = complement c-              !f = d `xor` e-          in go f ns--{--unsigned long-elfhash(const char *s)-{-  unsigned long h=0, g;-  while (*s){-    h = (h << 4) + *s++;-    if((g = h & 0xf0000000))-      h ^= g >> 24;-    h &= ~g;-  }-  return h;-}--}- ------------------------------------------------  getHVal :: HNodeId -> H HValue@@ -530,84 +421,31 @@  getId :: HValue -> H (HNodeId, Bool) getId hval = hval `seq` do+  sn <- io (makeStableName hval)+  let h = hashStableName sn   s <- gets seen-  case look hval s of+  case lookup sn =<< IM.lookup h s of     Just i -> return (i, False)     Nothing -> do       i <- newId       vs <- gets hvals-      modify (\e->e{seen=(hval,i):s+      modify (\e->e{seen= IM.insertWith (++) h [(sn,i)] s                    ,hvals= IM.insert i hval vs})       return (i, True)  getIdLazy :: HValue -> H (HNodeId, Bool) getIdLazy hval = do+  sn <- io (makeStableName hval)+  let h = hashStableName sn   s <- gets seen-  case lookLazy hval s of+  case lookup sn =<< IM.lookup h s of     Just i -> return (i, False)     Nothing -> do       i <- newId       vs <- gets hvals-      modify (\e->e{seen=(hval,i):s+      modify (\e->e{seen= IM.insertWith (++) h [(sn,i)] s                    ,hvals= IM.insert i hval vs})       return (i, True)----------------------------------------------------look :: HValue -> [(HValue, a)] -> Maybe a-look _      [] = Nothing-look hval ((x,i):xs)-  | hval .==. x = Just i-  | otherwise   = look hval xs--(.==.) :: HValue -> HValue -> Bool-a .==. b = a `seq` b `seq`-  (0 /= I# (reallyUnsafePtrEquality# a b))--lookLazy :: HValue -> [(HValue, a)] -> Maybe a-lookLazy _      [] = Nothing-lookLazy hval ((x,i):xs)-  | hval =.= x = Just i-  | otherwise   = lookLazy hval xs--(=.=) :: HValue -> HValue -> Bool-a =.= b = (0 /= I# (reallyUnsafePtrEquality# a b))--dumpArray :: Array Int a -> [a]-dumpArray a = let (m,n) = bounds a-              in fmap (a!) [m..n]--mapfst f = \(a,b) -> (f a,b)-mapsnd f = \(a,b) -> (a,f b)-f *** g = \(a, b) -> (f a, g b)--p2i :: Ptr a -> Int-i2p :: Int -> Ptr a-p2i (Ptr a#) = I# (addr2Int# a#)-i2p (I# n#) = Ptr (int2Addr# n#)----------------------------------------------------{--newtype S s a = S {unS :: forall o. s -> (s -> a -> IO o) -> IO o}-instance Functor (S s) where-  fmap f (S g) = S (\s k -> g s (\s a -> k s (f a)))-instance Monad (S s) where-  return a = S (\s k -> k s a)-  S g >>= f = S (\s k -> g s (\s a -> unS (f a) s k))-get :: S s s-get = S (\s k -> k s s)-gets :: (s -> a) -> S s a-gets f = S (\s k -> k s (f s))-set :: s -> S s ()-set s = S (\_ k -> k s ())-io :: IO a -> S s a-io m = S (\s k -> k s =<< m)-modify :: (s -> s) -> S s ()-modify f = S (\s k -> k (f s) ())-runS :: S s a -> s -> IO (a, s)-runS (S g) s = g s (\s a -> return (a, s))--}  ------------------------------------------------ 
− src/GHC/Vacuum/Dot.hs
@@ -1,66 +0,0 @@--module GHC.Vacuum.Dot (-   graphToDot-  ,ppGraph,ppEdge,gStyle---   ,Doc,text,render-) where--import Text.PrettyPrint------------------------------------------------------ | .-graphToDot :: (a -> String) -> [(a, [a])] -> Doc-graphToDot f = ppGraph . fmap (f *** fmap f)-  where f *** g = \(a, b)->(f a, g b)----------------------------------------------------gStyle :: String-gStyle = unlines-  ["  graph [rankdir=LR, splines=true];"-  ,"  node [label=\"\\N\", shape=none, fontcolor=blue, fontname=courier];"-  ,"  edge [color=black, style=dotted, fontname=courier, arrowname=onormal];"]--ppGraph :: [(String, [String])] -> Doc-ppGraph xs = (text "digraph g" <+> text "{")-              $+$ text gStyle-                $+$ nest indent (vcat . fmap ppEdge $ xs)-                    $+$ text "}"-                        where indent = 2--ppEdge :: (String, [String]) -> Doc-ppEdge (x,xs) = (dQText x) <+> (text "->")-                    <+> (braces . hcat . punctuate semi-                        . fmap dQText $ xs)--dQText :: String -> Doc-dQText = doubleQuotes . text--{--import System.Cmd-import System.Exit-graphToDotPng :: FilePath -> [(String,[String])] -> IO Bool-graphToDotPng fpre g = do-  let [dot,png] = fmap (fpre++) [".dot",".png"]-  writeFile dot-    . render . ppGraph-      -- . fmap (show***fmap show)-        $ g-  ((==ExitSuccess) `fmap`) .system . intercalate " " $-    -- ["cat",dot,"|","dot -Tpng",">",png,"2>/dev/null;","gliv",png,"&"]-    ["cat",dot,"|","dot -Tpng",">",png,"2>/dev/null;","display",png,"&"]--graphToDotPdf :: FilePath -> [(String,[String])] -> IO Bool-graphToDotPdf fpre g = do-  let [dot,png] = fmap (fpre++) [".dot",".pdf"]-  writeFile dot-    . render . ppGraph-      -- . fmap (show***fmap show)-        $ g-  ((==ExitSuccess) `fmap`) .system . intercalate " " $-    -- ["cat",dot,"|","dot -Tpng",">",png,"2>/dev/null;","gliv",png,"&"]-    ["cat",dot,"tred","|","dot -Tpdf",">",png,"2>/dev/null;","evince",png,"&"]--}--------------------------------------------------
+ src/GHC/Vacuum/Pretty.hs view
@@ -0,0 +1,108 @@++++module GHC.Vacuum.Pretty (+   module GHC.Vacuum.Pretty+  ,module GHC.Vacuum.Pretty.Dot+) where++import Data.List+import Data.IntMap(IntMap)+import Data.Monoid(Monoid(..))+import qualified Data.IntMap as IM+import Text.PrettyPrint(Doc,text,render)+--import Language.Haskell.Meta.Utils(pretty)+import Control.Monad++import GHC.Vacuum.Util+import GHC.Vacuum.Types+import GHC.Vacuum.Pretty.Dot++-----------------------------------------------------------------------------+++toAdjPair :: (HNodeId, HNode) -> (Int, [Int])+toAdjPair = mapsnd nodePtrs++toAdjList :: IntMap HNode -> [(Int, [Int])]+toAdjList = fmap toAdjPair . IM.toList++nameGraph :: IntMap HNode -> [(String, [String])]+nameGraph m = let g = toAdjList m+                  pp i = maybe "..."+                          (\n -> nodeName n ++ "|" ++ show i)+                          (IM.lookup i m)+              in fmap (\(x,xs) -> (pp x, fmap pp xs)) g++data ShowHNode = ShowHNode+  {showHNode   :: Int -> HNode -> String+  ,externHNode :: Int -> String}++showHNodes :: ShowHNode -> IntMap HNode -> [(String, [String])]+showHNodes (ShowHNode showN externN) m+  = let g = toAdjList m+        pp i = maybe (externN i) (showN i) (IM.lookup i m)+    in fmap (\(x,xs) -> (pp x, fmap pp xs)) g++-----------------------------------------------------------------------------++--ppHs :: (Show a) => a -> Doc+--ppHs = text . pretty++ppDot :: [(String, [String])] -> Doc+ppDot = graphToDot id++renderDot :: [(String, [String])] -> String+renderDot = render . ppDot++-----------------------------------------------------------------------------++-- | To assist in \"rendering\"+--  the graph to some source.+data Draw e v m a = Draw+  {mkV   :: Int -> a -> m v+  ,mkE   :: v -> v -> m e+  ,succs :: a -> [Int]}++newtype G e v = G {unG :: IntMap (v, IntMap e)}+  deriving(Eq,Ord,Read,Show)++draw :: (Monad m) => Draw e v m a -> IntMap a -> m (G e v)+draw (Draw mkV mkE succs) g = do+  vs <- IM.fromList `liftM` forM (IM.toList g)+          (\(i,a) -> do v <- mkV i a+                        return (i,(v,succs a)))+  (G . IM.fromList) `liftM` forM (IM.toList vs)+    (\(i,(v,ps)) -> do let us = fmap (vs IM.!) ps+                       es <- IM.fromList `liftM` forM ps+                               (\p -> do e <- mkE v (fst (vs IM.! p))+                                         return (p,e))+                       return (i,(v,es)))++-- | An example @Draw@+printDraw :: Draw (Int,Int) Int IO HNode+printDraw = Draw+  {mkV   = \i _ -> print i >> return i+  ,mkE   = \u v -> print (u,v) >> return (u,v)+  ,succs = nodePtrs}++-- | Build a map to @(preds,succs)@+split :: (a -> [Int]) -> IntMap a -> IntMap ([Int],[Int])+split f = flip IM.foldWithKey mempty (\i a m ->+            let ps = f a+            in foldl' (\m p -> IM.insertWith mappend p ([i],[]) m)+                      (IM.insertWith mappend i ([],ps) m)+                      ps)++-----------------------------------------------------------------------------+++++++++++
+ src/GHC/Vacuum/Pretty/Dot.hs view
@@ -0,0 +1,66 @@++module GHC.Vacuum.Pretty.Dot (+   graphToDot+  ,ppGraph,ppEdge,gStyle+--   ,Doc,text,render+) where++import Text.PrettyPrint++------------------------------------------------++-- | .+graphToDot :: (a -> String) -> [(a, [a])] -> Doc+graphToDot f = ppGraph . fmap (f *** fmap f)+  where f *** g = \(a, b)->(f a, g b)++------------------------------------------------++gStyle :: String+gStyle = unlines+  ["  graph [rankdir=LR, splines=true];"+  ,"  node [label=\"\\N\", shape=none, fontcolor=blue, fontname=courier];"+  ,"  edge [color=black, style=dotted, fontname=courier, arrowname=onormal];"]++ppGraph :: [(String, [String])] -> Doc+ppGraph xs = (text "digraph g" <+> text "{")+              $+$ text gStyle+                $+$ nest indent (vcat . fmap ppEdge $ xs)+                    $+$ text "}"+                        where indent = 2++ppEdge :: (String, [String]) -> Doc+ppEdge (x,xs) = (dQText x) <+> (text "->")+                    <+> (braces . hcat . punctuate semi+                        . fmap dQText $ xs)++dQText :: String -> Doc+dQText = doubleQuotes . text++{-+import System.Cmd+import System.Exit+graphToDotPng :: FilePath -> [(String,[String])] -> IO Bool+graphToDotPng fpre g = do+  let [dot,png] = fmap (fpre++) [".dot",".png"]+  writeFile dot+    . render . ppGraph+      -- . fmap (show***fmap show)+        $ g+  ((==ExitSuccess) `fmap`) .system . intercalate " " $+    -- ["cat",dot,"|","dot -Tpng",">",png,"2>/dev/null;","gliv",png,"&"]+    ["cat",dot,"|","dot -Tpng",">",png,"2>/dev/null;","display",png,"&"]++graphToDotPdf :: FilePath -> [(String,[String])] -> IO Bool+graphToDotPdf fpre g = do+  let [dot,png] = fmap (fpre++) [".dot",".pdf"]+  writeFile dot+    . render . ppGraph+      -- . fmap (show***fmap show)+        $ g+  ((==ExitSuccess) `fmap`) .system . intercalate " " $+    -- ["cat",dot,"|","dot -Tpng",">",png,"2>/dev/null;","gliv",png,"&"]+    ["cat",dot,"tred","|","dot -Tpdf",">",png,"2>/dev/null;","evince",png,"&"]+-}++------------------------------------------------
+ src/GHC/Vacuum/Q.hs view
@@ -0,0 +1,118 @@+{-# LANGUAGE BangPatterns, PostfixOperators #-}++module GHC.Vacuum.Q (+   Ref,ref,(!),(.=),(!=)+  ,Q,isEmptyQ,newQ,putQ,takeQ,tryTakeQ+  ,drainQ,getQContents,takeWhileQ+) where++import Data.IORef+import Control.Monad+import Control.Concurrent+import Control.Applicative+import System.IO.Unsafe(unsafeInterleaveIO)++------------------------------------------------++newtype Ref a = Ref+  {unRef :: IORef a}++ref :: a -> IO (Ref a)+ref a = Ref <$> newIORef a++(!) :: Ref a -> IO a+(!) (Ref r) = readIORef r++(.=) :: Ref a -> a -> IO ()+Ref r .= x = writeIORef r x++(!=) :: Ref a -> (a -> (a, b)) -> IO b+Ref r != f = atomicModifyIORef r f++------------------------------------------------++data Q a = Q (MVar (Tail a))+             (MVar (Tail a))++newtype Tail a = Tail (Ref (Maybe (a, Tail a)))++emptyTail :: IO (Tail a)+emptyTail = Tail <$> ref Nothing++isEmptyTail :: Tail a -> IO Bool+isEmptyTail (Tail r) = maybe True (const False) <$> (r!)++isEmptyQ :: Q a -> IO Bool+isEmptyQ (Q rd _) = isEmptyMVar rd++newQ :: IO (Q a)+newQ = do+  hole  <- emptyTail +  readVar  <- newEmptyMVar+  writeVar <- newMVar hole+  return (Q readVar writeVar)++putQ :: Q a -> a -> IO ()+putQ (Q rd wr) val = do+  Tail old <- takeMVar wr+  new <- emptyTail+  old .= Just (val, new)+  first <- isEmptyMVar rd+  when first (putMVar rd (Tail old))+  putMVar wr new++takeQ :: Q a -> IO a+takeQ q@(Q rd _) = do+  Tail end <- takeMVar rd+  m <- (end!)+  case m of+    Nothing -> takeQ q+    Just (a, new) -> do last <- isEmptyTail new+                        when (not last) (putMVar rd new)+                        return a++tryTakeQ :: Q a -> IO (Maybe a)+tryTakeQ  q@(Q rd _) = do+  o <- tryTakeMVar rd+  case o of+    Nothing -> return Nothing+    Just (Tail end) -> do+      m <- (end!)+      case m of+        Nothing -> error "impossible!"+        Just (a, new) -> do last <- isEmptyTail new+                            when (not last) (putMVar rd new)+                            return (Just a)++drainQ :: Q a -> IO [a]+drainQ q = do+  a <- tryTakeQ q+  case a of+    Nothing -> return []+    Just a -> do as <- unsafeInterleaveIO (drainQ q)+                 return (a:as)++getQContents :: Q a -> IO [a]+getQContents q = do+  a <- takeQ q+  as <- unsafeInterleaveIO (getQContents q)+  return (a:as)+++takeWhileQ :: (a -> Bool) -> Q a -> IO [a]+takeWhileQ p q = do+  a <- takeQ q+  case p a of+    False -> return []+    True -> do+      as <- unsafeInterleaveIO (takeWhileQ p q)+      return (a:as)++++++------------------------------------------------+++
+ src/GHC/Vacuum/Types.hs view
@@ -0,0 +1,97 @@++++module GHC.Vacuum.Types (+   module GHC.Vacuum.Types+) where++import GHC.Vacuum.ClosureType+import GHC.Vacuum.Internal(HValue)++import Data.List+import Data.Word+import Data.IntMap(IntMap)+import Data.Monoid(Monoid(..))+import qualified Data.IntMap as IM+import System.Mem.StableName++------------------------------------------------++type HNodeId = Int++data HNode = HNode+  {nodePtrs  :: [HNodeId]+  ,nodeLits  :: [Word]+  ,nodeInfo  :: InfoTab}+  deriving(Eq,Ord,Read,Show)++emptyHNode :: ClosureType -> HNode+emptyHNode ct = HNode+  {nodePtrs   = []+  ,nodeLits   = []+  ,nodeInfo   = if isCon ct+                  then ConInfo [] [] [] 0 0 ct 0 []+                  else OtherInfo 0 0 ct 0 []}++nodePkg   :: HNode -> String+nodeMod   :: HNode -> String+nodeName  :: HNode -> String+nodePkg   = fst3 . itabName . nodeInfo+nodeMod   = snd3 . itabName . nodeInfo+nodeName  = trd3 . itabName . nodeInfo++fst3 (x,_,_) = x+snd3 (_,x,_) = x+trd3 (_,_,x) = x++itabName :: InfoTab -> (String, String, String)+itabName i@(ConInfo{}) = (itabPkg i, itabMod i, itabCon i)+itabName  _            = ([], [], [])++summary :: HNode -> ([String],[HNodeId],[Word])+summary (HNode ps ls info) = case itabName info of+                              (a,b,c) -> ([a,b,c],ps,ls)++data InfoTab+  = ConInfo   {itabPkg    :: String+              ,itabMod    :: String+              ,itabCon    :: String+              ,itabPtrs   ::  Word+              ,itabLits   ::  Word+              ,itabType   ::  ClosureType+              ,itabSrtLen ::  Word+              ,itabCode   :: [Word]}+  | OtherInfo {itabPtrs   ::  Word+              ,itabLits   ::  Word+              ,itabType   ::  ClosureType+              ,itabSrtLen ::  Word+              ,itabCode   :: [Word]}+  deriving(Eq,Ord,Read,Show)++data Closure = Closure+  {closPtrs :: [HValue]+  ,closLits :: [Word]+  ,closITab :: InfoTab}+  deriving(Show)++-- So we can derive Show for Closure+instance Show HValue where show _ = "(HValue)"++------------------------------------------------++data Env = Env+  {uniq  :: HNodeId+    -- the keys are hashes of StableNames+  ,seen  :: IntMap [(StableName HValue,HNodeId)]+  ,hvals :: IntMap HValue+  ,graph :: IntMap HNode}++emptyEnv :: Env+emptyEnv = Env+  {uniq = 0+  ,seen = mempty+  ,hvals = mempty+  ,graph = mempty}++------------------------------------------------+
+ src/GHC/Vacuum/Util.hs view
@@ -0,0 +1,85 @@++++module GHC.Vacuum.Util (+   module GHC.Vacuum.Util+) where++import Data.List+import Data.Char+import Data.Bits+import Data.Array.IArray hiding ((!))+import qualified Data.Array.IArray as A++hash :: String -> Int+hash [] = 0+hash  s = go 0 (fmap ord s)+  where go !h [] = h+        go !h (n:ns) =+          let a = (h `shiftL` 4)+              b = a + n+              c = b .&. 0xf0000000+              !d = case c==0 of+                    False -> let !e = c `shiftR` 24+                              in b `xor` e+                    True  -> b+              !e = complement c+              !f = d .&. e+          in go f ns++{-+unsigned long+elfhash(const char *s)+{+  unsigned long h=0, g;+  while (*s){+    h = (h << 4) + *s++;+    if((g = h & 0xf0000000))+      h ^= g >> 24;+    h &= ~g;+  }+  return h;+}+-}++------------------------------------------------+{-+look :: HValue -> [(HValue, a)] -> Maybe a+look _      [] = Nothing+look hval ((x,i):xs)+  | hval .==. x = Just i+  | otherwise   = look hval xs++(.==.) :: HValue -> HValue -> Bool+a .==. b = a `seq` b `seq`+  (0 /= I# (reallyUnsafePtrEquality# a b))++lookLazy :: HValue -> [(HValue, a)] -> Maybe a+lookLazy _      [] = Nothing+lookLazy hval ((x,i):xs)+  | hval =.= x = Just i+  | otherwise   = lookLazy hval xs++(=.=) :: HValue -> HValue -> Bool+a =.= b = (0 /= I# (reallyUnsafePtrEquality# a b))+-}++dumpArray :: Array Int a -> [a]+dumpArray a = let (m,n) = bounds a+              in fmap (a A.!) [m..n]++mapfst f = \(a,b) -> (f a,b)+mapsnd f = \(a,b) -> (a,f b)+f *** g = \(a, b) -> (f a, g b)++{-+p2i :: Ptr a -> Int+i2p :: Int -> Ptr a+p2i (Ptr a#) = I# (addr2Int# a#)+i2p (I# n#) = Ptr (int2Addr# n#)+-}++------------------------------------------------+++
vacuum.cabal view
@@ -1,5 +1,5 @@ name:               vacuum-version:            0.0.94+version:            0.0.95 cabal-version:      >= 1.6 build-type:         Simple license:            LGPL@@ -18,9 +18,15 @@   ghc-options:      -O2 -fglasgow-exts -funbox-strict-fields   extensions:       CPP, BangPatterns   includes:         ghcautoconf.h+  build-depends:    base==4.*, ghc-prim, array,+                    containers, pretty+                    -- haskell-src-meta+   exposed-modules:  GHC.Vacuum,-                    GHC.Vacuum.Dot,                     GHC.Vacuum.ClosureType,-                    GHC.Vacuum.Internal-  build-depends:    base==4.*, ghc-prim, array,-                    containers, pretty, haskell-src-meta+                    GHC.Vacuum.Internal,+                    GHC.Vacuum.Q,+                    GHC.Vacuum.Types,+                    GHC.Vacuum.Util,+                    GHC.Vacuum.Pretty,+                    GHC.Vacuum.Pretty.Dot