packages feed

ghc-debug-brick-0.8.0.0: src/GHC/Debug/Brick/Action/Thunk.hs

{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE OverloadedStrings #-}
module GHC.Debug.Brick.Action.Thunk (
  thunkAnalysisActionAsync,
  thunkTreeMode,
  thunkTree,
  ) where

import Brick
import Brick.Widgets.IOTree (IOTree, setIOTreeRoots)
import Control.Monad (forM)
import qualified Data.List as List
import qualified Data.Map.Strict as Map
import qualified Data.Ord as Ord
import Data.Text (pack)
import Lens.Micro.Platform

import GHC.Debug.Brick.Action.Async
import GHC.Debug.Brick.ClosureDetails
import GHC.Debug.Brick.IOTree
import GHC.Debug.Brick.Lib as GD
import GHC.Debug.Brick.Model
import GHC.Debug.Brick.Render.Closure
import GHC.Debug.Brick.Render.Utils
import GHC.Debug.Profile.Types
import GHC.Debug.Retainers (SearchLimit)
import qualified GHC.Debug.Thunks as GD

thunkAnalysisActionAsync :: Debuggee -> EventM n OperationalState ()
thunkAnalysisActionAsync dbg = do
  outside_os <- get

  put $ outside_os
    & treeMode .~ thunkTreeMode (_resultSize outside_os) (thunkTree dbg) Map.empty

  runWithAsyncSampleReporter dbg "Counting thunks" ThunkSample
    (thunkAnalysisAsync dbg)
    (\ result -> do
      sendEvent $ CacheSearch DoThunkSearch result
      os <- get
      put (os & resetFooter))

thunkTreeMode :: SearchLimit -> IOTree ThunkLine Name -> GD.ThunkCensusBySourceLocation -> TreeMode
thunkTreeMode _limit tree census =
  let
    top_closures = [ ThunkLine k (cscount v) (sample v) | (k, v) <- (List.sortOn (Ord.Down . (cscount . snd)) (Map.toList census))]
  in
    Thunk renderHeaderPane (setIOTreeRoots top_closures tree)

-- | Create a retainer tree which we can incrementally add retainer samples to when we receive them.
thunkTree :: Debuggee -> IOTree ThunkLine Name
thunkTree dbg =
  mkIOTree dbg [] getChildrenOfThunkLine renderInline id

getChildrenOfThunkLine :: Debuggee -> ThunkLine -> IO [ThunkLine]
getChildrenOfThunkLine dbg (ThunkLine _ _ smp) = do
  cs' <- run dbg $ forM (getSamples smp) $ \c -> do
    c' <- GD.dereferenceClosure c
    return $ ListFullClosure $ Closure c c'
  children <- traverse (traverse (fillListItem dbg)) $ zipWith (\n c -> (show @Int n, c)) [0..] cs'
  mapM (\(lbl, child) -> ThunkClosureLine <$> getClosureDetails dbg (pack lbl) child) children
getChildrenOfThunkLine dbg (ThunkClosureLine c) = map ThunkClosureLine <$> getChildren dbg c

renderHeaderPane :: ThunkLine -> Widget Name
renderHeaderPane (ThunkLine sc c _smp) = vBox $
  maybe [txt "NoLoc"] renderSourceInformation sc
  ++ [ strWrap ("Count: " ++ show (getCount c)) ]
renderHeaderPane (ThunkClosureLine cd) = renderClosureDetails cd

renderInline :: ThunkLine -> [Widget n]
renderInline (ThunkLine msc (Count c) _smp) =
  [ case msc of
      Just sc -> strLabel (infoPosition sc)
      Nothing -> txtLabel "NoLoc"
  , txt " "
  , str (show c)
  ]
renderInline (ThunkClosureLine cd) = renderInlineClosureDesc cd