Skip to content

Commit 5c1a436

Browse files
Merge #4907
4907: workbench | tx-generator: SECP benchmarking r=deepfire a=mgmeier This PR expands the benchmarking machinery to enable SECP benchmarking. - add `plutuscall-*` profile family to workbench - add `model-*` profile family to workbench - additional loop calibration strategies for tx-generator, where previously only 'maximize per-tx-budget expenditure' was possible - make tx-generator emit a Plutus budget summary after loop calibration (via `TraceBenchPlutusBudgetSummary`) - plus several small convenience improvements Co-authored-by: Michael Karg <[email protected]>
2 parents d9ff0ef + 9528017 commit 5c1a436

File tree

23 files changed

+584
-88
lines changed

23 files changed

+584
-88
lines changed

Makefile

+7
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ PROFILES_BASE := default plutus plutus-secp-ecdsa plutus-secp-schnorr ol
7777
PROFILES_STARTSTOP := startstop startstop-p2p startstop-plutus startstop-notracer startstop-oldtracing
7878
PROFILES_CI_TEST := ci-test ci-test-p2p ci-test-plutus ci-test-notracer ci-test-dense10 aws-test
7979
PROFILES_CI_BENCH := ci-bench ci-bench-p2p ci-bench-plutus ci-bench-plutus-secp-ecdsa ci-bench-plutus-secp-schnorr ci-bench-notracer
80+
PROFILES_PLUTUSCALL := plutuscall-loop-plain plutuscall-secp-ecdsa-plain plutuscall-secp-schnorr-plain
81+
PROFILES_PLUTUSCALL += plutuscall-loop-half plutuscall-secp-ecdsa-half plutuscall-secp-schnorr-half
82+
PROFILES_PLUTUSCALL += plutuscall-loop-double plutuscall-secp-ecdsa-double plutuscall-secp-schnorr-double
83+
PROFILES_MODEL := model-value model-secp-ecdsa-plain model-secp-ecdsa-half model-secp-ecdsa-double
84+
PROFILES_MODEL += model-value-test
8085
PROFILES_10 := 10 10-p2p 10-plutus 10-notracer
8186
PROFILES_FORGE_STRESS := forge-stress forge-stress-p2p forge-stress-plutus forge-stress-plutus-singleton forge-stress-notracer
8287
PROFILES_FORGE_STRESS_PRE := forge-stress-pre forge-stress-pre-plutus forge-stress-pre-notracer
@@ -88,6 +93,8 @@ SHELL_PROFILES += $(PROFILES_BASE)
8893
SHELL_PROFILES += $(PROFILES_STARTSTOP)
8994
SHELL_PROFILES += $(PROFILES_CI_TEST)
9095
SHELL_PROFILES += $(PROFILES_CI_BENCH)
96+
SHELL_PROFILES += $(PROFILES_PLUTUSCALL)
97+
SHELL_PROFILES += $(PROFILES_MODEL)
9198
SHELL_PROFILES += $(PROFILES_10)
9299
SHELL_PROFILES += $(PROFILES_FORGE_STRESS)
93100
SHELL_PROFILES += $(PROFILES_FORGE_STRESS_PRE)

bench/plutus-scripts-bench/plutus-scripts-bench.cabal

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ common common-definitions
4747

4848
library
4949
import: common-definitions
50+
, project-config
5051
hs-source-dirs: src
5152

5253
if flag(unexpected_thunks)

bench/tx-generator/src/Cardano/Benchmarking/Command.hs

+5
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ runCommand = withIOManager $ \iocp -> do
4747
JsonHL file nodeConfigOverwrite cardanoTracerOverwrite -> do
4848
opts <- parseJSONFile fromJSON file
4949
finalOpts <- mangleTracerConfig cardanoTracerOverwrite <$> mangleNodeConfig nodeConfigOverwrite opts
50+
51+
Prelude.putStrLn $
52+
"--> initial options:\n" ++ show opts ++
53+
"\n--> final options:\n" ++ show finalOpts
54+
5055
case compileOptions finalOpts of
5156
Right script -> runScript script iocp >>= handleError
5257
err -> handleError err

bench/tx-generator/src/Cardano/Benchmarking/Compiler.hs

