ghc-debug-brick-0.8.0.0: src/GHC/Debug/Brick/Action/Profile.hs
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE LambdaCase #-}
module GHC.Debug.Brick.Action.Profile (
profileAction,
profileTreeMode,
profileTree,
renderProfileHeader,
) where
import Brick
import Brick.Widgets.IOTree
import qualified Data.List as List
import qualified Data.Map.Strict as Map
import qualified Data.Ord as Ord
import qualified Data.Semigroup
import qualified Data.Text as T
import Data.Traversable
import GHC.Debug.Brick.Action.Async
import GHC.Debug.Brick.ClosureDetails
import GHC.Debug.Brick.IOTree
import GHC.Debug.Brick.Lib
import qualified GHC.Debug.Brick.Lib as GD
import GHC.Debug.Brick.Model
import GHC.Debug.Brick.Render.Closure
import GHC.Debug.Brick.Render.Header (renderHeaderWithSummary)
import GHC.Debug.Brick.Render.Utils
import GHC.Debug.Profile
import qualified GHC.Debug.Profile as GD
import qualified GHC.Debug.Profile as GDP
import GHC.Debug.Profile.Types
import GHC.Debug.Retainers (SearchLimit)
import qualified Graphics.Vty as Vty
import Lens.Micro
import qualified Numeric
profileAction :: Debuggee -> ProfileLevel -> EventM n OperationalState ()
profileAction dbg lvl = do
outside_os <- get
let
put (outside_os
& resetFooter
& treeMode .~ profileTreeMode (_resultSize outside_os) (profileTree dbg) Map.empty
)
runWithAsyncSampleReporter dbg "Profile" (ProfileSample lvl)
(profileAsync dbg lvl)
(\ result -> do
-- write the final result to disk
-- liftIO $ GD.writeCensusByClosureType fp finalRes
sendEvent $ CacheSearch (DoProfileSearch lvl) result
os <- get
put (os & resetFooter)
)
profileTreeMode :: SearchLimit -> IOTree ProfileLine Name -> GD.CensusByClosureType -> TreeMode
profileTreeMode _limit tree census =
let
top_closure = [ProfileLine k kargs v | ((k, kargs), v) <- (List.sortOn (Ord.Down . (cssize . snd)) (Map.toList census))]
total_stats = foldMap snd (Map.toList census)
in
Profile (renderProfileHeader total_stats) (setIOTreeRoots top_closure tree)
profileTree :: Debuggee -> IOTree ProfileLine Name
profileTree dbg =
let
g_children d (ClosureLine c) = map ClosureLine <$> getChildren d c
g_children d (ProfileLine _ _ stats) = do
let cs = getSamples (sample stats)
cs' <- run dbg $ forM cs $ \c -> do
c' <- GD.dereferenceClosure c
return $ ListFullClosure $ Closure c c'
children' <- traverse (traverse (fillListItem d)) $ zipWith (\n c -> (show @Int n, c)) [0..] cs'
mapM (\(lbl, child) -> ClosureLine <$> getClosureDetails d (T.pack lbl) child) children'
in
mkIOTree dbg [] g_children renderProfileLine id
renderProfileLine :: ProfileLine -> [Widget Name]
renderProfileLine (ClosureLine c) = renderInlineClosureDesc c
renderProfileLine (ProfileLine k kargs c) =
[ txt (GDP.prettyShortProfileKey k <> GDP.prettyShortProfileKeyArgs kargs)
, txt " "
, showLine c
]
where
showLine :: CensusStats -> Widget Name
showLine (CS (Count n) (Size s) (Data.Semigroup.Max (Size mn)) _) =
hBox
[ withFontColor totalSizeColor $ str (show s), vSpace
, withFontColor countColor $ str (show n), vSpace
, withFontColor sizeColor $ str (show mn), vSpace
, withFontColor avgSizeColor $ str (Numeric.showFFloat @Double (Just 1) (fromIntegral s / fromIntegral n) "")
]
withFontColor color = modifyDefAttr (flip Vty.withForeColor color)
totalSizeColor = Vty.RGBColor 0x26 0x83 0xDE
countColor = Vty.RGBColor 0xDE 0x66 0x26
sizeColor = Vty.RGBColor 0x26 0xDE 0xD7
avgSizeColor = Vty.RGBColor 0xAB 0x4D 0xE0
renderProfileHeader :: CensusStats -> ProfileLine -> Widget Name
renderProfileHeader total_stats l =
renderHeaderWithSummary
(renderHeaderPane l)
(renderHeaderPane (ProfileLine (GDP.ProfileClosureDesc "Total") GDP.NoArgs total_stats))
renderHeaderPane :: ProfileLine -> Widget Name
renderHeaderPane (ClosureLine cs) = renderClosureDetails cs
renderHeaderPane (ProfileLine k args (CS (Count n) (Size s) (Data.Semigroup.Max (Size mn)) _)) = vBox $
[ txtLabel "Label " <+> vSpace <+> txt (GDP.prettyShortProfileKey k <> GDP.prettyShortProfileKeyArgs args)
]
<>
(case k of
GDP.ProfileConstrDesc desc ->
[ txtLabel "Package " <+> vSpace <+> (txt (GDP.pkgsText desc))
, txtLabel "Module " <+> vSpace <+> (txt (GDP.modlText desc))
, txtLabel "Constructor" <+> vSpace <+> (txt (GDP.nameText desc))
]
_ -> []
)
<>
[ txtLabel "Count " <+> vSpace <+> str (show n)
, txtLabel "Size " <+> vSpace <+> renderBytes s
, txtLabel "Max " <+> vSpace <+> renderBytes mn
, txtLabel "Average " <+> vSpace <+> renderBytes @Double (fromIntegral s / fromIntegral n)
]