Skip to content

Commit

Permalink
Bypass builtins costing
Browse files Browse the repository at this point in the history
  • Loading branch information
effectfully committed Jan 30, 2025
1 parent 506626a commit fa4ce4c
Show file tree
Hide file tree
Showing 9 changed files with 22 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,10 @@ instance (ToBuiltinMeaning uni fun1, ToBuiltinMeaning uni fun2
PairV (BuiltinSemanticsVariant fun1) (BuiltinSemanticsVariant fun2)
toBuiltinMeaning (PairV semvarL _) (Left fun) = case toBuiltinMeaning semvarL fun of
BuiltinMeaning tySch toF denot ->
BuiltinMeaning tySch toF (denot . fst)
BuiltinMeaning tySch toF denot
toBuiltinMeaning (PairV _ semvarR) (Right fun) = case toBuiltinMeaning semvarR fun of
BuiltinMeaning tySch toF denot ->
BuiltinMeaning tySch toF (denot . snd)
BuiltinMeaning tySch toF denot

instance (Default (BuiltinSemanticsVariant fun1), Default (BuiltinSemanticsVariant fun2))
=> Default (BuiltinSemanticsVariant (Either fun1 fun2)) where
Expand Down
24 changes: 10 additions & 14 deletions plutus-core/plutus-core/src/PlutusCore/Builtin/Meaning.hs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ data BuiltinMeaning val cost =
forall args res. BuiltinMeaning
(TypeScheme val args res)
~(FoldArgs args res)
(cost -> BuiltinRuntime val)
(BuiltinRuntime val)

-- | Constraints available when defining a built-in function.
type HasMeaningIn uni val = (Typeable val, ExMemoryUsage val, HasConstantIn uni val)
Expand Down Expand Up @@ -232,7 +232,7 @@ class KnownMonotype val args res where
-- passing the action returning the builtin application around until full saturation, which is
-- when the action actually gets run.
toMonoF
:: ReadKnownM (FoldArgs args res, FoldArgs args ExBudgetStream)
:: ReadKnownM (FoldArgs args res)
-> BuiltinRuntime val

-- | Once we've run out of term-level arguments, we return a
Expand All @@ -256,7 +256,7 @@ instance (Typeable res, KnownTypeAst TyName (UniOf val) res, MakeKnown val res)
-- computation inside, but that would slow things down a bit and the current strategy is
-- reasonable enough.
builtinRuntimeFailure
(\(x, cost) -> BuiltinCostedResult cost $ makeKnown x)
(\x -> BuiltinCostedResult $ makeKnown x)
{-# INLINE toMonoF #-}

{- Note [One-shotting runtime denotations]
Expand Down Expand Up @@ -317,15 +317,13 @@ instance
-- no benefit from having caching as the builtin application is going to be computed only
-- once. So we choose the "call-by-name" behavior and 'oneShot' is what enables that.
oneShot (toMonoF @val @args @res) $ do
(f, exF) <- getBoth
f <- getBoth
-- Force the argument that gets passed to the denotation. This seems to help performance
-- a bit (possibly due to its impact on strictness analysis), plus this way we ensure
-- that if computing the argument throws an exception (isn't supposed to happen), we'll
-- catch it in tests.
!x <- readKnown arg
-- See Note [Strict application in runtime denotations].
let !exY = exF x
pure (f x, exY)
pure (f x)
{-# INLINE toMonoF #-}

-- | A class that allows us to derive a polytype for a builtin.
Expand All @@ -337,7 +335,7 @@ class KnownMonotype val args res => KnownPolytype (binds :: [Some TyNameRep]) va
-- passing the action returning the builtin application around until full saturation, which is
-- when the action actually gets run.
toPolyF
:: ReadKnownM (FoldArgs args res, FoldArgs args ExBudgetStream)
:: ReadKnownM (FoldArgs args res)
-> BuiltinRuntime val

-- | Once we've run out of type-level arguments, we start handling term-level ones.
Expand Down Expand Up @@ -401,23 +399,21 @@ instance
, ThrowOnBothEmpty binds args (IsBuiltin uni a) a
, ElaborateFromTo uni 0 j val a, KnownPolytype binds val args res
) => MakeBuiltinMeaning a val where
makeBuiltinMeaning f toExF =
BuiltinMeaning (knownPolytype @binds @val @args @res) f $ \cost ->
makeBuiltinMeaning f _ =
BuiltinMeaning (knownPolytype @binds @val @args @res) f $
-- In order to make the 'BuiltinRuntime' of a builtin cacheable we need to tell GHC to
-- create a thunk for it, which we achieve by applying 'lazy' to the 'BuiltinRuntime'
-- here.
--
-- Those thunks however require a lot of care to be properly shared rather than
-- recreated every time a builtin application is evaluated, see 'toBuiltinsRuntime' for
-- how we sort it out.
lazy $ case toExF cost of
-- See Note [Optimizations of runCostingFun*] for why we use strict @case@.
!exF -> toPolyF @binds @val @args @res $ pure (f, exF)
lazy $ toPolyF @binds @val @args @res $ pure f
{-# INLINE makeBuiltinMeaning #-}

-- | Convert a 'BuiltinMeaning' to a 'BuiltinRuntime' given a cost model.
toBuiltinRuntime :: cost -> BuiltinMeaning val cost -> BuiltinRuntime val
toBuiltinRuntime cost (BuiltinMeaning _ _ denot) = denot cost
toBuiltinRuntime _ (BuiltinMeaning _ _ denot) = denot
{-# INLINE toBuiltinRuntime #-}

-- See Note [Inlining meanings of builtins].
Expand Down
7 changes: 3 additions & 4 deletions plutus-core/plutus-core/src/PlutusCore/Builtin/Runtime.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ module PlutusCore.Builtin.Runtime where
import PlutusPrelude

import PlutusCore.Builtin.KnownType
import PlutusCore.Evaluation.Machine.ExBudgetStream

import Control.DeepSeq
import Control.Monad.Except (throwError)
Expand All @@ -30,7 +29,7 @@ import NoThunks.Class
-- Evaluators that ignore the entire concept of costing (e.g. the CK machine) may of course force
-- the result of the builtin application unconditionally.
data BuiltinRuntime val
= BuiltinCostedResult ExBudgetStream ~(BuiltinResult (HeadSpine val))
= BuiltinCostedResult ~(BuiltinResult (HeadSpine val))
| BuiltinExpectArgument (val -> BuiltinRuntime val)
| BuiltinExpectForce (BuiltinRuntime val)

Expand All @@ -40,7 +39,7 @@ instance NoThunks (BuiltinRuntime val) where
-- checks for WHNF without recursing. Hence we can throw if we reach this clause somehow.
-- TODO: remove the CPP when rest of IOE moves to nothunks>=0.2
#if MIN_VERSION_nothunks(0,2,0)
BuiltinCostedResult _ _ -> pure . Just . ThunkInfo $ Left ctx
BuiltinCostedResult _ -> pure . Just . ThunkInfo $ Left ctx
#else
-- Plutus has moved to nothunks>=0.2, but some other IOE repos are using nothunks<0.2.
-- As a consequence, cardano-constitution:create-json-envelope cannot be build.
Expand Down Expand Up @@ -88,7 +87,7 @@ instance (Bounded fun, Enum fun) => NoThunks (BuiltinsRuntime fun val) where
showTypeOf = const "PlutusCore.Builtin.Runtime.BuiltinsRuntime"

builtinRuntimeFailure :: BuiltinError -> BuiltinRuntime val
builtinRuntimeFailure = BuiltinCostedResult (ExBudgetLast mempty) . throwError
builtinRuntimeFailure = BuiltinCostedResult . throwError
-- See Note [INLINE and OPAQUE on error-related definitions].
{-# OPAQUE builtinRuntimeFailure #-}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ evalBuiltinApp
-> BuiltinRuntime (CkValue uni fun)
-> CkM uni fun s (Term TyName Name uni fun ())
evalBuiltinApp stack term runtime = case runtime of
BuiltinCostedResult _ getFXs -> case getFXs of
BuiltinCostedResult getFXs -> case getFXs of
BuiltinSuccess fXs -> returnCkHeadSpine stack fXs
BuiltinSuccessWithLogs logs fXs -> emitCkM logs *> returnCkHeadSpine stack fXs
BuiltinFailure logs err -> emitCkM logs *> throwBuiltinErrorWithCause term err
Expand Down
2 changes: 1 addition & 1 deletion plutus-core/plutus-core/test/CostModelSafety/Spec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ testCosts semvar runtimes bn =
runtime0 = lookupBuiltin bn runtimes

eval :: [Term] -> BuiltinRuntime Term -> ExBudget
eval [] (BuiltinCostedResult budgetStream _) = sumExBudgetStream budgetStream
eval [] (BuiltinCostedResult _) = mempty
eval (arg : args) (BuiltinExpectArgument toRuntime) =
eval args (toRuntime arg)
eval args (BuiltinExpectForce runtime) =
Expand Down
2 changes: 1 addition & 1 deletion plutus-core/plutus-core/test/Evaluation/Spec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ prop_builtinEvaluation runtimes bn mkGen f = property $ do
[Term uni fun] ->
BuiltinRuntime (Term uni fun) ->
BuiltinResult (HeadSpine (Term uni fun))
eval [] (BuiltinCostedResult _ getFxs) =
eval [] (BuiltinCostedResult getFxs) =
getFxs
eval (arg : args) (BuiltinExpectArgument toRuntime) =
eval args (toRuntime arg)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ evaluateBuiltins preserveLogging binfo costModel = transformOf termSubterms proc
:: BuiltinRuntime (Term tyname name uni fun ())
-> AppContext tyname name uni fun a
-> Maybe (Term tyname name uni fun ())
eval (BuiltinCostedResult _ getFXs) AppContextEnd =
eval (BuiltinCostedResult getFXs) AppContextEnd =
case getFXs of
BuiltinSuccess fXs -> Just $ headSpineToTerm fXs
-- Evaluates successfully, but does logging. If we're being conservative
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,7 @@ enterComputeCek = computeCek
-> BuiltinRuntime (CekValue uni fun ann)
-> CekM uni fun s (Term NamedDeBruijn uni fun ())
evalBuiltinApp ctx fun term runtime = case runtime of
BuiltinCostedResult _budgets0 getFXs -> do
BuiltinCostedResult getFXs -> do
case getFXs of
BuiltinSuccess fXs ->
returnCekHeadSpine ctx fXs
Expand Down Expand Up @@ -850,8 +850,7 @@ runCekDeBruijn
-> NTerm uni fun ann
-> (Either (CekEvaluationException NamedDeBruijn uni fun) (NTerm uni fun ()), cost, [Text])
runCekDeBruijn params mode emitMode term =
runCekM params mode emitMode $ do
unCekBudgetSpender ?cekBudgetSpender BStartup $ runIdentity $ cekStartupCost ?cekCosts
runCekM params mode emitMode $
enterComputeCek NoFrame Env.empty term

{- Note [Accumulators for terms]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ where
import PlutusCore.Builtin
import PlutusCore.DeBruijn
import PlutusCore.Evaluation.Machine.ExBudget
import PlutusCore.Evaluation.Machine.ExBudgetStream
import PlutusCore.Evaluation.Machine.Exception
import PlutusCore.Evaluation.Machine.MachineParameters
import PlutusCore.Evaluation.Result
Expand Down Expand Up @@ -462,12 +461,7 @@ evalBuiltinApp
-> BuiltinRuntime (CekValue uni fun ann)
-> CekM uni fun s (CekState uni fun ann)
evalBuiltinApp ann ctx fun term runtime = case runtime of
BuiltinCostedResult budgets0 getFXs -> do
let exCat = BBuiltinApp fun
spendBudgets (ExBudgetLast budget) = spendBudget exCat budget
spendBudgets (ExBudgetCons budget budgets) =
spendBudget exCat budget *> spendBudgets budgets
spendBudgets budgets0
BuiltinCostedResult getFXs -> do
case getFXs of
BuiltinSuccess fXs ->
returnCekHeadSpine ann ctx fXs
Expand Down

0 comments on commit fa4ce4c

Please sign in to comment.