Skip to content

Commit 5d2560e

Browse files
committed
refactor: use consistent size measure wrappers for Value builtins
Address Kenneth's review comment by ensuring builtins use the same size measure wrappers as their budgeting benchmarks. Changes: - Add LogValueOuterOrMaxInner newtype combining logarithmic transformation with outer/max inner size measurement - Update lookupCoin and valueContains to use size measure wrappers - Add KnownTypeAst instances for ValueTotalSize and LogValueOuterOrMaxInner - Update benchmarks to use new combined wrapper type This ensures the cost model accurately reflects runtime behavior by using identical size measures in both denotations and benchmarks.
1 parent 5fde194 commit 5d2560e

File tree

4 files changed

+57
-11
lines changed

4 files changed

+57
-11
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import Control.Monad (replicateM)
1111
import Criterion.Main (Benchmark)
1212
import Data.ByteString (ByteString)
1313
import PlutusCore (DefaultFun (LookupCoin, UnValueData, ValueContains, ValueData))
14-
import PlutusCore.Evaluation.Machine.ExMemoryUsage (Logarithmic (..), ValueOuterOrMaxInner (..),
14+
import PlutusCore.Evaluation.Machine.ExMemoryUsage (LogValueOuterOrMaxInner (..),
1515
ValueTotalSize (..))
1616
import PlutusCore.Value (K, Value)
1717
import PlutusCore.Value qualified as Value
@@ -34,7 +34,7 @@ makeBenchmarks gen =
3434
lookupCoinBenchmark :: StdGen -> Benchmark
3535
lookupCoinBenchmark gen =
3636
createThreeTermBuiltinBenchElementwiseWithWrappers
37-
(id, id, Logarithmic . ValueOuterOrMaxInner) -- Wrap Value argument to report outer/max inner size
37+
(id, id, LogValueOuterOrMaxInner) -- Wrap Value argument to report outer/max inner size with log
3838
LookupCoin -- the builtin fun
3939
[] -- no type arguments needed (monomorphic builtin)
4040
(lookupCoinArgs gen) -- the argument combos to generate benchmarks for
@@ -102,8 +102,8 @@ generateRandomLookupTest g = do
102102
valueContainsBenchmark :: StdGen -> Benchmark
103103
valueContainsBenchmark gen =
104104
createTwoTermBuiltinBenchElementwiseWithWrappers
105-
(Logarithmic . ValueOuterOrMaxInner, ValueTotalSize)
106-
-- Container: outer/maxInner, Contained: totalSize
105+
(LogValueOuterOrMaxInner, ValueTotalSize)
106+
-- Container: outer/maxInner with log, Contained: totalSize
107107
ValueContains -- the builtin fun
108108
[] -- no type arguments needed (monomorphic builtin)
109109
(valueContainsArgs gen) -- the argument combos to generate benchmarks for

plutus-core/plutus-core/src/PlutusCore/Default/Builtins.hs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@ import PlutusCore.Default.Universe
2424
import PlutusCore.Evaluation.Machine.BuiltinCostModel
2525
import PlutusCore.Evaluation.Machine.ExBudgetStream (ExBudgetStream)
2626
import PlutusCore.Evaluation.Machine.ExMemoryUsage (ExMemoryUsage, IntegerCostedLiterally (..),
27-
NumBytesCostedAsNumWords (..), memoryUsage,
28-
singletonRose)
27+
LogValueOuterOrMaxInner (..),
28+
NumBytesCostedAsNumWords (..),
29+
ValueTotalSize (..), memoryUsage, singletonRose)
2930
import PlutusCore.Pretty (PrettyConfigPlc)
3031
import PlutusCore.Value (Value)
3132
import PlutusCore.Value qualified as Value
@@ -2055,8 +2056,8 @@ instance uni ~ DefaultUni => ToBuiltinMeaning uni DefaultFun where
20552056
(runCostingFunFourArguments . unimplementedCostingFun)
20562057

