ghc-debug-client-0.6.0.0: src/GHC/Debug/CostCentres.hs
{-# LANGUAGE BangPatterns #-}
module GHC.Debug.CostCentres
( findAllChildrenOfCC
, findExactlyByCC
, findAllCCSPayloads
, traverseCCSPayloads
-- * Helper functions for working with `IndexTable`'s
, flattenIndexTable
, traverseIndexTable
, foldIndexTable
-- * Efficient representation of CCSPtr sets
, CCSSet(..)
, memberCCSSet
) where
import qualified Data.Set as Set
import Data.IntSet (IntSet)
import qualified Data.IntSet as IntSet
import GHC.Debug.Client
import GHC.Debug.Types.Ptr (CCSPtr(..))
import Data.Coerce (coerce)
newtype CCSSet = CCSSet IntSet
memberCCSSet :: CCSPtr -> CCSSet -> Bool
memberCCSSet (CCSPtr k) set = IntSet.member (fromIntegral k) (coerce set)
-- | Find all Cost Centre Stacks that reference precisely the cost centre with the given id.
findExactlyByCC :: (CCPayload -> Bool) -> DebugM (Set.Set CCSPtr)
findExactlyByCC isRelevantCC = do
ccsMain <- requestCCSMain
collectNode Set.empty ccsMain
where
collectNode :: Set.Set CCSPtr -> CCSPtr -> DebugM (Set.Set CCSPtr)
collectNode !seen !ccsPtr = do
ccsPl <- dereferenceCCS ccsPtr
ccPl <- dereferenceCC (ccsCc ccsPl)
let newSeen = if isRelevantCC ccPl
then ccsPtr `Set.insert` seen
else seen
foldIndexTable (\_ ptr backEdge !seen' -> do
if backEdge
then pure seen'
else collectNode seen' ptr)
newSeen
(ccsIndexTable ccsPl)
-- | Find all cost centre stack parts that are transitively children of the cost
-- centre with the given id.
findAllChildrenOfCC :: (CCPayload -> Bool) -> DebugM (Set.Set CCSPtr)
findAllChildrenOfCC isRelevantCC = do
ccsMain <- requestCCSMain
findCostCentre Set.empty ccsMain
where
findCostCentre :: Set.Set CCSPtr -> CCSPtr -> DebugM (Set.Set CCSPtr)
findCostCentre !seen !ccsPtr = do
ccsPl <- dereferenceCCS ccsPtr
ccPl <- dereferenceCC (ccsCc ccsPl)
if isRelevantCC ccPl
then collectNodes seen ccsPtr
else
foldIndexTable (\_ ptr backEdge !seen' -> do
if backEdge
then pure seen'
else findCostCentre seen' ptr)
seen
(ccsIndexTable ccsPl)
collectNodes :: Set.Set CCSPtr -> CCSPtr -> DebugM (Set.Set CCSPtr)
collectNodes !seen !ccsPtr = do
ccsPl <- dereferenceCCS ccsPtr
foldIndexTable (\_ ptr backEdge !seen' -> do
let seen'' = ptr `Set.insert` seen'
if backEdge
then pure seen''
else collectNodes seen'' ptr)
(ccsPtr `Set.insert` seen)
(ccsIndexTable ccsPl)
findAllCCSPayloads :: DebugM CCSSet
findAllCCSPayloads = do
ccsMain <- requestCCSMain
CCSSet <$> collectNodes IntSet.empty ccsMain
where
collectNodes :: IntSet.IntSet -> CCSPtr -> DebugM (IntSet.IntSet)
collectNodes !seen ccsPtr@(CCSPtr w_) = do
ccsPl <- dereferenceCCS ccsPtr
foldIndexTable (\_ ptr@(CCSPtr w) backEdge !seen' -> do
let seen'' = fromIntegral w `IntSet.insert` seen'
if backEdge
then pure seen''
else collectNodes seen'' ptr)
(fromIntegral w_ `IntSet.insert` seen)
(ccsIndexTable ccsPl)
traverseCCSPayloads :: DebugM ()
traverseCCSPayloads = do
ccsMain <- requestCCSMain
collectNodes ccsMain
where
collectNodes :: CCSPtr -> DebugM ()
collectNodes ccsPtr = do
ccsPl <- dereferenceCCS ccsPtr
foldIndexTable (\_ ptr backEdge () -> do
if backEdge
then pure ()
else collectNodes ptr)
()
(ccsIndexTable ccsPl)
traverseIndexTable :: Maybe IndexTablePtr -> (CCPtr -> CCSPtr -> Bool -> DebugM a) -> DebugM [a]
traverseIndexTable Nothing _ = pure []
traverseIndexTable (Just ptr) f = do
idxTable <- dereferenceIndexTable ptr
x <- f (itCostCentre idxTable) (itCostCentreStack idxTable) (itBackEdge idxTable)
rest <- traverseIndexTable (itNext idxTable) f
pure $ x:rest
foldIndexTable :: (CCPtr -> CCSPtr -> Bool -> a -> DebugM a) -> a -> Maybe IndexTablePtr -> DebugM a
foldIndexTable _f acc Nothing = pure acc
foldIndexTable f acc (Just ptr) = do
idxTable <- dereferenceIndexTable ptr
acc' <- f (itCostCentre idxTable) (itCostCentreStack idxTable) (itBackEdge idxTable) acc
foldIndexTable f acc' (itNext idxTable)
-- | Flatten an optional index table pointer into a list of CCS Payloads.
flattenIndexTable :: Maybe IndexTablePtr -> DebugM [CCSPayload]
flattenIndexTable root = traverseIndexTable root (\_ ccsPtr _ -> dereferenceCCS ccsPtr)