module GHC.Vis.View.Graph.Parser (
xDotParse
)
where
import Data.List
import Control.Monad
import qualified Data.Text.Lazy as B
import Data.Graph.Inductive hiding (nodes, edges)
import Data.GraphViz hiding (Ellipse, Polygon, parse)
import Data.GraphViz.Attributes.Complete
import Data.GraphViz.Commands.IO
import GHC.HeapView hiding (name)
import GHC.Vis.Internal
import GHC.Vis.Types
import Graphics.XDot.Types hiding (name, h, Style, Color)
import Graphics.XDot.Parser
fontName :: B.Text
fontName = "Sans"
graphFontSize :: Double
graphFontSize = 24
nodeFontSize :: Double
nodeFontSize = 24
edgeFontSize :: Double
edgeFontSize = 24
foldlMaybe :: (a -> b -> Maybe a) -> a -> [b] -> Maybe a
foldlMaybe f a bs =
foldr (\b g x -> f x b >>= g) Just bs a
xDotParse :: [(Box, String)] -> IO ([(Object Node, Operation)], [Box], Rectangle)
xDotParse as = do
hm <- walkHeap as
let nodes = zip [0..] $ map (\(_,(_,c)) -> c) rhm
edges = do
mbe <- foldM mbEdges [] nodes
return $ foldlMaybe toLEdge [] mbe
rhm = reverse hm
toLEdge xs (0, Just t) = if length rhm <= t
then Nothing
else case rhm !! t of
(_,(Just name, _)) -> Just $ (0,t,name):xs
(_,(Nothing, _)) -> Just $ (0,t,""):xs
toLEdge xs (f, Just t) = Just $ (f,t,""):xs
toLEdge xs _ = Just xs
mbEdges xs (p,BCOClosure _ _ _ bPtr _ _ _) = do
children <- bcoChildren [bPtr]
return $ map (\b -> (p, Just b)) children ++ xs
mbEdges xs (p,c) = return $ map (\b -> (p, boxPos b)) (allPtrs c) ++ xs
boxPos :: Box -> Maybe Int
boxPos b = elemIndex b $ map fst rhm
bcoChildren :: [Box] -> IO [Int]
bcoChildren [] = return []
bcoChildren (b:bs) = case boxPos b of
Nothing -> do c <- getBoxedClosureData b
ptf <- pointersToFollow2 c
bcoChildren (ptf ++ bs)
Just pos -> do children <- bcoChildren bs
return $ pos : children
es' <- edges
case es' of
Nothing -> xDotParse as
Just es -> do
let buildGraph :: Gr Closure String
buildGraph = insEdges es $ insNodes nodes empty
xDot <- graphvizWithHandle Dot (defaultVis $ toViewableGraph buildGraph) XDot hGetDot
return (getOperations xDot, getBoxes hm, getSize xDot)
getBoxes :: HeapMap -> [Box]
getBoxes hm = map (\(b,(_,_)) -> b) $ reverse hm
toViewableGraph :: Gr Closure String -> Gr String String
toViewableGraph cg = emap id $ nmap showClosure cg
defaultVis :: (Graph gr) => gr String String -> DotGraph Node
defaultVis = graphToDot nonClusteredParams
{ globalAttributes = [GraphAttrs [BgColor [toWC $ RGBA 0 0 0 0], FontName fontName, FontSize graphFontSize]]
, fmtNode = \ (_,l) -> [toLabel l, FontName fontName, FontSize nodeFontSize]
, fmtEdge = \ (_,_,l) -> [toLabel l, FontName fontName, FontSize edgeFontSize]
}