Skip to content

Costing for caseList and caseData #6929

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 44 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
2e184d8
Intial costing benchmarks for CaseList
kwxm Mar 8, 2025
8060b3e
Intial costing benchmarks for CaseData
kwxm Mar 8, 2025
ab6fb6b
Remove one level of nesting
kwxm Mar 8, 2025
3d742df
Order constructors
kwxm Mar 8, 2025
3c71e88
Move CaseList
kwxm Mar 8, 2025
3042ebc
Preliminay costing code
kwxm Mar 8, 2025
2d924dc
WIP
kwxm Mar 9, 2025
77dceaf
WIP
kwxm Mar 9, 2025
7ff1f08
Trying to resolve conflicts deriving from 566a319
kwxm Mar 9, 2025
f29ba52
WIP: add stubs to resolve array costing problem
kwxm Mar 9, 2025
224aff0
WIP
kwxm Mar 9, 2025
899b489
Almost finished
kwxm Mar 9, 2025
b837688
Almost finished
kwxm Mar 9, 2025
84c80fd
Reduce number of samples for ChooseList
kwxm Mar 9, 2025
6bb0455
Force
kwxm Mar 9, 2025
2b416dd
Initial cost models
kwxm Mar 9, 2025
31a99d8
Force term arguments
kwxm Mar 9, 2025
ae0cc62
Update cost models
kwxm Mar 9, 2025
f318136
Experiment: remove more overhead
kwxm Mar 9, 2025
001bd3b
Update plutus-core/cost-model/create-cost-model/CreateBuiltinCostMode…
kwxm Mar 11, 2025
c0c4aab
Merge branch 'master' into kwxm/costing/case-list-case-data
kwxm Mar 11, 2025
0053fd1
WIP
kwxm Mar 11, 2025
810ab6d
Merge branch 'kwxm/costing/case-list-case-data' of github.com:Interse…
kwxm Mar 11, 2025
524f75c
Merge branch 'master' into kwxm/costing/case-list-case-data
kwxm Mar 11, 2025
555cfbc
Trying to fix plutus-ledger-api tests
kwxm Mar 13, 2025
2bf1994
Merge branch 'master' into kwxm/costing/case-list-case-data
kwxm Mar 13, 2025
4deba2b
WIP
kwxm Mar 13, 2025
3a905ff
Fix conflict
kwxm Mar 13, 2025
7d9bc24
Slightly more informative errors
kwxm Mar 13, 2025
72e614c
WIP
kwxm Mar 13, 2025
a521963
Remove accidentally-committed file
kwxm Mar 13, 2025
924e27f
WIP
kwxm Mar 13, 2025
e682316
Make errors clearer
kwxm Mar 13, 2025
ad295b2
Make plutus-ledger-api-test work
kwxm Mar 13, 2025
0b3a719
Merge branch 'master' into kwxm/costing/case-list-case-data
kwxm Mar 16, 2025
cdcd659
Nops for functions returning deferred applications
kwxm Mar 16, 2025
3971e59
WIP
kwxm Mar 17, 2025
693311e
Try better benchmarks for nops returning deferred applications
kwxm Mar 18, 2025
e46cd35
Fixes
kwxm Mar 19, 2025
20b8293
Wrong type in Nop4r
kwxm Mar 19, 2025
e767e0d
More experiments
kwxm Mar 19, 2025
a67849e
Back to using last argument
kwxm Mar 19, 2025
611f21a
Return unit
kwxm Mar 20, 2025
be10180
Return unit
kwxm Mar 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 64 additions & 4 deletions plutus-core/cost-model/budgeting-bench/Benchmarks/Data.hs
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}

module Benchmarks.Data (makeBenchmarks) where

import Common
import Generators

import PlutusCore hiding (Constr)
import PlutusCore.Compiler.Erase (eraseTerm)
import PlutusCore.Data
import PlutusCore.MkPlc (builtin, mkConstant, mkIterAppNoAnn, mkIterInstNoAnn)

import Control.DeepSeq (force)
import Criterion.Main
import System.Random (StdGen)

Expand All @@ -21,7 +27,6 @@ import System.Random (StdGen)
| B ByteString
-}


isConstr :: Data -> Bool
isConstr = \case {Constr {} -> True; _ -> False}

