Skip to content

Commit 2a702d1

Browse files
committed
Add benchmarking code and costing model for insertCoin
1 parent 55cba54 commit 2a702d1

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,6 +11,7 @@ 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.Bits (shiftR, (.&.))
1617
import Data.ByteString (ByteString)
@@ -19,13 +20,13 @@ import Data.Int (Int64)
1920
import Data.List (find, sort)
2021
import Data.Word (Word8)
2122
import GHC.Stack (HasCallStack)
22-
import PlutusCore (DefaultFun (LookupCoin, UnValueData, ValueContains, ValueData))
23+
import PlutusCore (DefaultFun (InsertCoin, LookupCoin, UnValueData, ValueContains, ValueData))
2324
import PlutusCore.Builtin (BuiltinResult (BuiltinFailure, BuiltinSuccess, BuiltinSuccessWithLogs))
2425
import PlutusCore.Evaluation.Machine.ExMemoryUsage (ValueLogOuterSizeAddLogMaxInnerSize (..),
2526
ValueTotalSize (..))
26-
import PlutusCore.Value (K, Value)
27+
import PlutusCore.Value (K, Quantity (..), Value)
2728
import PlutusCore.Value qualified as Value
28-
import System.Random.Stateful (StatefulGen, StdGen, runStateGen_, uniformRM)
29+
import System.Random.Stateful (StateGenM, StatefulGen, StdGen, runStateGen_, uniformRM)
2930

3031
----------------------------------------------------------------------------------------------------
3132
-- Benchmarks --------------------------------------------------------------------------------------
@@ -36,6 +37,7 @@ makeBenchmarks gen =
3637
, valueContainsBenchmark gen
3738
, valueDataBenchmark gen
3839
, unValueDataBenchmark gen
40+
, insertCoinBenchmark gen
3941
]
4042

4143
----------------------------------------------------------------------------------------------------
@@ -47,10 +49,10 @@ lookupCoinBenchmark gen =
4749
(id, id, ValueLogOuterSizeAddLogMaxInnerSize) -- Wrap Value argument to report sum of log sizes
4850
LookupCoin -- the builtin fun
4951
[] -- no type arguments needed (monomorphic builtin)
50-
(lookupCoinArgs gen) -- the argument combos to generate benchmarks for
52+
(runBenchGen gen lookupCoinArgs) -- the argument combos to generate benchmarks for
5153

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

8284
sequence
8385
-- Generate worst-case lookups for each size combination
84-
[ withWorstCaseSearchKeys (generateConstrainedValueWithMaxPolicy numPolicies tokensPerPolicy g)
86+
[ withWorstCaseSearchKeys (generateConstrainedValueWithMaxPolicy numPolicies tokensPerPolicy gen)
8587
| numPolicies <- sizes
8688
, tokensPerPolicy <- sizes
8789
]
@@ -211,6 +213,41 @@ unValueDataBenchmark :: StdGen -> Benchmark
211213
unValueDataBenchmark gen =
212214
createOneTermBuiltinBench UnValueData [] (Value.valueData <$> generateTestValues gen)
213215

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

@@ -360,3 +397,8 @@ unsafeFromBuiltinResult = \case
360397
BuiltinSuccess x -> x
361398
BuiltinSuccessWithLogs _ x -> x
362399
BuiltinFailure _ err -> error $ "BuiltinResult failed: " <> show err
400+
401+
-- | Abstracted runner for computations using stateful random generator 'StdGen'
402+
runBenchGen :: StdGen -> (StateGenM StdGen -> State StdGen a) -> a
403+
runBenchGen gen ma = runStateGen_ gen \g -> ma g
404+

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)