Skip to content

Commit 1c4b97e

Browse files
committed
simulation: handle NumCores in praosNode
1 parent 003a716 commit 1c4b97e

File tree

11 files changed

+214
-265
lines changed

11 files changed

+214
-265
lines changed

simulation/ouroboros-leios-sim.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ library
6161
LeiosProtocol.Short.VizSim
6262
LeiosProtocol.Short.VizSimP2P
6363
LeiosProtocol.SimTestRelay
64-
LeiosProtocol.TaskMultiQueue
6564
LeiosProtocol.VizSimTestRelay
6665
ModelTCP
6766
JSONCompat
@@ -91,6 +90,7 @@ library
9190
STMCompat
9291
SimTCPLinks
9392
SimTypes
93+
TaskMultiQueue
9494
TimeCompat
9595
Topology
9696
Viz

simulation/src/LeiosProtocol/Short/Generate.hs

Lines changed: 14 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{-# LANGUAGE BangPatterns #-}
22
{-# LANGUAGE GADTs #-}
33
{-# LANGUAGE KindSignatures #-}
4+
{-# LANGUAGE NamedFieldPuns #-}
45
{-# LANGUAGE OverloadedRecordDot #-}
56
{-# LANGUAGE OverloadedStrings #-}
67
{-# LANGUAGE RecordWildCards #-}
@@ -14,16 +15,13 @@ import Control.Monad (forM)
1415
import Control.Monad.State (
1516
MonadState (get, put),
1617
MonadTrans (lift),
17-
StateT (runStateT),
18-
gets,
19-
runState,
18+
StateT,
2019
)
2120
import Data.Bifunctor (Bifunctor (..))
2221
import Data.Kind (Type)
2322
import LeiosProtocol.Common
2423
import LeiosProtocol.Short hiding (Stage (..))
2524
import STMCompat
26-
import System.Random (StdGen, uniformR)
2725

2826
--------------------------------------------------------------------------------
2927

@@ -50,42 +48,7 @@ data SomeRole :: Type where
5048
data SomeAction :: Type where
5149
SomeAction :: Role a -> a -> SomeAction
5250

53-
mkScheduler :: MonadSTM m => StdGen -> (SlotNo -> [(a, Maybe (Double -> Word64))]) -> m (SlotNo -> m [(a, Word64)])
54-
mkScheduler rng0 rates = do
55-
let
56-
sampleRates (_role, Nothing) = return []
57-
sampleRates (role, Just f) = do
58-
(sample, rng') <- gets $ uniformR (0, 1)
59-
put $! rng'
60-
let wins = f sample
61-
return [(role, wins) | wins >= 1]
62-
rngVar <- newTVarIO rng0
63-
let sched slot = atomically $ do
64-
rng <- readTVar rngVar
65-
let (acts, rng1) = flip runState rng . fmap concat . mapM sampleRates $ rates slot
66-
writeTVar rngVar rng1
67-
return acts
68-
return sched
69-
70-
-- | @waitNextSlot cfg targetSlot@ waits until the beginning of
71-
-- @targetSlot@ if that's now or in the future, otherwise the closest slot.
72-
waitNextSlot :: (Monad m, MonadTime m, MonadDelay m) => SlotConfig -> SlotNo -> m SlotNo
73-
waitNextSlot slotConfig targetSlot = do
74-
now <- getCurrentTime
75-
let targetSlotTime = slotTime slotConfig targetSlot
76-
let slot
77-
| now <= targetSlotTime = targetSlot
78-
| otherwise = assert (nextSlotIndex >= 0) $ toEnum nextSlotIndex
79-
where
80-
nextSlotIndex =
81-
assert (slotConfig.duration == 1) $
82-
ceiling $
83-
now `diffUTCTime` slotConfig.start
84-
let tgt = slotTime slotConfig slot
85-
threadDelayNDT (tgt `diffUTCTime` now)
86-
return slot
87-
88-
data BlockGeneratorConfig m = BlockGeneratorConfig
51+
data LeiosGeneratorConfig m = LeiosGeneratorConfig
8952
{ leios :: LeiosConfig
9053
, slotConfig :: SlotConfig
9154
, nodeId :: NodeId
@@ -94,19 +57,21 @@ data BlockGeneratorConfig m = BlockGeneratorConfig
9457
, submit :: [(DiffTime, SomeAction)] -> m ()
9558
}
9659

97-
blockGenerator ::
60+
leiosBlockGenerator ::
9861
forall m.
9962
(MonadSTM m, MonadDelay m, MonadTime m) =>
100-
BlockGeneratorConfig m ->
63+
LeiosGeneratorConfig m ->
10164
m ()
102-
blockGenerator BlockGeneratorConfig{..} = go (0, 0)
65+
leiosBlockGenerator LeiosGeneratorConfig{..} =
66+
blockGenerator $
67+
BlockGeneratorConfig
68+
{ execute = \slot -> do
69+
roles <- lift $ schedule slot
70+
actions <- concat <$> mapM (execute slot) roles
71+
lift $ submit actions
72+
, slotConfig
73+
}
10374
where
104-
go (!blkId, !tgtSlot) = do
105-
slot <- waitNextSlot slotConfig tgtSlot
106-
roles <- schedule slot
107-
(actions, blkId') <- runStateT (concat <$> mapM (execute slot) roles) blkId
108-
submit actions
109-
go (blkId', slot + 1)
11075
execute slot (SomeRole r, wins) = assert (wins >= 1) $ (map . second) (SomeAction r) <$> execute' slot r wins
11176
execute' :: SlotNo -> Role a -> Word64 -> StateT Int m [(DiffTime, a)]
11277
execute' slot Base _wins = do

simulation/src/LeiosProtocol/Short/Node.hs

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import Control.Monad.Class.MonadThrow
2424
import Control.Tracer
2525
import Data.Coerce (coerce)
2626
import Data.Foldable (forM_)
27-
import Data.Ix (Ix, range)
27+
import Data.Ix (Ix)
2828
import Data.List (sort, sortOn)
2929
import Data.Map (Map)
3030
import qualified Data.Map.Strict as Map
@@ -39,7 +39,6 @@ import qualified LeiosProtocol.RelayBuffer as RB
3939
import LeiosProtocol.Short
4040
import LeiosProtocol.Short.Generate
4141
import qualified LeiosProtocol.Short.Generate as Generate
42-
import LeiosProtocol.TaskMultiQueue
4342
import Numeric.Natural (Natural)
4443
import PraosProtocol.BlockFetch (
4544
BlockFetchControllerState (blocksVar),
@@ -51,7 +50,7 @@ import qualified PraosProtocol.PraosNode as PraosNode
5150
import STMCompat
5251
import SimTypes (cpuTask)
5352
import System.Random
54-
import WorkerPool
53+
import TaskMultiQueue
5554

5655
--------------------------------------------------------------
5756
---- Events
@@ -99,9 +98,9 @@ data LeiosNodeState m = LeiosNodeState
9998
, relayVoteState :: !(RelayVoteState m)
10099
, ibDeliveryTimesVar :: !(TVar m (Map InputBlockId UTCTime))
101100
, taskQueue :: !(TaskMultiQueue LeiosNodeTask m)
102-
, waitingForRBVar :: !(TVar m (Map (HeaderHash RankingBlock) [m ()]))
101+
, waitingForRBVar :: !(TVar m (Map (HeaderHash RankingBlock) [STM m ()]))
103102
-- ^ waiting for RB block itself to be validated.
104-
, waitingForLedgerStateVar :: !(TVar m (Map (HeaderHash RankingBlock) [m ()]))
103+
, waitingForLedgerStateVar :: !(TVar m (Map (HeaderHash RankingBlock) [STM m ()]))
105104
-- ^ waiting for ledger state of RB block to be validated.
106105
, ledgerStateVar :: !(TVar m (Map (HeaderHash RankingBlock) LedgerState))
107106
, ibsNeededForEBVar :: !(TVar m (Map EndorseBlockId (Set InputBlockId)))
@@ -400,25 +399,6 @@ leiosNode tracer cfg followers peers = do
400399
, pruningThreads
401400
]
402401

403-
processCPUTasks ::
404-
(MonadSTM m, MonadDelay m, MonadMonotonicTimeNSec m, MonadFork m, MonadAsync m, MonadCatch m) =>
405-
NumCores ->
406-
Tracer m CPUTask ->
407-
TaskMultiQueue LeiosNodeTask m ->
408-
m ()
409-
processCPUTasks Infinite tracer queue = forever $ runInfParallelBlocking tracer queue
410-
processCPUTasks (Finite n) tracer queue = newBoundedWorkerPool n [taskSource l | l <- range (minBound, maxBound)]
411-
where
412-
taskSource l = do
413-
(cpu, m) <- readTMQueue queue l
414-
var <- newEmptyTMVar
415-
let action = do
416-
traceWith tracer cpu
417-
threadDelay (cpuTaskDuration cpu)
418-
m
419-
-- TODO: read from var and log exception.
420-
return $ Task action var
421-
422402
computeLedgerStateThread ::
423403
forall m.
424404
(MonadMVar m, MonadFork m, MonadAsync m, MonadSTM m, MonadTime m, MonadDelay m) =>
@@ -456,7 +436,7 @@ dispatchValidation ::
456436
dispatchValidation tracer cfg leiosState req =
457437
atomically $ mapM_ (uncurry $ writeTMQueue leiosState.taskQueue) =<< go req
458438
where
459-
queue = atomically . mapM_ (uncurry $ writeTMQueue leiosState.taskQueue)
439+
queue = mapM_ (uncurry $ writeTMQueue leiosState.taskQueue)
460440
labelTask (tag, (f, m)) = let !task = f (show tag) in (tag, (task, m))
461441
valRB rb m = do
462442
let task prefix = cpuTask prefix cfg.leios.praos.blockValidationDelay rb
@@ -561,7 +541,7 @@ generator tracer cfg st = do
561541
atomically $ modifyTVar' st.relayVoteState.relayBufferVar (RB.snoc v.id (v.id, v))
562542
traceWith tracer (LeiosNodeEvent Generate (EventVote v))
563543
let LeiosNodeConfig{..} = cfg
564-
blockGenerator $ BlockGeneratorConfig{submit = mapM_ submitOne, ..}
544+
leiosBlockGenerator $ LeiosGeneratorConfig{submit = mapM_ submitOne, ..}
565545

566546
mkBuffersView :: forall m. MonadSTM m => LeiosNodeConfig -> LeiosNodeState m -> BuffersView m
567547
mkBuffersView cfg st = BuffersView{..}

simulation/src/PraosProtocol/BlockFetch.hs

Lines changed: 13 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@ import Chan (Chan)
2626
import ChanDriver (ProtocolMessage, chanDriver)
2727
import Control.Exception (assert)
2828
import Control.Monad (forM, forever, guard, join, unless, void, when, (<=<))
29-
import Control.Tracer (Contravariant (contramap), Tracer, traceWith)
29+
import Control.Tracer (Tracer, traceWith)
3030
import Data.Bifunctor (second)
31-
import Data.Foldable (forM_)
3231
import Data.Kind (Type)
3332
import qualified Data.List as List
3433
import Data.Map.Strict (Map)
@@ -47,7 +46,6 @@ import Network.TypedProtocol (
4746
import Network.TypedProtocol.Driver (runPeerWithDriver)
4847
import qualified Network.TypedProtocol.Peer.Client as TC
4948
import qualified Network.TypedProtocol.Peer.Server as TS
50-
import Numeric.Natural (Natural)
5149
import PraosProtocol.Common
5250
import qualified PraosProtocol.Common.AnchoredFragment as AnchoredFragment
5351
import qualified PraosProtocol.Common.Chain as Chain
@@ -602,82 +600,30 @@ initBlockFetchConsumerStateForPeerId tracer peerId blockFetchControllerState sub
602600

603601
setupValidatorThreads ::
604602
(MonadSTM m, MonadDelay m) =>
605-
Tracer m (PraosNodeEvent BlockBody) ->
606603
PraosConfig BlockBody ->
607604
BlockFetchControllerState BlockBody m ->
608-
-- | bound on queue length.
609-
Natural ->
605+
((CPUTask, m ()) -> STM m ()) ->
610606
m ([m ()], Block BlockBody -> m () -> m ())
611-
setupValidatorThreads tracer cfg st n = do
612-
queue <- newTBQueueIO n
613-
(waitingVar, processWaitingThread) <- setupProcessWaitingThread (contramap PraosNodeEventCPU tracer) (Just 1) st.blocksVar
614-
let doTask (cpuTask, m) = do
615-
traceWith tracer . PraosNodeEventCPU $ cpuTask
616-
threadDelay cpuTask.cpuTaskDuration
617-
m
618-
619-
-- if we have the previous block, we process the task sequentially to provide back pressure on the queue.
620-
let waitForPrev block task = case blockPrevHash block of
621-
GenesisHash -> doTask task
607+
setupValidatorThreads cfg st queue = do
608+
waitingVar <- newTVarIO Map.empty
609+
let processWaitingThread = processWaiting' st.blocksVar waitingVar
610+
611+
let waitForPrev block task = atomically $ case blockPrevHash block of
612+
GenesisHash -> queue task
622613
BlockHash prev -> do
623-
havePrev <- Map.member prev <$> readTVarIO st.blocksVar
624-
-- Note: for pure praos this also means we have the ledger state.
625-
if havePrev
626-
then doTask task
627-
else atomically $ modifyTVar' waitingVar (Map.insertWith (++) prev [task])
628-
fetch = forever $ do
629-
(block, completion) <- atomically $ readTBQueue queue
614+
modifyTVar' waitingVar (Map.insertWith (++) prev [queue task])
615+
add block completion = do
630616
assert (blockInvariant block) $ do
631617
waitForPrev block $
632618
let !cpuTask = CPUTask (cfg.blockValidationDelay block) (T.pack $ "Validate " ++ show (blockHash block))
633619
in (cpuTask, completion)
634-
add block completion = atomically $ writeTBQueue queue (block, completion)
635-
return ([fetch, processWaitingThread], add)
636-
637-
setupProcessWaitingThread ::
638-
forall m a b.
639-
(MonadSTM m, MonadDelay m) =>
640-
Tracer m CPUTask ->
641-
-- | how many waiting to process in parallel
642-
Maybe Int ->
643-
TVar m (Map ConcreteHeaderHash a) ->
644-
m (TVar m (Map ConcreteHeaderHash [(CPUTask, m b)]), m ())
645-
setupProcessWaitingThread tracer npar blocksVar = do
646-
waitingVar <- newTVarIO Map.empty
647-
return (waitingVar, processWaiting tracer npar blocksVar waitingVar)
648-
649-
processWaiting ::
650-
forall m a b.
651-
(MonadSTM m, MonadDelay m) =>
652-
Tracer m CPUTask ->
653-
-- | how many waiting to process in parallel
654-
Maybe Int ->
655-
TVar m (Map ConcreteHeaderHash a) ->
656-
TVar m (Map ConcreteHeaderHash [(CPUTask, m b)]) ->
657-
m ()
658-
processWaiting tracer npar blocksVar waitingVar = go
659-
where
660-
parallelDelay xs = do
661-
let !d = maximum $ map (cpuTaskDuration . fst) xs
662-
forM_ xs $ traceWith tracer . fst
663-
threadDelay d
664-
mapM_ snd xs
665-
go = forever $ join $ atomically $ do
666-
waiting <- readTVar waitingVar
667-
when (Map.null waiting) retry
668-
blocks <- readTVar blocksVar
669-
let toValidate = Map.intersection waiting blocks
670-
when (Map.null toValidate) retry
671-
writeTVar waitingVar $! waiting Map.\\ toValidate
672-
let chunks Nothing xs = [xs]
673-
chunks (Just m) xs = map (take m) . takeWhile (not . null) . iterate (drop m) $ xs
674-
return . mapM_ parallelDelay . chunks npar . concat . Map.elems $ toValidate
620+
return ([processWaitingThread], add)
675621

676622
processWaiting' ::
677623
forall m a b.
678624
(MonadSTM m, MonadDelay m) =>
679625
TVar m (Map ConcreteHeaderHash a) ->
680-
TVar m (Map ConcreteHeaderHash [m b]) ->
626+
TVar m (Map ConcreteHeaderHash [STM m b]) ->
681627
m ()
682628
processWaiting' blocksVar waitingVar = go
683629
where
@@ -688,4 +634,4 @@ processWaiting' blocksVar waitingVar = go
688634
let toValidate = Map.intersection waiting blocks
689635
when (Map.null toValidate) retry
690636
writeTVar waitingVar $! waiting Map.\\ toValidate
691-
return . sequence_ . concat . Map.elems $ toValidate
637+
return . mapM_ atomically . concat . Map.elems $ toValidate

0 commit comments

Comments
 (0)