{-# LANGUAGE DeriveGeneric #-}

module Cardano.Tools.DBAnalyser.Analysis.BenchmarkLedgerOps.SlotDataPoint
  ( BlockStats (BlockStats, unBlockStats)
  , SlotDataPoint (..)
  ) where

import Cardano.Slotting.Slot (SlotNo)
import Data.Aeson as Aeson
import qualified Data.Aeson.Encoding as Aeson.Encoding
import Data.Int (Int64)
import Data.Word (Word32, Word64)
import GHC.Generics (Generic)
import TextBuilder (TextBuilder)
import qualified TextBuilder as Builder

-- | Information about the time spent processing the block corresponding to
-- 'slot', divided into the five major operations:
--
--  0. Forecast.
--  1. Header tick.
--  2. Header application.
--  3. Block tick.
--  4. Block application.
--
-- Before those five operations run, the node reads the ledger tables
-- that the block needs (e.g. the on-disk backend's UTxO-table, if the
-- on-disk backend is used). This is the tables read. 'totalTime',
-- 'mut', 'gc', 'majGcCount', 'minGcCount' and 'allocatedBytes' cover
-- the tables read and the five operations together. 'tableReadTime'
-- and 'mut_tableRead' report the costs of table read on its own.
--
-- It is up to the user of a slot data point to decide which units the data
-- represent (eg milliseconds, nanoseconds, etc)
data SlotDataPoint
  = SlotDataPoint
  { SlotDataPoint -> SlotNo
slot :: !SlotNo
  -- ^ Slot in which the 5 ledger operations were applied.
  , SlotDataPoint -> Word64
slotGap :: !Word64
  -- ^ Gap to the previous slot.
  , SlotDataPoint -> Int64
totalTime :: !Int64
  -- ^ Elapsed time spent on the tables read and the 5 ledger
  -- operations at 'slot'. Taken from GC.elapsed_ns.
  , SlotDataPoint -> Int64
mut :: !Int64
  -- ^ Time the mutator ran during the tables read and the 5 ledger
  -- operations at 'slot'. Taken from GC.mutator_elapsed_ns.
  , SlotDataPoint -> Int64
gc :: !Int64
  -- ^ Time spent in garbage collection during the tables read and the
  -- 5 ledger operations at 'slot'. Taken from GC.gc_elapsed_ns.
  , SlotDataPoint -> Int64
tableReadTime :: !Int64
  -- ^ Elapsed time spent on the tables read. 'totalTime' already
  -- counts this time. To get the time the 5 operations took on their
  -- own, subtract this from 'totalTime'.
  , SlotDataPoint -> Int64
mut_tableRead :: !Int64
  -- ^ Time the mutator ran during the tables read. Taken from
  -- GC.mutator_elapsed_ns, which is elapsed time minus GC time.
  -- 'tableReadTime' minus this value is the GC time inside the table
  -- read.
  , SlotDataPoint -> Word32
majGcCount :: !Word32
  -- ^ Total number of __major__ garbage collections that took place
  -- during the tables read and the 5 ledger operations at 'slot'.
  , SlotDataPoint -> Word32
minGcCount :: !Word32
  -- ^ Total number of __minor__ garbage collections that took place
  -- during the tables read and the 5 ledger operations at 'slot'.
  , SlotDataPoint -> Word64
allocatedBytes :: !Word64
  -- ^ Allocated bytes during the tables read and the 5 ledger
  -- operations at 'slot'.
  , SlotDataPoint -> Int64
mut_forecast :: !Int64
  -- ^ Difference of the GC.mutator_elapsed_ns field when computing the
  -- forecast.
  , SlotDataPoint -> Int64
mut_headerTick :: !Int64
  , SlotDataPoint -> Int64
mut_headerApply :: !Int64
  , SlotDataPoint -> Int64
mut_blockTick :: !Int64
  , SlotDataPoint -> Int64
mut_blockApply :: !Int64
  , SlotDataPoint -> Word32
blockByteSize :: !Word32
  , SlotDataPoint -> BlockStats
blockStats :: !BlockStats
  -- ^ Free-form information about the block.
  }
  deriving ((forall x. SlotDataPoint -> Rep SlotDataPoint x)
-> (forall x. Rep SlotDataPoint x -> SlotDataPoint)
-> Generic SlotDataPoint
forall x. Rep SlotDataPoint x -> SlotDataPoint
forall x. SlotDataPoint -> Rep SlotDataPoint x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. SlotDataPoint -> Rep SlotDataPoint x
from :: forall x. SlotDataPoint -> Rep SlotDataPoint x
$cto :: forall x. Rep SlotDataPoint x -> SlotDataPoint
to :: forall x. Rep SlotDataPoint x -> SlotDataPoint
Generic, Int -> SlotDataPoint -> ShowS
[SlotDataPoint] -> ShowS
SlotDataPoint -> String
(Int -> SlotDataPoint -> ShowS)
-> (SlotDataPoint -> String)
-> ([SlotDataPoint] -> ShowS)
-> Show SlotDataPoint
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SlotDataPoint -> ShowS
showsPrec :: Int -> SlotDataPoint -> ShowS
$cshow :: SlotDataPoint -> String
show :: SlotDataPoint -> String
$cshowList :: [SlotDataPoint] -> ShowS
showList :: [SlotDataPoint] -> ShowS
Show)

newtype BlockStats = BlockStats {BlockStats -> [TextBuilder]
unBlockStats :: [TextBuilder]}
  deriving ((forall x. BlockStats -> Rep BlockStats x)
-> (forall x. Rep BlockStats x -> BlockStats) -> Generic BlockStats
forall x. Rep BlockStats x -> BlockStats
forall x. BlockStats -> Rep BlockStats x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. BlockStats -> Rep BlockStats x
from :: forall x. BlockStats -> Rep BlockStats x
$cto :: forall x. Rep BlockStats x -> BlockStats
to :: forall x. Rep BlockStats x -> BlockStats
Generic, Int -> BlockStats -> ShowS
[BlockStats] -> ShowS
BlockStats -> String
(Int -> BlockStats -> ShowS)
-> (BlockStats -> String)
-> ([BlockStats] -> ShowS)
-> Show BlockStats
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BlockStats -> ShowS
showsPrec :: Int -> BlockStats -> ShowS
$cshow :: BlockStats -> String
show :: BlockStats -> String
$cshowList :: [BlockStats] -> ShowS
showList :: [BlockStats] -> ShowS
Show)

instance ToJSON BlockStats where
  -- We convert the blocks stats to a 'Vector Text'.
  toJSON :: BlockStats -> Value
toJSON = [Text] -> Value
forall a. ToJSON a => a -> Value
toJSON ([Text] -> Value) -> (BlockStats -> [Text]) -> BlockStats -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (TextBuilder -> Text) -> [TextBuilder] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap TextBuilder -> Text
Builder.toText ([TextBuilder] -> [Text])
-> (BlockStats -> [TextBuilder]) -> BlockStats -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BlockStats -> [TextBuilder]
unBlockStats

  toEncoding :: BlockStats -> Encoding
toEncoding = (TextBuilder -> Encoding) -> [TextBuilder] -> Encoding
forall a. (a -> Encoding) -> [a] -> Encoding
Aeson.Encoding.list (Text -> Encoding
forall a. Text -> Encoding' a
Aeson.Encoding.text (Text -> Encoding)
-> (TextBuilder -> Text) -> TextBuilder -> Encoding
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TextBuilder -> Text
Builder.toText) ([TextBuilder] -> Encoding)
-> (BlockStats -> [TextBuilder]) -> BlockStats -> Encoding
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BlockStats -> [TextBuilder]
unBlockStats

instance ToJSON SlotDataPoint where
  toEncoding :: SlotDataPoint -> Encoding
toEncoding = Options -> SlotDataPoint -> Encoding
forall a.
(Generic a, GToJSON' Encoding Zero (Rep a)) =>
Options -> a -> Encoding
Aeson.genericToEncoding Options
Aeson.defaultOptions