Skip to content

Commit b7c479e

Browse files
committed
Add benchmarking code and costing model for insertCoin
1 parent e50aa20 commit b7c479e

File tree

4 files changed

+99
-25
lines changed

4 files changed

+99
-25
lines changed

plutus-core/cost-model/budgeting-bench/Benchmarks/Values.hs

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,21 @@ import Prelude
1111

1212
import Common
1313
import Control.Monad (replicateM)
14+
import Control.Monad.State.Strict (State)
1415
import Criterion.Main (Benchmark)
1516
import Data.ByteString (ByteString)
1617
import Data.ByteString qualified as BS
1718
import Data.Int (Int64)
1819
import Data.List (find, sort)
1920
import Data.Word (Word8)
2021
import GHC.Stack (HasCallStack)
21-
import PlutusCore (DefaultFun (LookupCoin, UnValueData, ValueContains, ValueData))
22+
import PlutusCore (DefaultFun (InsertCoin, LookupCoin, UnValueData, ValueContains, ValueData))
2223
import PlutusCore.Builtin (BuiltinResult (BuiltinFailure, BuiltinSuccess, BuiltinSuccessWithLogs))
2324
import PlutusCore.Evaluation.Machine.ExMemoryUsage (ValueLogOuterSizeAddLogMaxInnerSize (..),
2425
ValueTotalSize (..))
25-
import PlutusCore.Value (K, Value)
26+
import PlutusCore.Value (K, Quantity (..), Value)
2627
import PlutusCore.Value qualified as Value
27-
import System.Random.Stateful (StatefulGen, StdGen, runStateGen_, uniformRM)
28+
import System.Random.Stateful (StateGenM, StatefulGen, StdGen, runStateGen_, uniformRM)
2829

2930
----------------------------------------------------------------------------------------------------
3031
-- Benchmarks --------------------------------------------------------------------------------------
@@ -35,6 +36,7 @@ makeBenchmarks gen =
3536
, valueContainsBenchmark gen
3637
, valueDataBenchmark gen
3738
, unValueDataBenchmark gen
39+
, insertCoinBenchmark gen
3840
]
3941

4042
----------------------------------------------------------------------------------------------------
@@ -46,10 +48,10 @@ lookupCoinBenchmark gen =
4648
(id, id, ValueLogOuterSizeAddLogMaxInnerSize) -- Wrap Value argument to report sum of log sizes
4749
LookupCoin -- the builtin fun
4850
[] -- no type arguments needed (monomorphic builtin)
49-
(lookupCoinArgs gen) -- the argument combos to generate benchmarks for
51+
(runBenchGen gen lookupCoinArgs) -- the argument combos to generate benchmarks for
5052

