content: -- This module supports a duration-based data-type to represent thread
  -- execution and GC information.
  
  module Events.EventDuration (
      EventDuration(..),
      isGCDuration,
      startTimeOf, endTimeOf, durationOf,
      eventsToDurations,
      isDiscreteEvent
    ) where
  
  -- Imports for GHC Events
  import qualified GHC.RTS.Events as GHC
  import GHC.RTS.Events hiding (Event,GCWork,GCIdle)
  
  -------------------------------------------------------------------------------
  -- This datastructure is a duration-based representation of the event
  -- loginformation where thread-runs and GCs are explicitly represented
  -- by a single constructor identifying their start and end points.
  
  data EventDuration
    = ThreadRun {-#UNPACK#-}!ThreadId
                ThreadStopStatus
                {-#UNPACK#-}!Timestamp
                {-#UNPACK#-}!Timestamp
  
    | GCStart {-#UNPACK#-}!Timestamp
              {-#UNPACK#-}!Timestamp
  
    | GCWork  {-#UNPACK#-}!Timestamp
              {-#UNPACK#-}!Timestamp
  
    | GCIdle  {-#UNPACK#-}!Timestamp
              {-#UNPACK#-}!Timestamp
  
    | GCEnd   {-#UNPACK#-}!Timestamp
              {-#UNPACK#-}!Timestamp
    | TXStart {-#UNPACK#-}!Timestamp
              {-#UNPACK#-}!Timestamp
  
    deriving Show
  
  {-
             GCStart     GCWork      GCIdle      GCEnd
    gc start -----> work -----> idle ------+> done -----> gc end
                     |                     |
                     `-------<-------<-----'
  -}
  
  isGCDuration :: EventDuration -> Bool
  isGCDuration GCStart{} = True
  isGCDuration GCWork{}  = True
  isGCDuration GCIdle{}  = True
  isGCDuration GCEnd{}   = True
  isGCDuration _         = False
  
  -------------------------------------------------------------------------------
  -- The start time of an event.
  
  startTimeOf :: EventDuration -> Timestamp
  startTimeOf ed
    = case ed of
        ThreadRun _ _ startTime _ -> startTime
        GCStart startTime _       -> startTime
        GCWork  startTime _       -> startTime
        GCIdle  startTime _       -> startTime
        GCEnd   startTime _       -> startTime
        TXStart startTime _       -> startTime
  
  -------------------------------------------------------------------------------
  -- The emd time of an event.
  
  endTimeOf :: EventDuration -> Timestamp
  endTimeOf ed
    = case ed of
        ThreadRun _ _ _ endTime -> endTime
        GCStart _ endTime       -> endTime
        GCWork  _ endTime       -> endTime
        GCIdle  _ endTime       -> endTime
        GCEnd   _ endTime       -> endTime
        TXStart _ endTime       -> endTime
  
  -------------------------------------------------------------------------------
  -- The duration of an EventDuration
  
  durationOf :: EventDuration -> Timestamp
  durationOf ed = endTimeOf ed - startTimeOf ed
  
  -------------------------------------------------------------------------------
  
  eventsToDurations :: [GHC.Event] -> [EventDuration]
  eventsToDurations [] = []
  eventsToDurations (event : events) =
    case spec event of
       RunThread{thread=t} -> runDuration t : rest
       StopThread{}  -> rest
       StartGC       -> gcStart (time event) events
       EndGC{}       -> rest
  --     StartTX       -> txStart (time event) events
   --    CommitTX      -> rest
       _otherEvent   -> rest
    where
      rest = eventsToDurations events
  
      runDuration t = ThreadRun t s (time event) endTime
         where (endTime, s) = case findRunThreadTime events of
                                Nothing -> (time event, NoStatus)   --   error $ "findRunThreadTime for " ++ (show event)
                                Just x -> x
  
  isDiscreteEvent :: GHC.Event -> Bool
  isDiscreteEvent e =
    case spec e of
      RunThread{}  -> False
      StopThread{} -> False
      StartGC{}    -> False
      EndGC{}      -> False
   --   StartTX{}    -> False
    --  CommitTX{}   -> False
      GHC.GCWork{} -> False
      GHC.GCIdle{} -> False
      GHC.GCDone{} -> False
      GHC.SparkCounters{} -> False
      _            -> True
  
  txStart :: Timestamp -> [GHC.Event] -> [EventDuration]
  txStart _ [] = []
  txStart t0 (event : events) = 
    case spec event of
      GHC.CommitTX{} -> TXStart t0 t1 : eventsToDurations events
      _other         -> gcStart t0 events
    where
        t1 = time event
  
  gcStart :: Timestamp -> [GHC.Event] -> [EventDuration]
  gcStart _  [] = []
  gcStart t0 (event : events) =
    case spec event of
      GHC.GCWork{} -> GCStart t0 t1 : gcWork t1 events
      GHC.GCIdle{} -> GCStart t0 t1 : gcIdle t1 events
      GHC.GCDone{} -> GCStart t0 t1 : gcDone t1 events
      GHC.EndGC{}  -> GCStart t0 t1 : eventsToDurations events
      RunThread{}  -> GCStart t0 t1 : eventsToDurations (event : events)
      _other       -> gcStart t0 events
   where
          t1 = time event
  
  gcWork :: Timestamp -> [GHC.Event] -> [EventDuration]
  gcWork _  [] = []
  gcWork t0 (event : events) =
    case spec event of
      GHC.GCWork{} -> gcWork t0 events
      GHC.GCIdle{} -> GCWork t0 t1 : gcIdle t1 events
      GHC.GCDone{} -> GCWork t0 t1 : gcDone t1 events
      GHC.EndGC{}  -> GCWork t0 t1 : eventsToDurations events
      RunThread{}  -> GCWork t0 t1 : eventsToDurations (event : events)
      _other       -> gcStart t0 events
   where
          t1 = time event
  
  gcIdle :: Timestamp -> [GHC.Event] -> [EventDuration]
  gcIdle _  [] = []
  gcIdle t0 (event : events) =
    case spec event of
      GHC.GCIdle{} -> gcIdle t0 events
      GHC.GCWork{} -> GCIdle t0 t1 : gcWork t1 events
      GHC.GCDone{} -> GCIdle t0 t1 : gcDone t1 events
      GHC.EndGC{}  -> GCIdle t0 t1 : eventsToDurations events
      RunThread{}  -> GCIdle t0 t1 : eventsToDurations (event : events)
      _other       -> gcStart t0 events
   where
          t1 = time event
  
  gcDone :: Timestamp -> [GHC.Event] -> [EventDuration]
  gcDone _  [] = []
  gcDone t0 (event : events) =
    case spec event of
      GHC.GCDone{} -> gcDone t0 events
      GHC.GCWork{} -> GCEnd t0 t1 : gcWork t1 events
      GHC.GCIdle{} -> GCEnd t0 t1 : gcIdle t1 events
      GHC.EndGC{}  -> GCEnd t0 t1 : eventsToDurations events
      RunThread{}  -> GCEnd t0 t1 : eventsToDurations (event : events)
      _other       -> gcStart t0 events
   where
          t1 = time event
  
  -------------------------------------------------------------------------------
  
  findRunThreadTime :: [GHC.Event] -> Maybe (Timestamp, ThreadStopStatus)
  findRunThreadTime [] = Nothing
  findRunThreadTime (e : es)
    = case spec e of
        StopThread{status=s} -> Just (time e, s)
        _                    -> findRunThreadTime es
  
  -------------------------------------------------------------------------------
  