Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit efd3adc

Browse files
add retainer graph (inverse reference graph) export
1 parent 5963a9d commit efd3adc

File tree

3 files changed

+154
-0
lines changed

3 files changed

+154
-0
lines changed

‎external-stg-interpreter/external-stg-interpreter.cabal‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ library
3131
Stg.Interpreter.Debugger.Region
3232
Stg.Interpreter.Debugger.UI
3333
Stg.Interpreter.Debugger.TraverseState
34+
Stg.Interpreter.Debugger.Retainer
3435
Stg.Interpreter.GC
3536
Stg.Interpreter.GC.GCRef
3637
Stg.Interpreter.GC.LiveDataAnalysis
@@ -93,6 +94,8 @@ library
9394
unagi-chan,
9495
pretty-terminal,
9596
pretty-simple,
97+
dom-lt,
98+
bimap,
9699
souffle-haskell,
97100
external-stg-syntax,
98101
external-stg
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
{-# LANGUAGE RecordWildCards, LambdaCase, OverloadedStrings #-}
2+
module Stg.Interpreter.Debugger.Retainer
3+
( exportRetainerGraph
4+
-- , exportRetainerDominatorTree
5+
) where
6+
7+
import Control.Monad.Writer
8+
import Control.Monad.State
9+
import Data.Maybe
10+
import Data.Bimap ( Bimap )
11+
import qualified Data.Bimap as Bimap
12+
import Data.Map (Map)
13+
import Data.Set (Set)
14+
import Data.IntMap.Strict (IntMap)
15+
import Data.IntSet (IntSet)
16+
import qualified Data.Set as Set
17+
import qualified Data.IntSet as IntSet
18+
import qualified Data.IntMap.Strict as IntMap
19+
import qualified Data.Map as Map
20+
import qualified Data.ByteString.Char8 as BS8
21+
import qualified Data.Graph.Dom as Graph
22+
import System.IO
23+
import Stg.Interpreter.Base
24+
import Stg.Interpreter.GC.GCRef
25+
import Stg.Interpreter.GC.LiveDataAnalysis
26+
import Stg.Interpreter.Debugger.TraverseState
27+
28+
29+
data RetainerState
30+
= RetainerState
31+
{ rsGraph :: IntMap IntSet
32+
, rsNodeMap :: Bimap GCSymbol Int
33+
}
34+
35+
type RetainerM = StateT RetainerState IO
36+
37+
addNode :: GCSymbol -> RetainerM Int
38+
addNode n = do
39+
nodeMap <- gets rsNodeMap
40+
case Bimap.lookup n nodeMap of
41+
Just i -> pure i
42+
Nothing -> do
43+
let i = Bimap.size nodeMap
44+
modify' $ \s@RetainerState{..} -> s {rsNodeMap = Bimap.insert n i rsNodeMap}
45+
pure i
46+
47+
addEdge :: GCSymbol -> GCSymbol -> RetainerM ()
48+
addEdge from to = do
49+
fromId <- addNode from
50+
toId <- addNode to
51+
modify' $ \s@RetainerState{..} -> s {rsGraph = IntMap.insertWith IntSet.union fromId (IntSet.singleton toId) rsGraph}
52+
53+
exportRetainerGraph :: FilePath -> FilePath -> StgState -> GCSymbol -> IO ()
54+
exportRetainerGraph nodesFname edgesFname stgState root = do
55+
{-
56+
done - calculate retainer graph
57+
done - traverse graph
58+
-}
59+
-- HINT: retainer = inverse reference
60+
RetainerState{..} <- flip execStateT (RetainerState mempty Bimap.empty) . withReferenceFacts stgState $ \from to -> addEdge to from
61+
let gcRootSet :: Map GCSymbol String
62+
gcRootSet = execWriter $ withGCRootFacts stgState (ssLocalEnv stgState) $ \msg s -> tell $ Map.singleton s msg
63+
64+
withFile edgesFname WriteMode $ \hEdge -> do
65+
withFile nodesFname WriteMode $ \hNode -> do
66+
BS8.hPutStrLn hNode $ BS8.intercalate "\t"
67+
[ "Id"
68+
, "Label"
69+
, "partition2"
70+
]
71+
BS8.hPutStrLn hEdge $ BS8.intercalate "\t"
72+
[ "Source"
73+
, "Target"
74+
, "partition2"
75+
]
76+
flip evalStateT Set.empty . addEdgesFrom hNode hEdge stgState gcRootSet root True $ \case
77+
source
78+
| Just i <- Bimap.lookup source rsNodeMap
79+
, Just edges <- IntMap.lookup i rsGraph
80+
-> catMaybes $ map (flip Bimap.lookupR rsNodeMap) $ IntSet.toList edges
81+
| otherwise
82+
-> []
83+
84+
pure ()
85+
86+
type ExportM = StateT (Set GCSymbol) IO
87+
88+
mark :: GCSymbol -> ExportM Bool
89+
mark symbol = state $ \visitedSet ->
90+
let wasVisited = Set.member symbol visitedSet
91+
in (not wasVisited, if wasVisited then visitedSet else Set.insert symbol visitedSet)
92+
93+
addEdgesFrom :: Handle -> Handle -> StgState -> Map GCSymbol String -> GCSymbol -> Bool -> (GCSymbol -> [GCSymbol]) -> ExportM ()
94+
addEdgesFrom hNode hEdge stgState@StgState{..} gcRootSet source isRoot getEdges = do
95+
firstTimeVisit <- mark source
96+
when firstTimeVisit $ do
97+
liftIO $ print source
98+
99+
let (ns, idx) = decodeRef source
100+
(nodeLabel, nodeCategory) = case ns of
101+
NS_HeapPtr
102+
| Just ho <- IntMap.lookup idx ssHeap
103+
-> (getHeapObjectSummary ho, getHeapObjectCategory ho)
104+
_ -> (drop 3 $ show ns, drop 3 $ show ns)
105+
106+
-- HINT: write line to node .tsv
107+
liftIO $ do
108+
BS8.hPut hNode $ unGCSymbol source
109+
BS8.hPut hNode "\t"
110+
hPutStr hNode $
111+
(if isRoot then ("Root " ++) else id) $
112+
(maybe id (\msg str -> "GCRoot " ++ msg ++ " " ++ str) $ Map.lookup source gcRootSet) $
113+
nodeLabel
114+
BS8.hPut hNode "\t"
115+
hPutStr hNode nodeCategory
116+
BS8.hPut hNode "\n"
117+
118+
-- TODO: generate Source node attributes ; or get
119+
forM_ (getEdges source) $ \target -> do
120+
-- HINT: write line to edge .tsv
121+
liftIO $ do
122+
BS8.hPut hEdge $ unGCSymbol source
123+
BS8.hPut hEdge "\t"
124+
BS8.hPut hEdge $ unGCSymbol target
125+
BS8.hPut hEdge "\t"
126+
BS8.hPut hEdge "green"
127+
BS8.hPut hEdge "\n"
128+
addEdgesFrom hNode hEdge stgState gcRootSet target False getEdges
129+
130+
{-
131+
exportRetainerDominatorTree :: FilePath -> FilePath -> StgState -> GCSymbol -> IO ()
132+
exportRetainerDominatorTree nodesFname edgesFname stgState root = do
133+
-- HINT: retainer = inverse reference
134+
RetainerState{..} <- flip execStateT (RetainerState mempty Bimap.empty) . withReferenceFacts stgState $ \from to -> addEdge to from
135+
let gcRootSet :: Set GCSymbol
136+
gcRootSet = execWriter $ withGCRootFacts stgState (ssLocalEnv stgState) (tell . Set.singleton)
137+
138+
withFile edgesFname WriteMode $ \hEdge -> do
139+
withFile nodesFname WriteMode $ \hNode -> do
140+
BS8.hPutStrLn hNode $ BS8.intercalate "\t"
141+
[ "Id"
142+
, "Label"
143+
, "partition2"
144+
]
145+
BS8.hPutStrLn hEdge $ BS8.intercalate "\t"
146+
[ "Source"
147+
, "Target"
148+
, "partition2"
149+
]
150+
-}

‎stack.yaml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ packages:
88
# - 'external-stg-compiler'
99

1010
extra-deps:
11+
- dom-lt-0.2.3
1112
- souffle-haskell-3.5.1
1213
- type-errors-pretty-0.0.1.2@sha256:9042b64d1ac2f69aa55690576504a2397ebea8a6a55332242c88f54027c7eb57,2781
1314
- github: csabahruska/final-pretty-printer

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /