ipedb-0.2.0.0: src/IpeDB/Types/CostCentre.hs
{-# LANGUAGE OverloadedStrings #-}
{- |
Module : IpeDb.Types.CostCentre
Description : Representation for GHC cost centres.
Stability : experimental
Portability : portable
-}
module IpeDB.Types.CostCentre (
CostCentreId (..),
CostCentre (..),
toCostCentre,
) where
import Control.Exception (assert)
import Data.Binary (Binary (..), Get, Put)
import Data.Binary.Text (getTextUTF8LEB128, putTextUTF8LEB128)
import Data.Coerce (coerce)
import Data.Either (fromRight, isRight)
import Data.Hashable (Hashable)
import Data.Text (Text)
import Data.Text qualified as T
import Data.Word (Word32)
import Database.LSMTree qualified as LSMT
import Foreign (toBool)
import Foreign.C.Types (CBool (..))
import GHC.Generics (Generic)
import GHC.RTS.Events (Event)
import GHC.RTS.Events qualified as E
import IpeDB.Database qualified as DB (SerialiseViaBinary (..))
import IpeDB.Types.SrcLoc (SrcLoc (..), parseSrcLoc)
import Numeric (showHex)
import Text.ParserCombinators.ReadP qualified as P
import Text.Read.Lex (readHexP)
{- |
The type of cost-centre IDs.
-}
newtype CostCentreId = CostCentreId
{ value :: Word32
}
deriving newtype (Hashable, Num)
deriving stock (Generic, Eq, Ord)
instance Show CostCentreId where
showsPrec :: Int -> CostCentreId -> ShowS
showsPrec _ (CostCentreId ipId) = showString "0x" . showHex ipId
instance Read CostCentreId where
readsPrec :: Int -> ReadS CostCentreId
readsPrec _ = P.readP_to_S (CostCentreId <$> (P.string "0x" *> readHexP))
{- |
The type of a cost-centre entry, as produced by the v`GHC.RTS.Events.HeapProfCostCentre` event.
-}
data CostCentre = CostCentre
{ ccLabel :: !Text
, ccModule :: !Text
, ccSrcLoc :: !SrcLoc
, ccIsCAF :: !Bool
}
deriving stock (Generic, Eq, Ord, Show, Read)
{- |
Extract a t`CostCentre` from a @ghc-events@ t`Event`.
-}
toCostCentre :: Event -> Maybe (CostCentreId, CostCentre)
toCostCentre ev
-- If the event is an `E.InfoTableProv` event, process it, and set @started@...
| E.HeapProfCostCentre{..} <- ev.evSpec = do
let !ccId = CostCentreId heapProfCostCentreId
let !ccSrcLocOrError
| heapProfSrcLoc `elem` ["<built-in>", "<entire-module>"] = Right UnhelpfulSrcLoc
| otherwise = parseSrcLoc . T.unpack $ heapProfSrcLoc
assert (isRight ccSrcLocOrError) $ do
let !cc =
CostCentre
{ ccLabel = heapProfLabel
, ccModule = heapProfModule
, ccSrcLoc = fromRight UnhelpfulSrcLoc ccSrcLocOrError
, ccIsCAF = toBool (coerce @E.HeapProfFlags @CBool heapProfFlags)
}
Just (ccId, cc)
| otherwise = Nothing
--------------------------------------------------------------------------------
-- Instances for binary serialisation of CostCentre
--------------------------------------------------------------------------------
deriving newtype instance Binary CostCentreId
instance Binary CostCentre where
get :: Get CostCentre
get = do
ccLabel <- getTextUTF8LEB128
ccModule <- getTextUTF8LEB128
ccSrcLoc <- get
ccIsCAF <- get
pure CostCentre{..}
put :: CostCentre -> Put
put CostCentre{..} = do
putTextUTF8LEB128 ccLabel
putTextUTF8LEB128 ccModule
put ccSrcLoc
put ccIsCAF
--------------------------------------------------------------------------------
-- Instances for lsm-tree serialisation of CostCentre
--------------------------------------------------------------------------------
deriving newtype instance LSMT.SerialiseKey CostCentreId
deriving via DB.SerialiseViaBinary CostCentre instance LSMT.SerialiseValue CostCentre
deriving via LSMT.ResolveAsFirst CostCentre instance LSMT.ResolveValue CostCentre