+2-2
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ splittingPhase srcWallet = do
137137
plutusPayMode :: DstWallet -> Compiler PayMode
138138
plutusPayMode dst = do
139139
~(Just plutus@PlutusOn{..}) <- askNixOption _nix_plutus
140-
scriptSpec <- if plutusType == LimitSaturationLoop
140+
scriptSpec_ <- if hasLoopCalibration plutusType
141141
then case plutusRedeemer of
142142
Nothing -> throwCompileError $ SomeCompilerError "Plutus loop autoscript requires a redeemer."
143143
Just redeemer -> do
@@ -154,7 +154,7 @@ splittingPhase srcWallet = do
154154
executionUnits
155155
debugMode
156156
pure $ ScriptSpec plutusScript budget
157-
return $ PayToScript scriptSpec dst
157+
return $ PayToScript (scriptSpec_ plutusType) dst
158158

159159
-- Generate src and dst wallet names for a splitSequence.
160160
-- testCompiler (error "opts") $ splitSequenceWalletNames (WalletName "w1") (WalletName "w2") (unfoldSplitSequence 1 1000 10000)

bench/tx-generator/src/Cardano/Benchmarking/GeneratorTx.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ type AsyncBenchmarkControl = (Async (), [Async ()], IO SubmissionSummary, IO ())
4848
waitBenchmark :: Tracer IO (TraceBenchTxSubmit TxId) -> AsyncBenchmarkControl -> ExceptT TxGenError IO ()
4949
waitBenchmark traceSubmit (feeder, workers, mkSummary, _) = liftIO $ do
5050
mapM_ waitCatch (feeder : workers)
51-
traceWith traceSubmit =<< TraceBenchTxSubSummary <$> mkSummary
51+
traceWith traceSubmit . TraceBenchTxSubSummary =<< mkSummary
5252

5353
lookupNodeAddress ::
5454
NodeAddress' NodeHostIPv4Address -> IO AddrInfo

bench/tx-generator/src/Cardano/Benchmarking/LogTypes.hs

+3
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import Ouroboros.Network.Protocol.TxSubmission2.Type (TxSubmission2)
5252

5353
import Cardano.Benchmarking.Types
5454
import Cardano.Benchmarking.Version as Version
55+
import Cardano.TxGenerator.PlutusContext (PlutusBudgetSummary)
5556
import Cardano.TxGenerator.Types (TPSRate)
5657

5758
data BenchTracers =
@@ -96,6 +97,8 @@ data TraceBenchTxSubmit txid
9697
-- ^ SubmissionSummary.
9798
| TraceBenchTxSubDebug String
9899
| TraceBenchTxSubError Text
100+
| TraceBenchPlutusBudgetSummary PlutusBudgetSummary
101+
-- ^ PlutusBudgetSummary.
99102
deriving stock (Show, Generic)
100103

101104
data SubmissionSummary

bench/tx-generator/src/Cardano/Benchmarking/Script/Core.hs

