Skip to content

Commit 235a99c

Browse files
committed
locli & workbench: run summary collection
1 parent 9997739 commit 235a99c

File tree

6 files changed

+113
-19
lines changed

6 files changed

+113
-19
lines changed

bench/locli/src/Cardano/Analysis/API.hs

+14
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,20 @@ import Cardano.Util
3636
-- * API types
3737
--
3838

39+
-- | Overall summary of all analyses.
40+
data Summary where
41+
Summary ::
42+
{ sumWhen :: !UTCTime
43+
, sumLogStreams :: !(Count [LogObject])
44+
, sumLogObjects :: !(Count LogObject)
45+
, sumFilters :: !([FilterName], [ChainFilter])
46+
, sumChainRejectionStats :: ![(ChainFilter, Int)]
47+
, sumBlocksRejected :: !(Count BlockEvents)
48+
, sumDomainSlots :: !(DataDomain SlotNo)
49+
, sumDomainBlocks :: !(DataDomain BlockNo)
50+
} -> Summary
51+
deriving (Generic, FromJSON, ToJSON, Show)
52+
3953
-- | Results of block propagation analysis.
4054
data BlockProp f
4155
= BlockProp

bench/locli/src/Cardano/Analysis/BlockProp.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ rebuildChain run@Run{genesis} flts fltNames xs@(fmap snd -> machViews) = do
411411
& handleMiss "Δt Adopted (forger)"
412412
, bfChainDelta = bfeChainDelta
413413
}
414-
, beForks = unsafeCoerceCount $ mkCount otherBlocks
414+
, beForks = unsafeCoerceCount $ countOfList otherBlocks
415415
, beObservations =
416416
catMaybes $
417417
os <&> \ObserverEvents{..}->

bench/locli/src/Cardano/Analysis/ChainFilter.hs

+4-3
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@ newtype JsonFilterFile
2525
deriving (Show, Eq)
2626

2727
newtype FilterName = FilterName { unFilterName :: Text }
28+
deriving (Eq, FromJSON, Generic, NFData, Show, ToJSON)
2829

2930
-- | Conditions for chain subsetting
3031
data ChainFilter
3132
= CBlock BlockCond
3233
| CSlot SlotCond
33-
deriving (FromJSON, Generic, NFData, Show, ToJSON)
34+
deriving (Eq, FromJSON, Generic, NFData, Ord, Show, ToJSON)
3435

3536
-- | Block classification -- primary for validity as subjects of analysis.
3637
data BlockCond
@@ -42,7 +43,7 @@ data BlockCond
4243
| BSizeLEq Word64
4344
| BMinimumAdoptions Word64 -- ^ At least this many adoptions
4445
| BNonNegatives -- ^ Non-negative timings only
45-
deriving (FromJSON, Generic, NFData, Show, ToJSON)
46+
deriving (Eq, FromJSON, Generic, NFData, Ord, Show, ToJSON)
4647

4748
data SlotCond
4849
= SlotGEq SlotNo
@@ -54,7 +55,7 @@ data SlotCond
5455
| EpSlotGEq EpochSlot
5556
| EpSlotLEq EpochSlot
5657
| SlotHasLeaders
57-
deriving (FromJSON, Generic, NFData, Show, ToJSON)
58+
deriving (Eq, FromJSON, Generic, NFData, Ord, Show, ToJSON)
5859

5960
cfIsSlotCond, cfIsBlockCond :: ChainFilter -> Bool
6061
cfIsSlotCond = \case { CSlot{} -> True; _ -> False; }

bench/locli/src/Cardano/Analysis/Ground.hs

+6-3
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,14 @@ instance FromJSONKey Hash where
5555

5656
newtype Count a = Count { unCount :: Int }
5757
deriving (Eq, Generic, Ord, Show)
58-
deriving newtype (FromJSON, ToJSON)
58+
deriving newtype (FromJSON, Num, ToJSON)
5959
deriving anyclass NFData
6060

61-
mkCount :: [a] -> Count a
62-
mkCount = Count . fromIntegral . length
61+
countOfList :: [a] -> Count a
62+
countOfList = Count . fromIntegral . length
63+
64+
countOfLists :: [[a]] -> Count a
65+
countOfLists = Count . fromIntegral . sum . fmap length
6366

6467
unsafeCoerceCount :: Count a -> Count b
6568
unsafeCoerceCount = Unsafe.unsafeCoerce

bench/locli/src/Cardano/Analysis/Run.hs

+4-4
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ import Cardano.Util
2626
data Anchor
2727
= Anchor
2828
{ aRuns :: [Text]
29-
, aFilters :: [FilterName]
29+
, aFilters :: ([FilterName], [ChainFilter])
3030
, aSlots :: Maybe (DataDomain SlotNo)
3131
, aBlocks :: Maybe (DataDomain BlockNo)
3232
, aVersion :: Cardano.Analysis.Version.Version
3333
, aWhen :: UTCTime
3434
}
3535

