Skip to content

Commit 266080e

Browse files
committedJan 30, 2025·
simulation: output diffusion data from short-leios sim
1 parent f726b6f commit 266080e

File tree

9 files changed

+342
-33
lines changed

9 files changed

+342
-33
lines changed
 

‎simulation/ouroboros-leios-sim.cabal

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ library
4545
ChanDriver
4646
ChanMux
4747
ChanTCP
48+
Diffusion
4849
ExamplesLayout
4950
ExamplesRelay
5051
ExamplesRelayP2P

‎simulation/src/Diffusion.hs

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
{-# LANGUAGE BangPatterns #-}
2+
{-# LANGUAGE DeriveAnyClass #-}
3+
{-# LANGUAGE DeriveGeneric #-}
4+
{-# LANGUAGE DuplicateRecordFields #-}
5+
{-# LANGUAGE FlexibleContexts #-}
6+
{-# LANGUAGE GADTs #-}
7+
{-# LANGUAGE NamedFieldPuns #-}
8+
{-# LANGUAGE RecordWildCards #-}
9+
{-# LANGUAGE ScopedTypeVariables #-}
10+
{-# LANGUAGE TupleSections #-}
11+
{-# LANGUAGE TypeApplications #-}
12+
{-# LANGUAGE NoFieldSelectors #-}
13+
14+
module Diffusion
15+
where
16+
17+
import Control.Monad
18+
import Data.Aeson
19+
import Data.Bifunctor
20+
import Data.IntMap (IntMap)
21+
import qualified Data.IntMap as IMap
22+
import qualified Data.List as List
23+
import Data.Map (Map)
24+
import qualified Data.Map.Strict as Map
25+
import Data.Maybe (fromMaybe, listToMaybe)
26+
import Data.Traversable
27+
import GHC.Generics
28+
import LeiosProtocol.Common hiding (Point)
29+
import qualified PraosProtocol.Common.Chain as Chain
30+
import PraosProtocol.ExamplesPraosP2P ()
31+
import SimTypes
32+
33+
data DiffusionEntry id = DiffusionEntry
34+
{ block_id :: !id
35+
, node_id :: !Int
36+
, created :: !DiffTime
37+
, adoptions :: ![(NodeId, DiffTime)]
38+
}
39+
deriving (Generic, ToJSON, FromJSON)
40+
41+
data DiffusionData id = DiffusionData
42+
{ entries :: ![DiffusionEntry id]
43+
, latency_per_stake :: ![LatencyPerStake id]
44+
-- ^ adoption latency, counted from slot start.
45+
, average_latencies :: !(Map.Map Double DiffTime)
46+
-- ^ map from stake fraction to average adoption latency
47+
}
48+
deriving (Generic, ToJSON, FromJSON)
49+
50+
data LatencyPerStake id = LatencyPerStake
51+
{ block_id :: !id
52+
, latencies :: ![(Maybe DiffTime, Double)]
53+
}
54+
deriving (Generic, ToJSON, FromJSON)
55+
56+
diffusionEntryToLatencyPerStake :: Map NodeId StakeFraction -> DiffusionEntry id -> LatencyPerStake id
57+
diffusionEntryToLatencyPerStake stakes DiffusionEntry{..} =
58+
LatencyPerStake
59+
{ block_id
60+
, latencies = bin $ diffusionLatencyPerStakeFraction stakes slotStart adoptions
61+
}
62+
where
63+
slotStart = fromIntegral @Integer $ floor created
64+
bins = [0.50, 0.8, 0.9, 0.92, 0.94, 0.96, 0.98, 1]
65+
bin xs = map (\b -> (,b) $ fst <$> listToMaybe (dropWhile (\(_, x) -> x < b) xs)) bins
66+
67+
diffusionLatencyPerStakeFraction ::
68+
Map NodeId StakeFraction ->
69+
DiffTime ->
70+
[(NodeId, DiffTime)] ->
71+
[(DiffTime, Double)]
72+
diffusionLatencyPerStakeFraction stakes t0 =
73+
snd
74+
. mapAccumL h 0
75+
. map (first (stakes Map.!))
76+
. reverse
77+
where
78+
h s (StakeFraction ns, t) =
79+
let
80+
!s' = s + ns
81+
!latency = t - t0
82+
in
83+
(s', (latency, s'))
84+
85+
stableChainHashes :: HasHeader a => IntMap (Chain a) -> [HeaderHash a]
86+
stableChainHashes chains =
87+
let stable_chain = fromMaybe Genesis $ do
88+
guard $ not $ IMap.null chains
89+
pure $ List.foldl1' aux (IMap.elems chains)
90+
aux c1 c2 = fromMaybe Genesis $ do
91+
p <- Chain.intersectChains c1 c2
92+
Chain.rollback p c1
93+
in map blockHash $ Chain.toNewestFirst stable_chain
94+
95+
diffusionDataFromMap ::
96+
Map NodeId StakeFraction ->
97+
Map id (msg, NodeId, Time, [(NodeId, Time)]) ->
98+
DiffusionData id
99+
diffusionDataFromMap stakes arrivals = DiffusionData{..}
100+
where
101+
entries =
102+
[ DiffusionEntry{..}
103+
| (block_id, (_, NodeId node_id, Time created, ts)) <- Map.toList arrivals
104+
, let adoptions = map (second (\(Time t) -> t)) ts
105+
]
106+
latency_per_stake = map (diffusionEntryToLatencyPerStake stakes) entries
107+
avg ts = sum ts / fromIntegral (length ts)
108+
average_latencies =
109+
Map.map avg $
110+
Map.fromListWith
111+
(++)
112+
[ (p, [d])
113+
| l <- latency_per_stake
114+
, (Just d, p) <- l.latencies
115+
]

‎simulation/src/LeiosProtocol/Common.hs

+29
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,19 @@ where
4242
import ChanTCP
4343
import Control.Exception (assert)
4444
import Control.Monad (guard)
45+
import Data.Aeson
46+
import Data.Aeson.Types (Parser, unexpected)
4547
import Data.Coerce
4648
import Data.Hashable
4749
import Data.Map (Map)
50+
import qualified Data.Text as T
4851
import Data.Word (Word64, Word8)
4952
import GHC.Generics
5053
import GHC.Records
5154
import PraosProtocol.Common
5255
import SimTypes
5356
import TaskMultiQueue
57+
import Text.Read (readMaybe)
5458

5559
{-
5660
Note [size of blocks/messages]: we add a `size` field to most
@@ -233,6 +237,11 @@ instance MessageSize VoteMsg where
233237
mkStringId :: (HasField "node" a NodeId, HasField "num" a Int) => a -> String
234238
mkStringId x = concat [show (coerce @_ @Int x.node), "-", show x.num]
235239

240+
readStringId :: String -> Maybe (NodeId, Int)
241+
readStringId s = do
242+
(node_s, '-' : i_s) <- pure $ break (== '-') s
243+
(,) <$> (NodeId <$> readMaybe node_s) <*> readMaybe i_s
244+
236245
instance HasField "stringId" InputBlockHeader String where
237246
getField = mkStringId . (.id)
238247

@@ -247,3 +256,23 @@ instance HasField "stringId" VoteMsg String where
247256

248257
instance HasField "stringId" EndorseBlock String where
249258
getField = mkStringId . (.id)
259+
260+
instance ToJSON InputBlockId where
261+
toJSON = toJSON . mkStringId
262+
263+
instance FromJSON InputBlockId where
264+
parseJSON = parseStringId InputBlockId
265+
266+
instance ToJSON EndorseBlockId where
267+
toJSON = toJSON . mkStringId
268+
instance FromJSON EndorseBlockId where
269+
parseJSON = parseStringId EndorseBlockId
270+
271+
instance ToJSON VoteId where
272+
toJSON = toJSON . mkStringId
273+
instance FromJSON VoteId where
274+
parseJSON = parseStringId VoteId
275+
276+
parseStringId :: (NodeId -> Int -> a) -> Value -> Parser a
277+
parseStringId c (String s) = maybe (fail "string id not readable") (pure . uncurry c) $ readStringId (T.unpack s)
278+
parseStringId c v = unexpected v

‎simulation/src/LeiosProtocol/Short/Sim.hs

+6
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ data LeiosEvent
5151
LeiosEventSetup
5252
!World
5353
!(Map NodeId Point) -- nodes and locations
54+
!(Map NodeId StakeFraction)
5455
!(Set (NodeId, NodeId)) -- links between nodes
5556
| -- | An event at a node
5657
LeiosEventNode (LabelNode LeiosNodeEvent)
@@ -183,6 +184,11 @@ traceRelayLink1 tcpprops =
183184
, (nodeB, Point 450 100)
184185
]
185186
)
187+
( Map.fromList
188+
[ (nodeA, StakeFraction 0.5)
189+
, (nodeB, StakeFraction 0.5)
190+
]
191+
)
186192
( Set.fromList
187193
[(nodeA, nodeB), (nodeB, nodeA)]
188194
)

‎simulation/src/LeiosProtocol/Short/SimP2P.hs

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ traceLeiosP2P
3939
rng0
4040
P2PNetwork
4141
{ p2pNodes
42+
, p2pNodeStakes
4243
, p2pLinks
4344
, p2pWorld
4445
}
@@ -51,6 +52,7 @@ traceLeiosP2P
5152
LeiosEventSetup
5253
p2pWorld
5354
p2pNodes
55+
p2pNodeStakes
5456
(Map.keysSet p2pLinks)
5557
tcplinks <-
5658
sequence

‎simulation/src/LeiosProtocol/Short/VizSim.hs

+10-7
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ data LeiosSimVizState
9898
= LeiosSimVizState
9999
{ vizWorld :: !World
100100
, vizNodePos :: !(Map NodeId Point)
101+
, vizNodeStakes :: !(Map NodeId StakeFraction)
101102
, vizNodeLinks :: !(Map (NodeId, NodeId) LinkPoints)
102103
, vizMsgsInTransit ::
103104
!( Map
@@ -205,7 +206,7 @@ accumChains _ (LeiosEventNode (LabelNode nid (PraosNodeEvent (PraosNodeEventNewT
205206
accumChains _ _ = id
206207

207208
type DiffusionLatencyMap = DiffusionLatencyMap' (HeaderHash RankingBlockHeader) RankingBlockHeader
208-
type DiffusionLatencyMap' id msg = Map id (msg, NodeId, Time, [Time])
209+
type DiffusionLatencyMap' id msg = Map id (msg, NodeId, Time, [(NodeId, Time)])
209210

210211
accumDiffusionLatency :: Time -> LeiosEvent -> DiffusionLatencyMap -> DiffusionLatencyMap
211212
accumDiffusionLatency now (LeiosEventNode (LabelNode n (PraosNodeEvent e))) =
@@ -230,12 +231,12 @@ accumDiffusionLatency' now nid Generate msgid msg vs =
230231
assert (not (msgid `Map.member` vs)) $
231232
Map.insert
232233
msgid
233-
(msg, nid, now, [now])
234+
(msg, nid, now, [(nid, now)])
234235
vs
235-
accumDiffusionLatency' now _nid EnterState msgid _msg vs =
236+
accumDiffusionLatency' now nid EnterState msgid _msg vs =
236237
Map.adjust
237238
( \(hdr, nid', created, arrivals) ->
238-
(hdr, nid', created, now : arrivals)
239+
(hdr, nid', created, (nid, now) : arrivals)
239240
)
240241
msgid
241242
vs
@@ -264,6 +265,7 @@ leiosSimVizModel LeiosModelConfig{recentSpan} =
264265
LeiosSimVizState
265266
{ vizWorld = World (0, 0) Rectangle
266267
, vizNodePos = Map.empty
268+
, vizNodeStakes = Map.empty
267269
, vizNodeLinks = Map.empty
268270
, vizMsgsInTransit = Map.empty
269271
, vizNodeTip = Map.empty
@@ -291,10 +293,11 @@ leiosSimVizModel LeiosModelConfig{recentSpan} =
291293
LeiosEvent ->
292294
LeiosSimVizState ->
293295
LeiosSimVizState
294-
accumEventVizState _now (LeiosEventSetup shape nodes links) vs =
296+
accumEventVizState _now (LeiosEventSetup shape nodes stakes links) vs =
295297
vs
296298
{ vizWorld = shape
297299
, vizNodePos = nodes
300+
, vizNodeStakes = stakes
298301
, vizNodeLinks =
299302
Map.fromSet
300303
( \(n1, n2) ->
@@ -343,7 +346,7 @@ leiosSimVizModel LeiosModelConfig{recentSpan} =
343346
assert (not (blockHash blk `Map.member` vizMsgsDiffusionLatency vs)) $
344347
Map.insert
345348
(blockHash blk)
346-
(blockHeader blk, nid, now, [now])
349+
(blockHeader blk, nid, now, [(nid, now)])
347350
(vizMsgsDiffusionLatency vs)
348351
, ibsInRBs = accumIBsInRBs (Left blk) vs.ibsInRBs
349352
}
@@ -378,7 +381,7 @@ leiosSimVizModel LeiosModelConfig{recentSpan} =
378381
, vizMsgsDiffusionLatency =
379382
Map.adjust
380383
( \(hdr, nid', created, arrivals) ->
381-
(hdr, nid', created, now : arrivals)
384+
(hdr, nid', created, (nid, now) : arrivals)
382385
)
383386
(blockHash blk)
384387
(vizMsgsDiffusionLatency vs)

0 commit comments

Comments
 (0)