+44-10
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ evalGenerator :: forall era. IsShelleyBasedEra era => Generator -> TxGenTxParams
281281
evalGenerator generator txParams@TxGenTxParams{txParamFee = fee} era = do
282282
networkId <- getEnvNetworkId
283283
protocolParameters <- getProtocolParameters
284+
284285
case generator of
285286
SecureGenesis wallet genesisKeyName destKeyName -> do
286287
genesis <- getEnvGenesis
@@ -294,6 +295,7 @@ evalGenerator generator txParams@TxGenTxParams{txParamFee = fee} era = do
294295
walletRefInsertFund destWallet fund
295296
return $ Right tx
296297
return $ Streaming.effect (Streaming.yield <$> gen)
298+
297299
Split walletName payMode payModeChange coins -> do
298300
wallet <- getEnvWallets walletName
299301
(toUTxO, addressOut) <- interpretPayMode payMode
@@ -306,6 +308,7 @@ evalGenerator generator txParams@TxGenTxParams{txParamFee = fee} era = do
306308
txGenerator = genTx protocolParameters (TxInsCollateralNone, []) feeInEra TxMetadataNone
307309
sourceToStore = sourceToStoreTransactionNew txGenerator fundSource inToOut $ mangleWithChange toUTxOChange toUTxO
308310
return $ Streaming.effect (Streaming.yield <$> sourceToStore)
311+
309312
SplitN walletName payMode count -> do
310313
wallet <- getEnvWallets walletName
311314
(toUTxO, addressOut) <- interpretPayMode payMode
@@ -327,16 +330,36 @@ evalGenerator generator txParams@TxGenTxParams{txParamFee = fee} era = do
327330
inToOut = Utils.inputsToOutputsWithFee fee outputs
328331
txGenerator = genTx protocolParameters collaterals feeInEra (toMetadata metadataSize)
329332
sourceToStore = sourceToStoreTransactionNew txGenerator fundSource inToOut (mangle $ repeat toUTxO)
333+
334+
fundPreview <- liftIO $ walletPreview wallet inputs
335+
case sourceTransactionPreview txGenerator fundPreview inToOut (mangle $ repeat toUTxO) of
336+
Left err -> traceDebug $ "Error creating Tx preview: " ++ show err
337+
Right tx -> do
338+
let txSize = txSizeInBytes tx
339+
traceDebug $ "Projected Tx size in bytes: " ++ show txSize
340+
summary_ <- getEnvSummary
341+
forM_ summary_ $ \summary -> do
342+
let summary' = summary {projectedTxSize = Just txSize}
343+
setEnvSummary summary'
344+
traceBenchTxSubmit TraceBenchPlutusBudgetSummary summary'
345+
dumpBudgetSummaryIfExisting
346+
330347
return $ Streaming.effect (Streaming.yield <$> sourceToStore)
348+
331349
Sequence l -> do
332350
gList <- forM l $ \g -> evalGenerator g txParams era
333351
return $ Streaming.for (Streaming.each gList) id
352+
334353
Cycle g -> Streaming.cycle <$> evalGenerator g txParams era
354+
335355
Take count g -> Streaming.take count <$> evalGenerator g txParams era
356+
336357
RoundRobin l -> do
337358
_gList <- forM l $ \g -> evalGenerator g txParams era
338359
error "return $ foldr1 Streaming.interleaves gList"
360+
339361
OneOf _l -> error "todo: implement Quickcheck style oneOf generator"
362+
340363
where
341364
feeInEra = Utils.mkTxFee fee
342365

@@ -414,29 +437,30 @@ makePlutusContext ScriptSpec{..} = do
414437
]
415438
return (sData, redeemer, units)
416439

417-
AutoScript redeemerFile budgetFraction -> do
440+
AutoScript redeemerFile txInputs -> do
418441
redeemer <- liftIOSafe $ readScriptData redeemerFile
419442
let
420-
budget = ExecutionUnits
421-
(executionSteps perTxBudget `div` fromIntegral budgetFraction)
422-
(executionMemory perTxBudget `div` fromIntegral budgetFraction)
443+
strategy = case scriptSpecPlutusType of
444+
LimitTxPerBlock_8 -> TargetTxsPerBlock 8
445+
_ -> TargetTxExpenditure
423446