Expand All @@ -45,11 +50,11 @@ isB = \case {B {} -> True; _ -> False}
-- fortunately 'chooseData' is parametric in its last five arguments so we can
-- just give it integers for those.
benchChooseData :: Benchmark
benchChooseData = bgroup (show name) [mkBM d | d <- take 100 dataSample]
benchChooseData = bgroup (show name) [mkBM d | d <- take 30 dataSample]
where name = ChooseData
mkBM d = benchDefault (showMemoryUsage d) $
mkApp6 name [integer] d (111::Integer) (222::Integer)
(333::Integer) (444::Integer) (555::Integer)
(333::Integer) (444::Integer) (555::Integer)


---------------- Construction ----------------
Expand Down Expand Up @@ -133,6 +138,60 @@ benchSerialiseData =
-- does the internal structure of a Data object influence serialisation
-- time? What causes a Data object to be quick or slow to serialise?

{- Benchmark `caseData`. The first argument is `lam x. lam y. ()` and the next
four are all `lam x. ()` (and the final one is a `data` object). This is to
minimise the amount of extra work that the evaluator has to do after the
builtin returns (which will be included in the cost of the builtin). We can't
re-use the functions that we use for other benchmarks because the term
arguments whave to be treated separately, so there's quite a bit of extra
machinery in here; it seems unlikely to be more generally useful, so for the
time being it's kept local to this function. -}
{- Experiments show that the function takes the about ame amount of time for each
constructor, even for `Constr` which might be expected to take longer because
it has two arguments. -}
benchCaseData :: Benchmark
benchCaseData =
let name = CaseData
-- Thirty data objects for each constructor, in separate batches so that
-- we can check that they all take about the same amount of time.
inputs = (take 30 $ filter isConstr dataSample)
++ (take 30 $ filter isMap dataSample)
++ (take 30 $ filter isList dataSample)
++ (take 30 $ filter isI dataSample)
++ (take 30 $ filter isB dataSample)
y = Name "y" (Unique 1)
ys = Name "ys" (Unique 2)
-- lam y (con unit ())
mkCase1 ty = LamAbs () y ty (mkConstant () ())
-- lam y (lam ys (con unit ()))
mkCase2 ty1 ty2 = LamAbs () y ty1 (LamAbs () ys ty2 (mkConstant () ()))
-- Like mkApp6, but the first five arguments are terms (in fact values)
mkApp6' !fun !tys !term1 !term2 !term3 !term4 !term5 (force -> !d) =
eraseTerm $ mkIterAppNoAnn instantiated [term1, term2, term3, term4, term5, mkConstant () d]
where instantiated = mkIterInstNoAnn (builtin () fun) tys

mkBMs l =
let caseConstr = mkCase2 integer (list tydata)
caseMap = mkCase1 (list (pair tydata tydata))
caseList = mkCase1 (list tydata)
caseI = mkCase1 integer
caseB = mkCase1 bytestring
in [ bgroup "1" -- Fake size for term arguments
[ bgroup "1"
[ bgroup "1"
[ bgroup "1"
[ bgroup "1"
[ benchDefault
(showMemoryUsage d)
(mkApp6' name [unit] caseConstr caseMap caseList caseI caseB d)
]
]
]
]
]
| d <- l ]
in bgroup (show name) $ mkBMs inputs

makeBenchmarks :: StdGen -> [Benchmark]
makeBenchmarks gen =
[ benchChooseData
Expand All @@ -148,4 +207,5 @@ makeBenchmarks gen =
, benchUnBData
, benchEqualsData
, benchSerialiseData
, benchCaseData
]
78 changes: 70 additions & 8 deletions plutus-core/cost-model/budgeting-bench/Benchmarks/Lists.hs
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
module Benchmarks.Lists (makeBenchmarks) where
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}

module Benchmarks.Lists where

import Common
import Generators

import PlutusCore
import PlutusCore.Compiler.Erase (eraseTerm)
import PlutusCore.Evaluation.Machine.ExMemoryUsage (IntegerCostedLiterally (..))
import PlutusCore.MkPlc (builtin, mkConstant, mkIterAppNoAnn, mkIterInstNoAnn)

import Control.DeepSeq (force)
import Criterion.Main
import Data.ByteString (ByteString)
import Hedgehog qualified as H
import PlutusCore.Evaluation.Machine.ExMemoryUsage (IntegerCostedLiterally (..))
import System.Random (StdGen, randomR)


{- Some functions for generating lists of sizes integers/bytestrings The time
behaviour of the list functions should be independent of the sizes and types
of the arguments (and in fact constant), but we benchmark them with both
Expand Down Expand Up @@ -41,6 +47,12 @@ makeListOfByteStringLists seed ((count, size):rest) =
intLists :: StdGen -> [[Integer]]
intLists gen = makeListOfIntegerLists gen [(count,size) | count <- [0..7], size <- [1..7]]

biggerIntLists :: StdGen -> [[Integer]]
biggerIntLists gen =
makeListOfIntegerLists gen [ (count,size)
| count <- [0, 10, 20, 50, 100, 500, 1000]
, size <- [1..7] ]

-- Make a list of n integers whose value is less than or equal to m
intMaxList :: Integer -> Integer -> StdGen -> [Integer]
intMaxList 0 _ _ = []
Expand All @@ -54,6 +66,12 @@ byteStringLists :: H.Seed -> [[ByteString]]
byteStringLists seed =
makeListOfByteStringLists seed [(count,size) | count <- [0..7], size <- [0, 500..3000]]

biggerByteStringLists :: H.Seed -> [[ByteString]]
biggerByteStringLists seed =
makeListOfByteStringLists seed [ (count,size)
| count <- [0, 10, 20, 50, 100, 500, 1000]
, size <- [0, 500..3000] ]

nonEmptyByteStringLists :: H.Seed -> [[ByteString]]
nonEmptyByteStringLists seed =
makeListOfByteStringLists seed [(count,size) | count <- [1..7], size <- [0, 500..3000]]
Expand All @@ -71,11 +89,11 @@ benchChooseList gen =
intInputs = take 10 $ intLists gen
bsInputs = take 10 $ byteStringLists seedA
mkBMs tys inputs = [ bgroup (showMemoryUsage x)
[ bgroup (showMemoryUsage r1)
[ benchDefault (showMemoryUsage r2) $ mkApp3 name tys x r1 r2
| r2 <- results2 ]
| r1 <- results1 ]
| x <- inputs ]
[ bgroup (showMemoryUsage r1)
[ benchDefault (showMemoryUsage r2) $ mkApp3 name tys x r1 r2
| r2 <- results2 ]
| r1 <- results1 ]
| x <- inputs ]
in bgroup (show name) (mkBMs [integer,bytestring] intInputs
++ mkBMs [bytestring,bytestring] bsInputs)

Expand Down Expand Up @@ -119,11 +137,55 @@ benchDropList gen =
in createTwoTermBuiltinBenchElementwiseWithWrappers
(IntegerCostedLiterally, id) name [bytestring] inputs


{- Benchmark `caseList (con unit ()) (lam x (lam y (con unit ()))) l` to minimise
the amount of extra work the evaluator has to do to compute the final result
after the builtin returns (which will be included in the cost of the builtin)..
We can't re-use the functions that we use for other benchmarks because the term
arguments have to be treated separately, so there's quite a bit of extra
machinery in here; it seems unlikely to be more generally useful, so for the
time being it's kept local to this function.
-}
benchCaseList :: StdGen -> Benchmark
benchCaseList gen =
let name = CaseList
y = Name "y" (Unique 1)
ys = Name "ys" (Unique 2)
-- lam y (con unit ())
mkCase1 ty = LamAbs () y ty (mkConstant () ())
-- lam y (lam ys (con unit ()))
mkCase2 ty = LamAbs () y ty (LamAbs () ys (list ty) (mkConstant () ()))
-- Two different types of inputs, just to make sure there's no difference
-- Use `take` just in case we make the list bigger later
intInputs = take 50 $ biggerIntLists gen
bsInputs = take 50 $ biggerByteStringLists seedA
-- Like mkApp3, but the first two arguments are terms (in fact values)
mkApp3' !fun !tys !term1 !term2 (force -> !l) =
eraseTerm $ mkIterAppNoAnn instantiated [term1, term2, mkConstant () l]
where instantiated = mkIterInstNoAnn (builtin () fun) tys

mkBMs ty inputs =
let case1 = mkCase1 ty
case2 = mkCase2 ty
in [ bgroup "1" -- Fake size for term arguments
[ bgroup "1"
[ benchDefault
-- Strictly it might be better to cost the list by length
-- here, but it's constant time anyway so it shouldn't
-- matter.
(showMemoryUsage l)
(mkApp3' name [ty, unit] case1 case2 l)
]
]
| l <- inputs ]
in bgroup (show name) (mkBMs integer intInputs ++ mkBMs bytestring bsInputs)

makeBenchmarks :: StdGen -> [Benchmark]
makeBenchmarks gen = [ benchChooseList gen
, benchMkCons gen
, benchNonEmptyList gen HeadList
, benchNonEmptyList gen TailList
, benchNullList gen
, benchDropList gen
, benchCaseList gen
]
Loading