{-# LANGUAGE CPP, ScopedTypeVariables, RecordWildCards #-} {- | Module : GHC.Vis.View.Common Copyright : (c) Dennis Felsing License : 3-Clause BSD-style Maintainer : dennis@felsin9.de -} module GHC.Vis.View.Common ( visSignal, visRunning, visState, visBoxes, visHidden, visHeapHistory, getHeapGraph, inHistoryMode, parseBoxes, parseBoxesHeap, evaluate ) where #if __GLASGOW_HASKELL__ < 706 import Prelude hiding (catch) #endif import Control.Concurrent import Control.DeepSeq import Control.Exception hiding (evaluate) import Control.Monad.State hiding (State, fix) import qualified Data.IntMap as M import Data.IORef import Data.Maybe (catMaybes) import Data.List import System.IO.Unsafe import GHC.Vis.Internal import GHC.Vis.Types import GHC.HeapView -- | Communication channel to the visualization visSignal :: MVar Signal visSignal = unsafePerformIO (newEmptyMVar :: IO (MVar Signal)) -- | Whether a visualization is currently running visRunning :: MVar Bool visRunning = unsafePerformIO (newMVar False) -- | Internal state of the visualization visState :: IORef State visState = unsafePerformIO $ newIORef $ State (0, 0) ListView 1 (0, 0) False False -- | All the visualized boxes visBoxes :: MVar [NamedBox] visBoxes = unsafePerformIO (newMVar [] :: IO (MVar [NamedBox])) -- | Hidden boxes visHidden :: MVar [Box] visHidden = unsafePerformIO (newMVar [] :: IO (MVar [Box])) -- | All heap graphs since the last clear command visHeapHistory :: MVar (Int, [(HeapGraph Identifier, [(Identifier, HeapGraphIndex)])]) visHeapHistory = unsafePerformIO (newMVar (0, [(HeapGraph M.empty, [])]) :: IO (MVar (Int, [(HeapGraph Identifier, [(Identifier, HeapGraphIndex)])]))) -- | Get the currently selected heap graph getHeapGraph :: IO (HeapGraph Identifier, [(Identifier, HeapGraphIndex)]) getHeapGraph = do (pos, xs) <- readMVar visHeapHistory return $ xs !! pos -- | Whether we're currently looking at an older heap graph or the most recent one inHistoryMode :: IO Bool inHistoryMode = liftM ((> 0) . fst) $ readMVar visHeapHistory -- | Evaluate an object identified by a String. evaluate :: String -> IO () evaluate identifier = do (_,HeapGraph m) <- printAll (show (M.map go m) `deepseq` return ()) `catch` \(e :: SomeException) -> putStrLn $ "Caught exception while evaluating: " ++ show e where go hge@(HeapGraphEntry (Box a) _ _ n) | n == identifier = seq a hge | otherwise = hge -- | Walk the heap for a list of objects to be visualized and their -- corresponding names. parseBoxes :: IO [[VisObject]] parseBoxes = generalParseBoxes evalState -- | Walk the heap for a list of objects to be visualized and their -- corresponding names. Also return the resulting 'HeapMap' and another -- 'HeapMap' that does not contain BCO pointers. parseBoxesHeap :: IO ([[VisObject]], PState) parseBoxesHeap = generalParseBoxes runState --generalParseBoxes :: -- (PrintState (Maybe [[VisObject]]) -> PState -> b) -- -> [NamedBox] -> IO b generalParseBoxes :: (PrintState [[VisObject]] -> PState -> b) -> IO b generalParseBoxes f = do --(hg, starts) <- multiBuildHeapGraph 100 $ map (\(_,x) -> ("",x)) bs (hg@(HeapGraph m), starts) <- getHeapGraph let bindings = boundMultipleTimes hg $ map snd starts let g i = do r <- parseClosure i return $ simplify r return $ f (mapM (g . snd) starts) $ PState 1 1 1 bindings $ HeapGraph $ M.map (\hge -> hge{hgeData = ""}) m -- | In the given HeapMap, list all indices that are used more than once. The -- second parameter adds external references, commonly @[heapGraphRoot]@. boundMultipleTimes :: HeapGraph a -> [HeapGraphIndex] -> [HeapGraphIndex] boundMultipleTimes (HeapGraph m) roots = map head $ filter (not.null) $ map tail $ group $ sort $ roots ++ concatMap (catMaybes . allPtrs . hgeClosure) (M.elems m) -- Pulls together multiple Unnamed objects to one simplify :: [VisObject] -> [VisObject] simplify [] = [] simplify [Named a bs] = [Named a $ simplify bs] simplify [a] = [a] simplify (Unnamed a : Unnamed b : xs) = simplify $ Unnamed (a ++ b) : xs simplify (Named a bs : xs) = Named a (simplify bs) : simplify xs simplify (a:xs) = a : simplify xs printAll :: IO (String, HeapGraph String) printAll = do (t, PState{heapGraph = h}) <- parseBoxesHeap return (show t, h)