51-
lookupCoinArgs :: StdGen -> [(ByteString, ByteString, Value)]
52-
lookupCoinArgs gen = runStateGen_ gen \(g :: g) -> do
53+
lookupCoinArgs :: (StatefulGen g m) => g -> m [(ByteString, ByteString, Value)]
54+
lookupCoinArgs gen = do
5355
{- Exhaustive power-of-2 combinations for BST worst-case benchmarking.
5456
5557
Tests all combinations of sizes from powers and half-powers of 2.
@@ -80,7 +82,7 @@ lookupCoinArgs gen = runStateGen_ gen \(g :: g) -> do
8082

8183
sequence
8284
-- Generate worst-case lookups for each size combination
83-
[ withWorstCaseSearchKeys (generateConstrainedValueWithMaxPolicy numPolicies tokensPerPolicy g)
85+
[ withWorstCaseSearchKeys (generateConstrainedValueWithMaxPolicy numPolicies tokensPerPolicy gen)
8486
| numPolicies <- sizes
8587
, tokensPerPolicy <- sizes
8688
]
@@ -210,6 +212,41 @@ unValueDataBenchmark :: StdGen -> Benchmark
210212
unValueDataBenchmark gen =
211213
createOneTermBuiltinBench UnValueData [] (Value.valueData <$> generateTestValues gen)
212214

215+
----------------------------------------------------------------------------------------------------
216+
-- InsertCoin --------------------------------------------------------------------------------------
217+
218+
insertCoinBenchmark :: StdGen -> Benchmark
219+
insertCoinBenchmark gen =
220+
createFourTermBuiltinBenchElementwiseWithWrappers
221+
(id, id, id, ValueLogOuterSizeAddLogMaxInnerSize)
222+
InsertCoin
223+
[]
224+
(runBenchGen gen insertCoinArgs)
225+
226+
insertCoinArgs :: (StatefulGen g m) => g -> m [(ByteString, ByteString, Integer, Value)]
227+
insertCoinArgs gen = do
228+
lookupArgs <- lookupCoinArgs gen
229+
let noOfBenchs = length lookupArgs
230+
amounts <- genZeroOrMaxAmount gen noOfBenchs
231+
pure $ reorderArgs <$> zip lookupArgs amounts
232+
where
233+
reorderArgs ((b1, b2, val), am) = (b1, b2, am, val)
234+
235+
-- | Generate either zero or maximum amount Integer values, the probability of each is 50%
236+
genZeroOrMaxAmount
237+
:: (StatefulGen g m)
238+
=> g
239+
-> Int
240+
-- ^ Number of amounts to generate
241+
-> m [Integer]
242+
genZeroOrMaxAmount gen n =
243+
replicateM n $ do
244+
coinType <- uniformRM (0 :: Int, 1) gen
245+
pure $ case coinType of
246+
0 -> 0
247+
1 -> unQuantity maxBound
248+
_ -> error "genZeroOrMaxAmount: impossible"
249+
213250
----------------------------------------------------------------------------------------------------
214251
-- Value Generators --------------------------------------------------------------------------------
215252

@@ -341,3 +378,8 @@ unsafeFromBuiltinResult = \case
341378
BuiltinSuccess x -> x
342379
BuiltinSuccessWithLogs _ x -> x
343380
BuiltinFailure _ err -> error $ "BuiltinResult failed: " <> show err
381+
382+
-- | Abstracted runner for computations using stateful random generator 'StdGen'
383+
runBenchGen :: StdGen -> (StateGenM StdGen -> State StdGen a) -> a
384+
runBenchGen gen ma = runStateGen_ gen \g -> ma g
385+

plutus-core/cost-model/budgeting-bench/Main.hs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,20 @@ main = do
4848
criterionMainWith
4949
Start
5050
defaultConfig $
51-
Benchmarks.Bitwise.makeBenchmarks
52-
<> Benchmarks.Bool.makeBenchmarks gen
53-
<> Benchmarks.ByteStrings.makeBenchmarks gen
54-
<> Benchmarks.Crypto.makeBenchmarks gen
55-
<> Benchmarks.Data.makeBenchmarks gen
56-
<> Benchmarks.Integers.makeBenchmarks gen
57-
<> Benchmarks.Lists.makeBenchmarks gen
58-
<> Benchmarks.Arrays.makeBenchmarks gen
59-
<> Benchmarks.Misc.makeBenchmarks gen
60-
<> Benchmarks.Pairs.makeBenchmarks gen
61-
<> Benchmarks.Strings.makeBenchmarks gen
62-
<> Benchmarks.Tracing.makeBenchmarks gen
63-
<> Benchmarks.Unit.makeBenchmarks gen
64-
<> Benchmarks.Values.makeBenchmarks gen
51+
Benchmarks.Bitwise.makeBenchmarks
52+
<> Benchmarks.Bool.makeBenchmarks gen
53+
<> Benchmarks.ByteStrings.makeBenchmarks gen
54+
<> Benchmarks.Crypto.makeBenchmarks gen
55+
<> Benchmarks.Data.makeBenchmarks gen
56+
<> Benchmarks.Integers.makeBenchmarks gen
57+
<> Benchmarks.Lists.makeBenchmarks gen
58+
<> Benchmarks.Arrays.makeBenchmarks gen
59+
<> Benchmarks.Misc.makeBenchmarks gen
60+
<> Benchmarks.Pairs.makeBenchmarks gen
61+
<> Benchmarks.Strings.makeBenchmarks gen
62+
<> Benchmarks.Tracing.makeBenchmarks gen
63+
<> Benchmarks.Unit.makeBenchmarks gen
64+
<> Benchmarks.Values.makeBenchmarks gen
6565

6666
{- Run the nop benchmarks with a large time limit (30 seconds) in an attempt to
6767
get accurate results. -}

plutus-core/cost-model/data/models.R

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ arity <- function(name) {
156156
"ValueContains" = 2,
157157
"ValueData" = 1,
158158
"UnValueData" = 1,
159+
"InsertCoin" = 4,
159160
-1 ## Default for missing values
160161
)
161162
}
@@ -170,7 +171,7 @@ get.bench.data <- function(path) {
170171
comment.char="#"
171172
)
172173

173-
benchname <- regex("([[:alnum:]_]+)/(\\d+)(?:/(\\d+))?(?:/(\\d+))?")
174+
benchname <- regex("([[:alnum:]_]+)/(\\d+)(?:/(\\d+))?(?:/(\\d+))?(?:/(\\d+))?")
174175
## We have benchmark names like "AddInteger/11/22", the numbers representing the sizes of
175176
## the inputs to the benchmark. This extracts the name and up to three numbers, returning
176177
## "NA" for any that are missing. If we ever have builtins with more than three arguments
@@ -182,7 +183,7 @@ get.bench.data <- function(path) {
182183
## the size of the first one because the others are terms (and the time is
183184
## constant anyway).
184185

185-
numbercols = c("x_mem", "y_mem", "z_mem")
186+
numbercols = c("x_mem", "y_mem", "z_mem", "w_mem")
186187

187188
benchmark.name.to.numbers <- function(name) {
188189
a <- str_match(name, benchname)
@@ -432,6 +433,14 @@ modelFun <- function(path) {
432433
return (mk.result(m, "linear_in_z"))
433434
}
434435

436+
linearInW <- function (fname) {
437+
filtered <- data %>%
438+
filter.and.check.nonempty(fname) %>%
439+
discard.overhead ()
440+
m <- lm(t ~ w_mem, filtered)
441+
return (mk.result(m, "linear_in_w"))
442+
}
443+
435444
##### Integers #####
436445

437446
addIntegerModel <- {
@@ -817,6 +826,7 @@ modelFun <- function(path) {
817826

818827
# Z wrapped with `Logarithmic . ValueOuterOrMaxInner`
819828
lookupCoinModel <- linearInZ ("LookupCoin")
829+
insertCoinModel <- linearInW ("InsertCoin")
820830

821831
# X wrapped with `ValueLogOuterSizeAddLogMaxInnerSize` (sum of logarithmic sizes)
822832
# Y wrapped with `ValueTotalSize` (contained value size)
@@ -829,7 +839,7 @@ modelFun <- function(path) {
829839
mk.result(m, "multiplied_sizes")
830840
}
831841

832-
# Sizes of parameters are used as is (unwrapped):
842+
# # Sizes of parameters are used as is (unwrapped):
833843
valueDataModel <- constantModel ("ValueData")
834844
unValueDataModel <- linearInX ("UnValueData")
835845

@@ -930,7 +940,8 @@ modelFun <- function(path) {
930940
lookupCoinModel = lookupCoinModel,
931941
valueContainsModel = valueContainsModel,
932942
valueDataModel = valueDataModel,
933-
unValueDataModel = unValueDataModel
943+
unValueDataModel = unValueDataModel,
944+
insertCoinModel = insertCoinModel
934945
)
935946

936947
## The integer division functions have a complex costing behaviour that requires some negative

scripts/toframe.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/bin/bash
2+
cat "$*" |
3+
sed 's#/# #g' |
4+
sed 's/,/ /g' |
5+
# grep -v "^Nop" |
6+
grep -v "^#" |
7+
awk '
8+
BEGIN {printf ("name x y z u v w t lb ub\n")}
9+
function print1() {printf ("%-20s %7d %7d %7d %7d %7d %7d %g %g %g \n", $1, $2, 0, 0, 0, 0, 0, $3, $4, $5)}
10+
function print2() {printf ("%-20s %7d %7d %7d %7d %7d %7d %g %g %g \n", $1, $2, $3, 0, 0, 0, 0, $4, $5, $6)}
11+
function print3() {printf ("%-20s %7d %7d %7d %7d %7d %7d %g %g %g \n", $1, $2, $3, $4, 0, 0, 0, $5, $6, $7)}
12+
function print4() {printf ("%-20s %7d %7d %7d %7d %7d %7d %g %g %g \n", $1, $2, $3, $4, $5, 0, 0, $6, $7, $8)}
13+
function print5() {printf ("%-20s %7d %7d %7d %7d %7d %7d %g %g %g \n", $1, $2, $3, $4, $5, $6, 0, $7, $8, $9)}
14+
function print6() {printf ("%-20s %7d %7d %7d %7d %7d %7d %g %g %g \n", $1, $2, $3, $4, $5, $6, $7, $8, $9, $10)}
15+
NF == 8 {print1()}
16+
NF == 9 {print2()}
17+
NF == 10 {print3()}
18+
NF == 11 {print4()}
19+
NF == 12 {print5()}
20+
NF == 13 {print6()}
21+
'

0 commit comments

Comments
 (0)