{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE MultiWayIf #-}
module GHC.RTS.Events.Incremental
(
Decoder(..)
, decodeHeader
, decodeEvents
, decodeEventLog
, readHeader
, readEvents
, readEventLog
) where
import Control.Monad
import Data.Either
import Data.Maybe
import Prelude
import qualified Data.Binary.Get as G
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Internal as BL
import qualified Data.IntMap.Strict as IM
import GHC.RTS.EventParserUtils
import GHC.RTS.EventTypes
import GHC.RTS.Events.Binary
#define EVENTLOG_CONSTANTS_ONLY
#include "EventLogFormat.h"
data Decoder a
= Consume (B.ByteString -> Decoder a)
| Produce !a (Decoder a)
| Done B.ByteString
| Error B.ByteString String
pushChunk :: Decoder a -> B.ByteString -> Decoder a
pushChunk :: Decoder a -> ByteString -> Decoder a
pushChunk Decoder a
decoder ByteString
chunk = case Decoder a
decoder of
Consume ByteString -> Decoder a
k -> ByteString -> Decoder a
k ByteString
chunk
Produce a
a Decoder a
decoder' -> a -> Decoder a -> Decoder a
forall a. a -> Decoder a -> Decoder a
Produce a
a (Decoder a -> Decoder a) -> Decoder a -> Decoder a
forall a b. (a -> b) -> a -> b
$ Decoder a
decoder' Decoder a -> ByteString -> Decoder a
forall a. Decoder a -> ByteString -> Decoder a
`pushChunk` ByteString
chunk
Done ByteString
leftover -> ByteString -> Decoder a
forall a. ByteString -> Decoder a
Done (ByteString -> Decoder a) -> ByteString -> Decoder a
forall a b. (a -> b) -> a -> b
$ ByteString
leftover ByteString -> ByteString -> ByteString
`B.append` ByteString
chunk
Error ByteString
leftover String
err -> ByteString -> String -> Decoder a
forall a. ByteString -> String -> Decoder a
Error (ByteString
leftover ByteString -> ByteString -> ByteString
`B.append` ByteString
chunk) String
err
withHeader
:: (Header -> B.ByteString -> Decoder r)
-> Decoder r
Header -> ByteString -> Decoder r
f = Decoder Header -> Decoder r
go (Decoder Header -> Decoder r) -> Decoder Header -> Decoder r
forall a b. (a -> b) -> a -> b
$ Get Header -> Decoder Header
forall a. Get a -> Decoder a
G.runGetIncremental Get Header
getHeader
where
go :: Decoder Header -> Decoder r
go Decoder Header
decoder = case Decoder Header
decoder of
G.Done ByteString
leftover ByteOffset
_ Header
header -> Header -> ByteString -> Decoder r
f Header
header ByteString
leftover
G.Partial Maybe ByteString -> Decoder Header
k -> (ByteString -> Decoder r) -> Decoder r
forall a. (ByteString -> Decoder a) -> Decoder a
Consume ((ByteString -> Decoder r) -> Decoder r)
-> (ByteString -> Decoder r) -> Decoder r
forall a b. (a -> b) -> a -> b
$ \ByteString
chunk -> Decoder Header -> Decoder r
go (Decoder Header -> Decoder r) -> Decoder Header -> Decoder r
forall a b. (a -> b) -> a -> b
$ Maybe ByteString -> Decoder Header
k (Maybe ByteString -> Decoder Header)
-> Maybe ByteString -> Decoder Header
forall a b. (a -> b) -> a -> b
$ ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
chunk
G.Fail ByteString
leftover ByteOffset
_ String
err -> ByteString -> String -> Decoder r
forall a. ByteString -> String -> Decoder a
Error ByteString
leftover String
err
decodeHeader :: Decoder Header
= (Header -> ByteString -> Decoder Header) -> Decoder Header
forall r. (Header -> ByteString -> Decoder r) -> Decoder r
withHeader ((Header -> ByteString -> Decoder Header) -> Decoder Header)
-> (Header -> ByteString -> Decoder Header) -> Decoder Header
forall a b. (a -> b) -> a -> b
$ \Header
header ByteString
leftover -> Header -> Decoder Header -> Decoder Header
forall a. a -> Decoder a -> Decoder a
Produce Header
header (Decoder Header -> Decoder Header)
-> Decoder Header -> Decoder Header
forall a b. (a -> b) -> a -> b
$ ByteString -> Decoder Header
forall a. ByteString -> Decoder a
Done ByteString
leftover
decodeEvents :: Header -> Decoder Event
decodeEvents :: Header -> Decoder Event
decodeEvents Header
header = Int -> Maybe Int -> Decoder (Maybe Event) -> Decoder Event
forall t.
(Ord t, Num t) =>
t -> Maybe Int -> Decoder (Maybe Event) -> Decoder Event
go (Int
0 :: Int) Maybe Int
forall a. Maybe a
Nothing Decoder (Maybe Event)
decoder0
where
decoder0 :: Decoder (Maybe Event)
decoder0 = Header -> Decoder (Maybe Event)
mkEventDecoder Header
header
go :: t -> Maybe Int -> Decoder (Maybe Event) -> Decoder Event
go !t
remaining !Maybe Int
blockCap Decoder (Maybe Event)
decoder = case Decoder (Maybe Event)
decoder of
G.Done ByteString
leftover ByteOffset
consumed Maybe Event
r -> do
let !decoder' :: Decoder (Maybe Event)
decoder' = Decoder (Maybe Event)
decoder0 Decoder (Maybe Event) -> ByteString -> Decoder (Maybe Event)
forall a. Decoder a -> ByteString -> Decoder a
`G.pushChunk` ByteString
leftover
case Maybe Event
r of
Just Event
event -> case Event -> EventInfo
evSpec Event
event of
EventBlock {Int
BlockSize
Timestamp
block_size :: EventInfo -> BlockSize
cap :: EventInfo -> Int
end_time :: EventInfo -> Timestamp
block_size :: BlockSize
cap :: Int
end_time :: Timestamp
..} ->
t -> Maybe Int -> Decoder (Maybe Event) -> Decoder Event
go (BlockSize -> t
forall a b. (Integral a, Num b) => a -> b
fromIntegral BlockSize
block_size) (Int -> Maybe Int
mkCap Int
cap) Decoder (Maybe Event)
decoder'
EventInfo
_ -> do
let
!remaining' :: t
remaining' = t
remaining t -> t -> t
forall a. Num a => a -> a -> a
- ByteOffset -> t
forall a b. (Integral a, Num b) => a -> b
fromIntegral ByteOffset
consumed
!blockCap' :: Maybe Int
blockCap' = if t
remaining' t -> t -> Bool
forall a. Ord a => a -> a -> Bool
> t
0 then Maybe Int
blockCap else Maybe Int
forall a. Maybe a
Nothing
!event' :: Event
event' = Event
event { evCap :: Maybe Int
evCap = Maybe Int
blockCap }
Event -> Decoder Event -> Decoder Event
forall a. a -> Decoder a -> Decoder a
Produce Event
event' (Decoder Event -> Decoder Event) -> Decoder Event -> Decoder Event
forall a b. (a -> b) -> a -> b
$ t -> Maybe Int -> Decoder (Maybe Event) -> Decoder Event
go t
remaining' Maybe Int
blockCap' Decoder (Maybe Event)
decoder'
Maybe Event
Nothing -> t -> Maybe Int -> Decoder (Maybe Event) -> Decoder Event
go t
remaining Maybe Int
blockCap Decoder (Maybe Event)
decoder'
G.Partial Maybe ByteString -> Decoder (Maybe Event)
k ->
(ByteString -> Decoder Event) -> Decoder Event
forall a. (ByteString -> Decoder a) -> Decoder a
Consume ((ByteString -> Decoder Event) -> Decoder Event)
-> (ByteString -> Decoder Event) -> Decoder Event
forall a b. (a -> b) -> a -> b
$ \ByteString
chunk -> t -> Maybe Int -> Decoder (Maybe Event) -> Decoder Event
go t
remaining Maybe Int
blockCap (Decoder (Maybe Event) -> Decoder Event)
-> Decoder (Maybe Event) -> Decoder Event
forall a b. (a -> b) -> a -> b
$ Maybe ByteString -> Decoder (Maybe Event)
k (Maybe ByteString -> Decoder (Maybe Event))
-> Maybe ByteString -> Decoder (Maybe Event)
forall a b. (a -> b) -> a -> b
$ ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
chunk
G.Fail ByteString
leftover ByteOffset
_ String
err ->
ByteString -> String -> Decoder Event
forall a. ByteString -> String -> Decoder a
Error ByteString
leftover String
err
decodeEventLog :: Decoder Event
decodeEventLog :: Decoder Event
decodeEventLog = (Header -> ByteString -> Decoder Event) -> Decoder Event
forall r. (Header -> ByteString -> Decoder r) -> Decoder r
withHeader ((Header -> ByteString -> Decoder Event) -> Decoder Event)
-> (Header -> ByteString -> Decoder Event) -> Decoder Event
forall a b. (a -> b) -> a -> b
$ \Header
header ByteString
leftover ->
Header -> Decoder Event
decodeEvents Header
header Decoder Event -> ByteString -> Decoder Event
forall a. Decoder a -> ByteString -> Decoder a
`pushChunk` ByteString
leftover
readHeader :: BL.ByteString -> Either String (Header, BL.ByteString)
= Either (Decoder Header) Header
-> ByteString -> Either String (Header, ByteString)
forall b.
Either (Decoder b) b -> ByteString -> Either String (b, ByteString)
go (Either (Decoder Header) Header
-> ByteString -> Either String (Header, ByteString))
-> Either (Decoder Header) Header
-> ByteString
-> Either String (Header, ByteString)
forall a b. (a -> b) -> a -> b
$ Decoder Header -> Either (Decoder Header) Header
forall a b. a -> Either a b
Left Decoder Header
decodeHeader
where
go :: Either (Decoder b) b -> ByteString -> Either String (b, ByteString)
go Either (Decoder b) b
r ByteString
bytes = case Either (Decoder b) b
r of
Left Decoder b
decoder -> case Decoder b
decoder of
Produce b
header Decoder b
decoder' -> case Decoder b
decoder' of
Done ByteString
leftover -> (b, ByteString) -> Either String (b, ByteString)
forall a b. b -> Either a b
Right (b
header, ByteString -> ByteString -> ByteString
BL.Chunk ByteString
leftover ByteString
bytes)
Decoder b
_ -> String -> Either String (b, ByteString)
forall a b. a -> Either a b
Left String
"readHeader: unexpected decoder"
Consume ByteString -> Decoder b
k -> case ByteString
bytes of
ByteString
BL.Empty -> String -> Either String (b, ByteString)
forall a b. a -> Either a b
Left String
"readHeader: not enough bytes"
BL.Chunk ByteString
chunk ByteString
chunks -> Either (Decoder b) b -> ByteString -> Either String (b, ByteString)
go (Decoder b -> Either (Decoder b) b
forall a b. a -> Either a b
Left (Decoder b -> Either (Decoder b) b)
-> Decoder b -> Either (Decoder b) b
forall a b. (a -> b) -> a -> b
$! ByteString -> Decoder b
k ByteString
chunk) ByteString
chunks
Done ByteString
_ -> String -> Either String (b, ByteString)
forall a b. a -> Either a b
Left String
"readHeader: unexpected termination"
Error ByteString
_ String
err -> String -> Either String (b, ByteString)
forall a b. a -> Either a b
Left String
err
Right b
header -> (b, ByteString) -> Either String (b, ByteString)
forall a b. b -> Either a b
Right (b
header, ByteString
bytes)
readEvents :: Header -> BL.ByteString -> ([Event], Maybe String)
readEvents :: Header -> ByteString -> ([Event], Maybe String)
readEvents Header
header = ([Either String Event], [Either String Event])
-> ([Event], Maybe String)
forall a b a b. ([Either a b], [Either a b]) -> ([b], Maybe a)
f (([Either String Event], [Either String Event])
-> ([Event], Maybe String))
-> (ByteString -> ([Either String Event], [Either String Event]))
-> ByteString
-> ([Event], Maybe String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Either String Event -> Bool)
-> [Either String Event]
-> ([Either String Event], [Either String Event])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break Either String Event -> Bool
forall a b. Either a b -> Bool
isLeft ([Either String Event]
-> ([Either String Event], [Either String Event]))
-> (ByteString -> [Either String Event])
-> ByteString
-> ([Either String Event], [Either String Event])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Decoder Event -> ByteString -> [Either String Event]
go (Header -> Decoder Event
decodeEvents Header
header)
where
f :: ([Either a b], [Either a b]) -> ([b], Maybe a)
f ([Either a b]
rs, [Either a b]
ls) = ([Either a b] -> [b]
forall a b. [Either a b] -> [b]
rights [Either a b]
rs, [a] -> Maybe a
forall a. [a] -> Maybe a
listToMaybe ([Either a b] -> [a]
forall a b. [Either a b] -> [a]
lefts [Either a b]
ls))
#if !MIN_VERSION_base(4, 7, 0)
isLeft (Left _) = True
isLeft _ = False
#endif
go :: Decoder Event -> BL.ByteString -> [Either String Event]
go :: Decoder Event -> ByteString -> [Either String Event]
go Decoder Event
decoder ByteString
bytes = case Decoder Event
decoder of
Produce Event
event Decoder Event
decoder' -> Event -> Either String Event
forall a b. b -> Either a b
Right Event
event Either String Event
-> [Either String Event] -> [Either String Event]
forall a. a -> [a] -> [a]
: Decoder Event -> ByteString -> [Either String Event]
go Decoder Event
decoder' ByteString
bytes
Consume ByteString -> Decoder Event
k -> case ByteString
bytes of
ByteString
BL.Empty -> []
BL.Chunk ByteString
chunk ByteString
chunks -> Decoder Event -> ByteString -> [Either String Event]
go (ByteString -> Decoder Event
k ByteString
chunk) ByteString
chunks
Done {} -> []
Error ByteString
_ String
err -> [String -> Either String Event
forall a b. a -> Either a b
Left String
err]
readEventLog :: BL.ByteString -> Either String (EventLog, Maybe String)
readEventLog :: ByteString -> Either String (EventLog, Maybe String)
readEventLog ByteString
bytes = do
(Header
header, ByteString
bytes') <- ByteString -> Either String (Header, ByteString)
readHeader ByteString
bytes
case Header -> ByteString -> ([Event], Maybe String)
readEvents Header
header ByteString
bytes' of
([Event]
events, Maybe String
err) -> (EventLog, Maybe String) -> Either String (EventLog, Maybe String)
forall (m :: * -> *) a. Monad m => a -> m a
return (Header -> Data -> EventLog
EventLog Header
header ([Event] -> Data
Data [Event]
events), Maybe String
err)
mkEventDecoder :: Header -> G.Decoder (Maybe Event)
mkEventDecoder :: Header -> Decoder (Maybe Event)
mkEventDecoder Header
header = Get (Maybe Event) -> Decoder (Maybe Event)
forall a. Get a -> Decoder a
G.runGetIncremental (Get (Maybe Event) -> Decoder (Maybe Event))
-> Get (Maybe Event) -> Decoder (Maybe Event)
forall a b. (a -> b) -> a -> b
$ EventParsers -> Get (Maybe Event)
getEvent EventParsers
parsers
where
imap :: IntMap EventType
imap = [(Int, EventType)] -> IntMap EventType
forall a. [(Int, a)] -> IntMap a
IM.fromList [(EventTypeNum -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (EventType -> EventTypeNum
num EventType
t), EventType
t) | EventType
t <- Header -> [EventType]
eventTypes Header
header]
is_ghc_6 :: Bool
is_ghc_6 = EventTypeNum -> Maybe EventTypeNum
forall a. a -> Maybe a
Just EventTypeNum
sz_old_tid Maybe EventTypeNum -> Maybe EventTypeNum -> Bool
forall a. Eq a => a -> a -> Bool
== do
EventType
create_et <- Int -> IntMap EventType -> Maybe EventType
forall a. Int -> IntMap a -> Maybe a
IM.lookup EVENT_CREATE_THREAD imap
EventType -> Maybe EventTypeNum
size EventType
create_et
is_pre77 :: Bool
is_pre77 = Int -> IntMap EventType -> Bool
forall a. Int -> IntMap a -> Bool
IM.notMember EVENT_USER_MARKER imap
is_ghc782 :: Bool
is_ghc782 = Int -> IntMap EventType -> Bool
forall a. Int -> IntMap a -> Bool
IM.member EVENT_USER_MARKER imap
Bool -> Bool -> Bool
&& Int -> IntMap EventType -> Bool
forall a. Int -> IntMap a -> Bool
IM.notMember EVENT_HACK_BUG_T9003 imap
stopParsers :: [EventParser EventInfo]
stopParsers
| Bool
is_pre77 = [EventParser EventInfo]
pre77StopParsers
| Bool
is_ghc782 = [EventParser EventInfo
ghc782StopParser]
| Bool
otherwise = [EventParser EventInfo
post782StopParser]
event_parsers :: [EventParser EventInfo]
event_parsers
| Bool
is_ghc_6 = [[EventParser EventInfo]] -> [EventParser EventInfo]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
[ [EventParser EventInfo]
standardParsers
, [EventParser EventInfo]
ghc6Parsers
, EventTypeNum -> [EventParser EventInfo]
parRTSParsers EventTypeNum
sz_old_tid
]
| Bool
otherwise = [[EventParser EventInfo]] -> [EventParser EventInfo]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
[ [EventParser EventInfo]
standardParsers
, [EventParser EventInfo]
ghc7Parsers
, [EventParser EventInfo]
stopParsers
, EventTypeNum -> [EventParser EventInfo]
parRTSParsers EventTypeNum
sz_tid
, [EventParser EventInfo]
mercuryParsers
, [EventParser EventInfo]
perfParsers
, [EventParser EventInfo]
heapProfParsers
, [EventParser EventInfo]
timeProfParsers
, [EventParser EventInfo]
binaryEventParsers
, [EventParser EventInfo]
tickyParsers
]
parsers :: EventParsers
parsers = Array Int (Get EventInfo) -> EventParsers
EventParsers (Array Int (Get EventInfo) -> EventParsers)
-> Array Int (Get EventInfo) -> EventParsers
forall a b. (a -> b) -> a -> b
$ IntMap EventType
-> [EventParser EventInfo] -> Array Int (Get EventInfo)
mkEventTypeParsers IntMap EventType
imap [EventParser EventInfo]
event_parsers