Skip to content
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

[Builtins] Inline SatInt stuff and costing monoids #5062

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion plutus-benchmark/ed25519-throughput/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import Cardano.Crypto.Seed (mkSeedFromBytes)
import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Data.ByteString.Hash qualified as Hash
import Data.SatInt
import Flat qualified
import Hedgehog.Internal.Gen qualified as G
import Hedgehog.Internal.Range qualified as R
Expand Down Expand Up @@ -188,7 +189,7 @@ evaluate (UPLC.Program _ _ prog) =
(_res, Cek.TallyingSt _ budget, _logs) ->
let ExCPU cpu = exBudgetCPU budget
ExMemory mem = exBudgetMemory budget
in (fromIntegral cpu, fromIntegral mem)
in (fromIntegral $ unSatInt cpu, fromIntegral $ unSatInt mem)

-- | Evaluate a script and print out the serialised size and the CPU and memory
-- usage, both as absolute values and percentages of the maxima specified in the
Expand Down
6 changes: 4 additions & 2 deletions plutus-benchmark/lists/exe/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Text.Printf (printf)
import PlutusBenchmark.Common (Term)
import PlutusBenchmark.Lists.Sort

import Data.SatInt
import PlutusCore qualified as PLC
import PlutusCore.Evaluation.Machine.ExBudget (ExBudget (..))
import PlutusCore.Evaluation.Machine.ExBudgetingDefaults qualified as PLC
Expand All @@ -22,7 +23,8 @@ getBudgetUsage :: Term -> Maybe Integer
getBudgetUsage term =
case (\ (fstT,sndT,_) -> (fstT,sndT) ) $ Cek.runCekDeBruijn PLC.defaultCekParameters Cek.counting Cek.noEmitter term of
(Left _, _) -> Nothing
(Right _, Cek.CountingSt c) -> let ExCPU cpu = exBudgetCPU c in Just $ fromIntegral cpu
(Right _, Cek.CountingSt c) ->
let ExCPU cpu = exBudgetCPU c in Just $ fromIntegral (unSatInt cpu)

getCekSteps :: Term -> Maybe Integer
getCekSteps term =
Expand All @@ -31,7 +33,7 @@ getCekSteps term =
(Right _, Cek.TallyingSt (Cek.CekExTally counts) _) ->
let getCount k =
case H.lookup k counts of
Just v -> let ExCPU n = exBudgetCPU v in fromIntegral n
Just v -> let ExCPU n = exBudgetCPU v in fromIntegral (unSatInt n)
Nothing -> 0
allNodeTags = fmap Cek.BStep [Cek.BConst, Cek.BVar, Cek.BLamAbs, Cek.BApply, Cek.BDelay, Cek.BForce, Cek.BBuiltin]
totalComputeSteps = sum $ map getCount allNodeTags
Expand Down
3 changes: 2 additions & 1 deletion plutus-benchmark/nofib/exe/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Control.Monad ()
import Control.Monad.Trans.Except (runExceptT)
import Data.ByteString qualified as BS
import Data.Char (isSpace)
import Data.SatInt
import Flat qualified
import Options.Applicative as Opt hiding (action)
import System.Exit (exitFailure)
Expand Down Expand Up @@ -249,7 +250,7 @@ measureBudget compiledCode =
let (_, UPLC.TallyingSt _ budget) = UPLC.runCekNoEmit PLC.defaultCekParameters UPLC.tallying $ program ^. UPLC.progTerm
ExCPU cpu = exBudgetCPU budget
ExMemory mem = exBudgetMemory budget
in (Hs.fromIntegral cpu, Hs.fromIntegral mem)
in (Hs.fromIntegral (unSatInt cpu), Hs.fromIntegral (unSatInt mem))

getInfo :: (Hs.String, CompiledCode a) -> (Hs.String, Integer, Integer, Integer)
getInfo (name, code) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import Data.Coerce (coerce)
import Data.Csv (FromNamedRecord, FromRecord, HasHeader (HasHeader), decode, parseNamedRecord, (.:))
import Data.Either.Extra (maybeToEither)
import Data.Functor.Compose (Compose (Compose))
import Data.SatInt
import Data.Text (Text)
import Data.Text.Encoding qualified as T (encodeUtf8)
import Data.Vector (Vector, find)
Expand All @@ -33,7 +34,7 @@ import Language.R.QQ (r)
-- | Convert microseconds represented as a float to picoseconds represented as a
-- CostingInteger. We round up to be sure we don't underestimate anything.
microToPico :: Double -> CostingInteger
microToPico = ceiling . (1e6 *)
microToPico = toSatInt . ceiling . (1e6 *)

{- See CostModelGeneration.md for a description of what this does. -}