36-
runAnchor :: Run -> UTCTime -> [FilterName] -> Maybe (DataDomain SlotNo) -> Maybe (DataDomain BlockNo) -> Anchor
36+
runAnchor :: Run -> UTCTime -> ([FilterName], [ChainFilter]) -> Maybe (DataDomain SlotNo) -> Maybe (DataDomain BlockNo) -> Anchor
3737
runAnchor Run{..} = tagsAnchor [tag metadata]
3838

39-
tagsAnchor :: [Text] -> UTCTime -> [FilterName] -> Maybe (DataDomain SlotNo) -> Maybe (DataDomain BlockNo) -> Anchor
39+
tagsAnchor :: [Text] -> UTCTime -> ([FilterName], [ChainFilter]) -> Maybe (DataDomain SlotNo) -> Maybe (DataDomain BlockNo) -> Anchor
4040
tagsAnchor aRuns aWhen aFilters aSlots aBlocks =
4141
Anchor { aVersion = getVersion, .. }
4242

@@ -52,7 +52,7 @@ renderAnchorRuns Anchor{..} = mconcat
5252

5353
renderAnchorFiltersAndDomains :: Anchor -> Text
5454
renderAnchorFiltersAndDomains a@Anchor{..} = mconcat
55-
[ "filters: ", case aFilters of
55+
[ "filters: ", case fst aFilters of
5656
[] -> "unfiltered"
5757
xs -> T.intercalate ", " (unFilterName <$> xs)
5858
, renderAnchorDomains a]

bench/locli/src/Cardano/Command.hs

+84-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
{-# OPTIONS_GHC -fmax-pmcheck-models=15000 #-}
1+
{-# OPTIONS_GHC -fmax-pmcheck-models=25000 #-}
22
module Cardano.Command (module Cardano.Command) where
33

44
import Cardano.Prelude hiding (State, head)
55

66
import Data.Aeson qualified as Aeson
77
import Data.ByteString qualified as BS
88
import Data.ByteString.Lazy.Char8 qualified as LBS
9+
import Data.Map.Strict qualified as Map
910
import Data.Text (pack)
1011
import Data.Text qualified as T
1112
import Data.Text.Short (toText)
@@ -69,7 +70,6 @@ data ChainCommand
6970
| ComputePropagation
7071
| RenderPropagation RenderFormat TextOutputFile PropSubset
7172
| ReadPropagations [JsonInputFile BlockPropOne]
72-
7373
| ComputeMultiPropagation
7474
| RenderMultiPropagation RenderFormat TextOutputFile PropSubset CDF2Aspect
7575

@@ -79,10 +79,13 @@ data ChainCommand
7979
| ComputeClusterPerf
8080
| RenderClusterPerf RenderFormat TextOutputFile PerfSubset
8181
| ReadClusterPerfs [JsonInputFile MultiClusterPerf]
82-
8382
| ComputeMultiClusterPerf
8483
| RenderMultiClusterPerf RenderFormat TextOutputFile PerfSubset CDF2Aspect
8584

85+
| ComputeSummary
86+
| RenderSummary RenderFormat TextOutputFile
87+
| ReadSummaries [JsonInputFile Summary]
88+
8689
| Compare InputDir (Maybe TextInputFile) TextOutputFile
8790
[( JsonInputFile RunPartial
8891
, JsonInputFile Genesis
@@ -212,7 +215,20 @@ parseChainCommand =
212215
(writerOpts RenderMultiClusterPerf "Render"
213216
<*> parsePerfSubset
214217
<*> parseCDF2Aspect)
218+
]) <|>
219+
220+
subparser (mconcat [ commandGroup "Analysis summary"
221+
, op "compute-summary" "Compute run analysis summary"
222+
(ComputeSummary & pure)
223+
, op "render-summary" "Render run analysis summary"
224+
(writerOpts RenderSummary "Render")
225+
, op "read-summaries" "Read analysis summaries"
226+
(ReadSummaries
227+
<$> some
228+
(optJsonInputFile "summary" "JSON block propagation input file"))
229+
]) <|>
215230

231+
subparser (mconcat [ commandGroup "Run comparison"
216232
, op "compare" "Generate a report comparing multiple runs"
217233
(Compare
218234
<$> optInputDir "ede" "Directory with EDE templates."
@@ -289,7 +305,7 @@ data State
289305
= State
290306
{ -- common
291307
sWhen :: UTCTime
292-
, sFilters :: [FilterName]
308+
, sFilters :: ([FilterName], [ChainFilter])
293309
, sTags :: [Text]
294310
, sRun :: Maybe Run
295311
, sObjLists :: Maybe [(JsonLogfile, [LogObject])]
@@ -308,8 +324,46 @@ data State
308324
, sMachPerf :: Maybe [(JsonLogfile, MachPerfOne)]
309325
, sClusterPerf :: Maybe [ClusterPerf]
310326
, sMultiClusterPerf :: Maybe MultiClusterPerf
327+
--
328+
, sSummaries :: Maybe [Summary]
311329
}
312330

331+
computeSummary :: State -> Summary
332+
computeSummary =
333+
\case
334+
State{sRun = Nothing} -> err "a run"
335+
State{sObjLists = Nothing} -> err "logobjects"
336+
State{sObjLists = Just []} -> err "logobjects"
337+
State{sClusterPerf = Nothing} -> err "cluster performance results"
338+
State{sBlockProp = Nothing} -> err "block propagation results"
339+
State{sChainRejecta = Nothing} -> err "chain rejects"
340+
State{sDomSlots = Nothing} -> err "a slot domain"
341+
State{sDomBlocks = Nothing} -> err "a block domain"
342+
State{ sObjLists = Just (fmap snd -> objLists)
343+
-- , sClusterPerf = Just clusterPerf
344+
-- , sBlockProp = Just blockProp
345+
, sChainRejecta = Just chainRejecta
346+
, sDomSlots = Just sumDomainSlots
347+
, sDomBlocks = Just sumDomainBlocks
348+
, ..} ->
349+
Summary
350+
{ sumWhen = sWhen
351+
, sumFilters = sFilters
352+
, sumLogStreams = countOfList objLists
353+
, sumLogObjects = countOfLists objLists
354+
, sumBlocksRejected = countOfList chainRejecta
355+
, ..
356+
}
357+
where
358+
sumChainRejectionStats =
359+
chainRejecta
360+
<&> fmap fst . filter (not . snd) . beAcceptance
361+
& concat
362+
& foldr' (\k m -> Map.insertWith (+) k 1 m) Map.empty
363+
& Map.toList
364+
where
365+
err = error . ("Summary of a run requires " <>)
366+
313367
sRunAnchor :: State -> Anchor
314368
sRunAnchor State{sRun = Just run, sFilters, sWhen, sDomSlots, sDomBlocks}
315369
= runAnchor run sWhen sFilters sDomSlots sDomBlocks
@@ -391,7 +445,7 @@ runChainCommand s@State{sRun=Just run, sMachViews=Just mvs}
391445
, sChainRejecta = Just chainRejecta
392446
, sDomSlots = Just domSlot
393447
, sDomBlocks = Just domBlock
394-
, sFilters = fltNames
448+
, sFilters = (fltNames, flts)
395449
}
396450
-- pure s { sChain = Just chain }
397451
runChainCommand _ c@RebuildChain{} = missingCommandData c
@@ -467,7 +521,7 @@ runChainCommand s@State{sRun=Just run, sSlotsRaw=Just slotsRaw}
467521
[ "All ", show $ maximum (length . snd <$> slotsRaw), " slots filtered out." ]
468522
pure s { sSlots = Just fltrd
469523
, sDomSlots = Just domSlots
470-
, sFilters = fltNames
524+
, sFilters = (fltNames, flts)
471525
}
472526
runChainCommand _ c@FilterSlots{} = missingCommandData c
473527
["run metadata & genesis", "unfiltered slot stats"]
@@ -612,6 +666,28 @@ runChainCommand s@State{sMultiClusterPerf=Just (MultiClusterPerf perf)}
612666
runChainCommand _ c@RenderMultiClusterPerf{} = missingCommandData c
613667
["multi-run cluster preformance stats"]
614668

669+
runChainCommand s ComputeSummary = do
670+
progress "summary" (Q "summarising a run")
671+
pure s { sSummaries = Just [computeSummary s] }
672+
673+
runChainCommand s@State{sSummaries = Just (_summary:_)} c@(RenderSummary fmt f) = do
674+
progress "summary" (Q $ printf "rendering summary")
675+
dumpText "summary" body (modeFilename f "" fmt)
676+
& firstExceptT (CommandError c)
677+
pure s
678+
where body = [""] -- renderSummary summary
679+
runChainCommand _ c@RenderSummary{} = missingCommandData c
680+
["run summary"]
681+
682+
runChainCommand s@State{}
683+
c@(ReadSummaries fs) = do
684+
progress "summaries" (Q $ printf "reading %d run summaries" $ length fs)
685+
xs <- mapConcurrently (fmap (Aeson.eitherDecode @Summary) . LBS.readFile . unJsonInputFile) fs
686+
& fmap sequence
687+
& newExceptT
688+
& firstExceptT (CommandError c . show)
689+
pure s { sSummaries = Just xs }
690+
615691
runChainCommand s c@(Compare ede mTmpl outf@(TextOutputFile outfp) runs) = do
616692
progress "report" (Q $ printf "rendering report for %d runs" $ length runs)
617693
xs :: [(ClusterPerf, BlockPropOne, Run)] <- forM runs $
@@ -666,11 +742,11 @@ runCommand (ChainCommand cs) = do
666742
where
667743
initialState :: UTCTime -> State
668744
initialState now =
669-
State now [] []
745+
State now ([], []) []
746+
Nothing Nothing Nothing Nothing
670747
Nothing Nothing Nothing Nothing
671748
Nothing Nothing Nothing Nothing
672749
Nothing Nothing Nothing Nothing
673-
Nothing Nothing Nothing
674750

675751
opts :: ParserInfo Command
676752
opts =

0 commit comments

Comments
 (0)