20572058
toBuiltinMeaning _semvar LookupCoin =
2058-
let lookupCoinDenotation :: ByteString -> ByteString -> Value -> Integer
2059-
lookupCoinDenotation = Value.lookupCoin
2059+
let lookupCoinDenotation :: ByteString -> ByteString -> LogValueOuterOrMaxInner -> Integer
2060+
lookupCoinDenotation p t (LogValueOuterOrMaxInner v) = Value.lookupCoin p t v
20602061
{-# INLINE lookupCoinDenotation #-}
20612062
in makeBuiltinMeaning
20622063
lookupCoinDenotation
@@ -2071,8 +2072,9 @@ instance uni ~ DefaultUni => ToBuiltinMeaning uni DefaultFun where
20712072
(runCostingFunTwoArguments . unimplementedCostingFun)
20722073

20732074
toBuiltinMeaning _semvar ValueContains =
2074-
let valueContainsDenotation :: Value -> Value -> Bool
2075-
valueContainsDenotation = Value.valueContains
2075+
let valueContainsDenotation :: LogValueOuterOrMaxInner -> ValueTotalSize -> Bool
2076+
valueContainsDenotation (LogValueOuterOrMaxInner v1) (ValueTotalSize v2) =
2077+
Value.valueContains v1 v2
20762078
{-# INLINE valueContainsDenotation #-}
20772079
in makeBuiltinMeaning
20782080
valueContainsDenotation

plutus-core/plutus-core/src/PlutusCore/Default/Universe.hs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ import PlutusCore.Crypto.BLS12_381.G2 qualified as BLS12_381.G2
5252
import PlutusCore.Crypto.BLS12_381.Pairing qualified as BLS12_381.Pairing
5353
import PlutusCore.Data (Data)
5454
import PlutusCore.Evaluation.Machine.ExMemoryUsage (IntegerCostedLiterally (..),
55-
NumBytesCostedAsNumWords (..))
55+
LogValueOuterOrMaxInner (..),
56+
NumBytesCostedAsNumWords (..),
57+
ValueTotalSize (..))
5658
import PlutusCore.Pretty.Extra (juxtRenderContext)
5759
import PlutusCore.Value (Value)
5860

@@ -566,6 +568,28 @@ instance KnownBuiltinTypeIn DefaultUni term Integer =>
566568
readKnown = readKnownCoerce @Integer
567569
{-# INLINE readKnown #-}
568570

571+
deriving newtype instance
572+
KnownTypeAst tyname DefaultUni ValueTotalSize
573+
instance KnownBuiltinTypeIn DefaultUni term Value =>
574+
MakeKnownIn DefaultUni term ValueTotalSize where
575+
makeKnown = makeKnownCoerce @Value
576+
{-# INLINE makeKnown #-}
577+
instance KnownBuiltinTypeIn DefaultUni term Value =>
578+
ReadKnownIn DefaultUni term ValueTotalSize where
579+
readKnown = readKnownCoerce @Value
580+
{-# INLINE readKnown #-}
581+
582+
deriving newtype instance
583+
KnownTypeAst tyname DefaultUni LogValueOuterOrMaxInner
584+
instance KnownBuiltinTypeIn DefaultUni term Value =>
585+
MakeKnownIn DefaultUni term LogValueOuterOrMaxInner where
586+
makeKnown = makeKnownCoerce @Value
587+
{-# INLINE makeKnown #-}
588+
instance KnownBuiltinTypeIn DefaultUni term Value =>
589+
ReadKnownIn DefaultUni term LogValueOuterOrMaxInner where
590+
readKnown = readKnownCoerce @Value
591+
{-# INLINE readKnown #-}
592+
569593
deriving via AsInteger Natural instance
570594
KnownTypeAst tyname DefaultUni Natural
571595
instance KnownBuiltinTypeIn DefaultUni term Integer =>

plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/ExMemoryUsage.hs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ module PlutusCore.Evaluation.Machine.ExMemoryUsage
1515
, ValueTotalSize(..)
1616
, ValueOuterOrMaxInner(..)
1717
, Logarithmic(..)
18+
, LogValueOuterOrMaxInner(..)
1819
) where
1920

2021
import PlutusCore.Crypto.BLS12_381.G1 as BLS12_381.G1
@@ -415,6 +416,25 @@ instance ExMemoryUsage n => ExMemoryUsage (Logarithmic n) where
415416
in singletonRose $ max 1 (fromIntegral (logSize + 1))
416417
{-# INLINE memoryUsage #-}
417418

419+
{-| A combined wrapper for Value that measures size using outer/max inner map sizes
420+
with logarithmic transformation. This is equivalent to @Logarithmic ValueOuterOrMaxInner@
421+
but defined as a single newtype for simpler type instances and better error messages.
422+
423+
Used for builtins like lookupCoin and valueContains where the cost depends on
424+
O(log max(m, k)) where m is the number of policies and k is the max tokens per policy.
425+
426+
If this is used to wrap an argument in the denotation of a builtin then it *MUST* also
427+
be used to wrap the same argument in the relevant budgeting benchmark.
428+
-}
429+
newtype LogValueOuterOrMaxInner = LogValueOuterOrMaxInner { unLogValueOuterOrMaxInner :: Value }
430+
431+
instance ExMemoryUsage LogValueOuterOrMaxInner where
432+
memoryUsage (LogValueOuterOrMaxInner v) =
433+
let size = Map.size (Value.unpack v) `max` Value.maxInnerSize v
434+
logSize = integerLog2 (toInteger size)
435+
in singletonRose $ max 1 (fromIntegral (logSize + 1))
436+
{-# INLINE memoryUsage #-}
437+
418438
{- Note [Costing constant-size types]
419439
The memory usage of each of the BLS12-381 types is constant, so we may be able
420440
to optimise things a little by ensuring that we don't re-compute the size of

0 commit comments

Comments
 (0)