424447
-- reflects properties hard-coded into the loop scripts for benchmarking:
425448
-- 1. script datum is not used
426449
-- 2. the loop terminates at 1_000_000 when counting down
427450
-- 3. the loop's initial value is the first numerical value in the redeemer argument structure
428451
autoBudget = PlutusAutoBudget
429-
{ autoBudgetUnits = budget
452+
{ autoBudgetUnits = perTxBudget
430453
, autoBudgetDatum = ScriptDataNumber 0
431454
, autoBudgetRedeemer = scriptDataModifyNumber (const 1_000_000) redeemer
432455
}
433-
traceDebug $ "Plutus auto mode : Available budget per Tx input / script run: " ++ show budget
434-
++ " -- fraction of protocolParamMaxTxExUnits budget: 1/" ++ show budgetFraction
456+
traceDebug $ "Plutus auto mode : Available budget per Tx: " ++ show perTxBudget
457+
++ " -- split between inputs per Tx: " ++ show txInputs
435458

436-
case plutusAutoBudgetMaxOut protocolParameters script autoBudget of
459+
case plutusAutoScaleBlockfit protocolParameters scriptSpecFile script autoBudget strategy txInputs of
437460
Left err -> liftTxGenError err
438-
Right PlutusAutoBudget{..} -> do
439-
preRun <- preExecuteScriptAction protocolParameters script autoBudgetDatum autoBudgetRedeemer
461+
Right (summary, PlutusAutoBudget{..}, preRun) -> do
462+
setEnvSummary summary
463+
dumpBudgetSummaryIfExisting
440464
return (autoBudgetDatum, autoBudgetRedeemer, preRun)
441465

442466
let msg = mconcat [ "Plutus Benchmark :"
@@ -485,6 +509,16 @@ preExecuteScriptAction protocolParameters script scriptData redeemer
485509
Left err -> throwE $ WalletError ( "makePlutusContext preExecuteScript failed: " ++ show err )
486510
Right costs -> return costs
487511

512+
dumpBudgetSummaryIfExisting :: ActionM ()
513+
dumpBudgetSummaryIfExisting
514+
= do
515+
summary_ <- getEnvSummary
516+
forM_ summary_ $ \summary -> do
517+
liftIO $ BSL.writeFile summaryFile $ prettyPrintOrdered summary
518+
traceDebug $ "dumpBudgetSummaryIfExisting : budget summary created/updated in: " ++ summaryFile
519+
where
520+
summaryFile = "plutus-budget-summary.json"
521+
488522
traceTxGeneratorVersion :: ActionM ()
489523
traceTxGeneratorVersion = traceBenchTxSubmit TraceTxGeneratorVersion Version.txGeneratorVersion
490524

bench/tx-generator/src/Cardano/Benchmarking/Script/Env.hs

+12
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ module Cardano.Benchmarking.Script.Env (
3939
, setEnvThreads
4040
, getEnvWallets
4141
, setEnvWallets
42+
, getEnvSummary
43+
, setEnvSummary
4244
) where
4345

4446
import Control.Monad.IO.Class
@@ -61,8 +63,10 @@ import Cardano.Benchmarking.Wallet
6163
import Cardano.Node.Protocol.Types (SomeConsensusProtocol)
6264
import Ouroboros.Network.NodeToClient (IOManager)
6365

66+
import Cardano.TxGenerator.PlutusContext (PlutusBudgetSummary)
6467
import Cardano.TxGenerator.Types (TxGenError (..))
6568

69+
6670
data Env = Env { protoParams :: Maybe ProtocolParameterMode
6771
, benchTracers :: Maybe Tracer.BenchTracers
6872
, envGenesis :: Maybe (ShelleyGenesis StandardShelley)
@@ -72,6 +76,7 @@ data Env = Env { protoParams :: Maybe ProtocolParameterMode
7276
, envKeys :: Map String (SigningKey PaymentKey)
7377
, envThreads :: Map String AsyncBenchmarkControl
7478
, envWallets :: Map String WalletRef
79+
, envSummary :: Maybe PlutusBudgetSummary
7580
}
7681

7782
emptyEnv :: Env
@@ -84,6 +89,7 @@ emptyEnv = Env { protoParams = Nothing
8489
, envSocketPath = Nothing
8590
, envThreads = Map.empty
8691
, envWallets = Map.empty
92+
, envSummary = Nothing
8793
}
8894

8995
type ActionM a = ExceptT Error (RWST IOManager () Env IO) a
@@ -140,6 +146,9 @@ setEnvThreads key val = modifyEnv (\e -> e { envThreads = Map.insert key val (en
140146
setEnvWallets :: String -> WalletRef -> ActionM ()
141147
setEnvWallets key val = modifyEnv (\e -> e { envWallets = Map.insert key val (envWallets e) })
142148

149+
setEnvSummary :: PlutusBudgetSummary -> ActionM ()
150+
setEnvSummary val = modifyEnv (\e -> e { envSummary = pure val })
151+
143152
getEnvVal :: (Env -> Maybe t) -> String -> ActionM t
144153
getEnvVal acc s = do
145154
lift (RWS.gets acc) >>= \case
@@ -180,6 +189,9 @@ getEnvThreads = getEnvMap envThreads
180189
getEnvWallets :: String -> ActionM WalletRef
181190
getEnvWallets = getEnvMap envWallets
182191

192+
getEnvSummary :: ActionM (Maybe PlutusBudgetSummary)
193+
getEnvSummary = lift (RWS.gets envSummary)
194+
183195
traceBenchTxSubmit :: (forall txId. x -> Tracer.TraceBenchTxSubmit txId) -> x -> ActionM ()
184196
traceBenchTxSubmit tag msg = do
185197
tracers <- getBenchTracers

bench/tx-generator/src/Cardano/Benchmarking/Script/Types.hs

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ module Cardano.Benchmarking.Script.Types (
1717
, ProtocolParameterMode(..)
1818
, ProtocolParametersSource(QueryLocalNode, UseLocalProtocolFile)
1919
, ScriptBudget(AutoScript, StaticScriptBudget)
20-
, ScriptSpec(ScriptSpec, scriptSpecFile, scriptSpecBudget)
20+
, ScriptSpec(..)
2121
, SubmitMode(Benchmark, DiscardTX, DumpToFile, LocalSocket,
2222
NodeToNode)
2323
, TargetNodes
@@ -110,6 +110,7 @@ data ScriptSpec = ScriptSpec
110110
{
111111
scriptSpecFile :: !FilePath
112112
, scriptSpecBudget :: !ScriptBudget
113+
, scriptSpecPlutusType :: !TxGenPlutusType
113114
}
114115
deriving (Show, Eq)
115116
deriving instance Generic ScriptSpec

bench/tx-generator/src/Cardano/Benchmarking/Tracer.hs

+6
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,10 @@ instance LogFormatting (TraceBenchTxSubmit TxId) where
253253
mconcat [ "kind" .= A.String "TraceBenchTxSubError"
254254
, "msg" .= A.String s
255255
]
256+
TraceBenchPlutusBudgetSummary summary ->
257+
mconcat [ "kind" .= A.String "TraceBenchPlutusBudgetSummary"
258+
, "summary" .= toJSON summary
259+
]
256260

257261
instance MetaTrace (TraceBenchTxSubmit TxId) where
258262
namespaceFor TraceTxGeneratorVersion {} = Namespace [] ["TxGeneratorVersion"]
@@ -271,6 +275,7 @@ instance MetaTrace (TraceBenchTxSubmit TxId) where
271275
namespaceFor TraceBenchTxSubSummary {} = Namespace [] ["eBenchTxSubSummary"]
272276
namespaceFor TraceBenchTxSubDebug {} = Namespace [] ["BenchTxSubDebug"]
273277
namespaceFor TraceBenchTxSubError {} = Namespace [] ["BenchTxSubError"]
278+
namespaceFor TraceBenchPlutusBudgetSummary {} = Namespace [] ["BenchPlutusBudgetSummary"]
274279

275280
severityFor _ _ = Just Info
276281

@@ -293,6 +298,7 @@ instance MetaTrace (TraceBenchTxSubmit TxId) where
293298
, Namespace [] ["eBenchTxSubSummary"]
294299
, Namespace [] ["BenchTxSubDebug"]
295300
, Namespace [] ["BenchTxSubError"]
301+
, Namespace [] ["BenchPlutusBudgetSummary"]
296302
]
297303

298304
instance LogFormatting NodeToNodeSubmissionTrace where

bench/tx-generator/src/Cardano/Benchmarking/Wallet.hs

+7-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,13 @@ mkWalletFundStore walletRef fund = modifyMVar_ walletRef
5656
walletSource :: WalletRef -> Int -> FundSource IO
5757
walletSource ref munch = modifyMVar ref $ \fifo -> return $ case removeFunds munch fifo of
5858
Nothing -> (fifo, Left $ TxGenError "WalletSource: out of funds")
59-
Just (newFifo, funds) -> (newFifo, Right funds)
59+
Just (newFifo, funds) -> (newFifo, Right funds)
60+
61+
-- just a preview of the wallet's funds; wallet remains unmodified
62+
walletPreview :: WalletRef -> Int -> IO [Fund]
63+
walletPreview ref munch = do
64+
fifo <- readMVar ref
65+
return $ maybe (toList fifo) snd (removeFunds munch fifo)
6066

6167
mangleWithChange :: Monad m => CreateAndStore m era -> CreateAndStore m era -> CreateAndStoreList m era PayWithChange
6268
mangleWithChange mkChange mkPayment outs = case outs of

0 commit comments

Comments
 (0)