Expand Down
35 changes: 18 additions & 17 deletions plutus-core/cost-model/test/TestCostModels.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import TH
import Control.Applicative (Const, getConst)
import Control.Monad.Morph (MFunctor, hoist, lift)
import Data.Coerce (coerce)
import Data.SatInt
import Data.String (fromString)
import Unsafe.Coerce (unsafeCoerce)

Expand Down Expand Up @@ -77,8 +78,8 @@ numberOfTests = 100
memUsageGen :: Gen CostingInteger
memUsageGen =
Gen.choice [small, large]
where small = Gen.integral (Range.constant 0 2)
large = Gen.integral (Range.linear 0 5000)
where small = toSatInt <$> Gen.integral (Range.constant 0 2)
large = toSatInt <$> Gen.integral (Range.linear 0 5000)

-- A type alias to make our signatures more concise. This type is a record in
-- which every field refers to an R SEXP (over some state s), the lm model for
Expand All @@ -96,12 +97,12 @@ data TestDomain
| BelowDiagonal

-- Approximate equality
(~=) :: Integral a => a -> a -> Bool
(~=) :: CostingInteger -> CostingInteger -> Bool
x ~= y
| x==0 && y==0 = True
| otherwise = err < 1/100
where x' = fromIntegral x :: Double
y' = fromIntegral y :: Double
where x' = fromIntegral (unSatInt x) :: Double
y' = fromIntegral (unSatInt y) :: Double
err = abs ((x'-y')/y')

-- Runs property tests in the `R` Monad.
Expand Down Expand Up @@ -158,7 +159,7 @@ testPredictOne haskellModelFun modelR1 = propertyR $ do
predictR :: MonadR m => CostingInteger -> m CostingInteger
predictR x =
let
xD = fromIntegral x :: Double
xD = fromIntegral (unSatInt x) :: Double
in
microToPico . fromSomeSEXP <$> [r|predict(modelR_hs, data.frame(x_mem=xD_hs))[[1]]|]
predictH :: CostingInteger -> CostingInteger
Expand All @@ -182,8 +183,8 @@ testPredictTwo haskellModelFun modelR1 domain = propertyR $ do
predictR :: MonadR m => CostingInteger -> CostingInteger -> m CostingInteger
predictR x y =
let
xD = fromIntegral x :: Double
yD = fromIntegral y :: Double
xD = fromIntegral (unSatInt x) :: Double
yD = fromIntegral (unSatInt y) :: Double
in
microToPico . fromSomeSEXP <$> [r|predict(modelR_hs, data.frame(x_mem=xD_hs, y_mem=yD_hs))[[1]]|]
predictH :: CostingInteger -> CostingInteger -> CostingInteger
Expand All @@ -209,9 +210,9 @@ testPredictThree haskellModelFun modelR1 = propertyR $ do
predictR :: MonadR m => CostingInteger -> CostingInteger -> CostingInteger -> m CostingInteger
predictR x y z =
let
xD = fromIntegral x :: Double
yD = fromIntegral y :: Double
zD = fromIntegral z :: Double
xD = fromIntegral (unSatInt x) :: Double
yD = fromIntegral (unSatInt y) :: Double
zD = fromIntegral (unSatInt z) :: Double
in
microToPico . fromSomeSEXP <$> [r|predict(modelR_hs, data.frame(x_mem=xD_hs, y_mem=yD_hs, z_mem=zD_hs))[[1]]|]
predictH :: CostingInteger -> CostingInteger -> CostingInteger -> CostingInteger
Expand All @@ -235,12 +236,12 @@ testPredictSix haskellModelFun modelR1 = propertyR $ do
-> CostingInteger -> CostingInteger -> CostingInteger -> m CostingInteger
predictR x y z u v w =
let
xD = fromIntegral x :: Double
yD = fromIntegral y :: Double
zD = fromIntegral z :: Double
uD = fromIntegral u :: Double
vD = fromIntegral v :: Double
wD = fromIntegral w :: Double
xD = fromIntegral (unSatInt x) :: Double
yD = fromIntegral (unSatInt y) :: Double
zD = fromIntegral (unSatInt z) :: Double
uD = fromIntegral (unSatInt u) :: Double
vD = fromIntegral (unSatInt v) :: Double
wD = fromIntegral (unSatInt w) :: Double
in
microToPico . fromSomeSEXP <$> [r|predict(modelR_hs, data.frame(x_mem=xD_hs, y_mem=yD_hs, z_mem=zD_hs,
u_mem=uD_hs, v_mem=vD_hs, w_mem=wD_hs))[[1]]|]
Expand Down
3 changes: 2 additions & 1 deletion plutus-core/executables/src/PlutusCore/Executable/Common.hs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import Data.List (intercalate, nub)
import Data.List qualified as List
import Data.Maybe (fromJust)
import Data.Proxy (Proxy (..))
import Data.SatInt
import Data.Text qualified as T
import Data.Text.IO qualified as T
import Flat (Flat, flat, unflat)
Expand Down Expand Up @@ -242,7 +243,7 @@ printBudgetStateTally term model (Cek.CekExTally costs) = do
builtinCosts = mconcat (map snd builtinsAndCosts)
-- \^ Total builtin evaluation time (according to the models) in picoseconds
-- (units depend on BuiltinCostModel.costMultiplier)
getCPU b = let ExCPU b' = exBudgetCPU b in fromIntegral b' :: Double
getCPU b = let ExCPU b' = exBudgetCPU b in fromIntegral (unSatInt b') :: Double
totalCost = getSpent Cek.BStartup <> totalComputeCost <> builtinCosts
totalTime =
(getCPU $ getSpent Cek.BStartup) + getCPU totalComputeCost + getCPU builtinCosts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ data ExBudget = ExBudget { exBudgetCPU :: ExCPU, exBudgetMemory :: ExMemory }
-- | Subract one 'ExBudget' from another. Does not guarantee that the result is positive.
minusExBudget :: ExBudget -> ExBudget -> ExBudget
minusExBudget (ExBudget c1 m1) (ExBudget c2 m2) = ExBudget (c1-c2) (m1-m2)
{-# INLINE minusExBudget #-}

-- These functions are performance critical, so we can't use GenericSemigroupMonoid, and we insist that they be inlined.
instance Semigroup ExBudget where
Expand All @@ -195,6 +196,7 @@ instance Semigroup ExBudget where

instance Monoid ExBudget where
mempty = ExBudget mempty mempty
{-# INLINE mempty #-}

instance Pretty ExBudget where
pretty (ExBudget cpu memory) = parens $ braces $ vsep
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import PlutusCore.Pretty
import PlutusPrelude

import Codec.Serialise (Serialise)
import Control.Monad.RWS.Strict
import Data.Aeson
import Data.ByteString qualified as BS
import Data.Proxy
Expand Down Expand Up @@ -105,29 +104,43 @@ type CostingInteger = SatInt
newtype ExMemory = ExMemory CostingInteger
deriving stock (Eq, Ord, Show, Generic, Lift)
deriving newtype (Num, NFData, Read, Bounded)
deriving (Semigroup, Monoid) via (Sum CostingInteger)
deriving (FromJSON, ToJSON) via CostingInteger
deriving Serialise via CostingInteger
deriving anyclass NoThunks
instance Pretty ExMemory where
pretty (ExMemory i) = pretty (toInteger i)
pretty (ExMemory i) = pretty (unSatInt i)
instance PrettyBy config ExMemory where
prettyBy _ m = pretty m

instance Semigroup ExMemory where
(<>) = coerce $ (+) @CostingInteger
{-# INLINE (<>) #-}

instance Monoid ExMemory where
mempty = coerce (0 :: CostingInteger)
{-# INLINE mempty #-}

-- | Counts CPU units in picoseconds: maximum value for SatInt is 2^63 ps, or
-- appproximately 106 days.
newtype ExCPU = ExCPU CostingInteger
deriving stock (Eq, Ord, Show, Generic, Lift)
deriving newtype (Num, NFData, Read, Bounded)
deriving (Semigroup, Monoid) via (Sum CostingInteger)
deriving (FromJSON, ToJSON) via CostingInteger
deriving Serialise via CostingInteger
deriving anyclass NoThunks
instance Pretty ExCPU where
pretty (ExCPU i) = pretty (toInteger i)
pretty (ExCPU i) = pretty (unSatInt i)
instance PrettyBy config ExCPU where
prettyBy _ m = pretty m

instance Semigroup ExCPU where
(<>) = coerce $ (+) @CostingInteger
{-# INLINE (<>) #-}

instance Monoid ExCPU where
mempty = coerce (0 :: CostingInteger)
{-# INLINE mempty #-}

{- Note [ExMemoryUsage instances for non-constants]
In order to calculate the cost of a built-in function we need to feed the 'ExMemory' of each
argument to the costing function associated with the builtin. For a polymorphic builtin this means
Expand Down Expand Up @@ -214,8 +227,8 @@ instance ExMemoryUsage Word8 where
1 + (toInteger $ BS.length bs) `div` 8, which would count one extra for
things whose sizes are multiples of 8. -}
instance ExMemoryUsage BS.ByteString where
memoryUsage bs = ExMemory $ ((n-1) `quot` 8) + 1 -- Don't use `div` here! That gives 1 instead of 0 for n=0.
where n = fromIntegral $ BS.length bs :: SatInt
-- Don't use `div` here! That gives 1 instead of 0 for n=0.
memoryUsage bs = ExMemory . toSatInt $ ((BS.length bs - 1) `quot` 8) + 1
{-# INLINE memoryUsage #-}

instance ExMemoryUsage T.Text where
Expand Down
Loading