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] Unlift both ways #4516

Merged
merged 18 commits into from
Apr 7, 2022
Merged

Conversation

effectfully
Copy link
Contributor

Don't look here yet.

@effectfully
Copy link
Contributor Author

/benchmark plutus-benchmark:validation

@iohk-devops
Copy link

Comparing benchmark results of 'plutus-benchmark:validation' on 'e59ade143' (base) and 'f07097902' (PR)

Script e59ade1 f070979 Change
auction_1-1 225.8 μs 211.3 μs -6.4%
auction_1-2 857.3 μs 838.9 μs -2.1%
auction_1-3 848.4 μs 827.8 μs -2.4%
auction_1-4 293.2 μs 272.7 μs -7.0%
auction_2-1 227.3 μs 213.0 μs -6.3%
auction_2-2 858.7 μs 840.1 μs -2.2%
auction_2-3 1.089 ms 1.065 ms -2.2%
auction_2-4 848.5 μs 826.6 μs -2.6%
auction_2-5 293.7 μs 271.3 μs -7.6%
crowdfunding-success-1 267.5 μs 248.2 μs -7.2%
crowdfunding-success-2 267.0 μs 248.0 μs -7.1%
crowdfunding-success-3 267.8 μs 248.7 μs -7.1%
currency-1 321.2 μs 310.2 μs -3.4%
escrow-redeem_1-1 465.3 μs 442.5 μs -4.9%
escrow-redeem_1-2 466.6 μs 442.6 μs -5.1%
escrow-redeem_2-1 545.5 μs 518.5 μs -4.9%
escrow-redeem_2-2 545.3 μs 519.1 μs -4.8%
escrow-redeem_2-3 544.9 μs 521.1 μs -4.4%
escrow-refund-1 199.9 μs 188.1 μs -5.9%
future-increase-margin-1 321.0 μs 310.6 μs -3.2%
future-increase-margin-2 720.5 μs 701.8 μs -2.6%
future-increase-margin-3 719.5 μs 700.1 μs -2.7%
future-increase-margin-4 674.4 μs 648.1 μs -3.9%
future-increase-margin-5 1.052 ms 1.033 ms -1.8%
future-pay-out-1 320.0 μs 309.4 μs -3.3%
future-pay-out-2 721.7 μs 698.5 μs -3.2%
future-pay-out-3 722.0 μs 698.8 μs -3.2%
future-pay-out-4 1.051 ms 1.031 ms -1.9%
future-settle-early-1 321.5 μs 308.9 μs -3.9%
future-settle-early-2 722.0 μs 699.9 μs -3.1%
future-settle-early-3 721.7 μs 699.8 μs -3.0%
future-settle-early-4 805.2 μs 786.5 μs -2.3%
game-sm-success_1-1 523.6 μs 498.6 μs -4.8%
game-sm-success_1-2 248.8 μs 233.5 μs -6.1%
game-sm-success_1-3 848.5 μs 830.4 μs -2.1%
game-sm-success_1-4 289.4 μs 271.3 μs -6.3%
game-sm-success_2-1 526.3 μs 498.3 μs -5.3%
game-sm-success_2-2 249.1 μs 232.6 μs -6.6%
game-sm-success_2-3 848.7 μs 827.4 μs -2.5%
game-sm-success_2-4 288.5 μs 269.9 μs -6.4%
game-sm-success_2-5 846.8 μs 826.1 μs -2.4%
game-sm-success_2-6 289.3 μs 270.6 μs -6.5%
multisig-sm-1 536.3 μs 515.0 μs -4.0%
multisig-sm-2 526.1 μs 502.5 μs -4.5%
multisig-sm-3 531.9 μs 509.0 μs -4.3%
multisig-sm-4 537.8 μs 514.4 μs -4.4%
multisig-sm-5 753.0 μs 734.1 μs -2.5%
multisig-sm-6 536.0 μs 514.4 μs -4.0%
multisig-sm-7 524.6 μs 501.9 μs -4.3%
multisig-sm-8 531.2 μs 508.1 μs -4.3%
multisig-sm-9 538.0 μs 516.5 μs -4.0%
multisig-sm-10 754.5 μs 736.3 μs -2.4%
ping-pong-1 441.7 μs 422.2 μs -4.4%
ping-pong-2 441.5 μs 421.0 μs -4.6%
ping-pong_2-1 263.3 μs 247.5 μs -6.0%
prism-1 209.7 μs 190.8 μs -9.0%
prism-2 568.2 μs 539.1 μs -5.1%
prism-3 480.9 μs 455.2 μs -5.3%
pubkey-1 175.5 μs 162.8 μs -7.2%
stablecoin_1-1 1.174 ms 1.135 ms -3.3%
stablecoin_1-2 242.4 μs 226.9 μs -6.4%
stablecoin_1-3 1.344 ms 1.300 ms -3.3%
stablecoin_1-4 257.3 μs 240.3 μs -6.6%
stablecoin_1-5 1.692 ms 1.630 ms -3.7%
stablecoin_1-6 321.1 μs 299.1 μs -6.9%
stablecoin_2-1 1.178 ms 1.142 ms -3.1%
stablecoin_2-2 243.9 μs 226.6 μs -7.1%
stablecoin_2-3 1.345 ms 1.298 ms -3.5%
stablecoin_2-4 258.4 μs 239.8 μs -7.2%
token-account-1 243.2 μs 231.3 μs -4.9%
token-account-2 430.2 μs 412.8 μs -4.0%
uniswap-1 535.8 μs 523.5 μs -2.3%
uniswap-2 288.6 μs 273.0 μs -5.4%
uniswap-3 2.188 ms 2.093 ms -4.3%
uniswap-4 434.4 μs 399.5 μs -8.0%
uniswap-5 1.507 ms 1.437 ms -4.6%
uniswap-6 415.6 μs 382.6 μs -7.9%
vesting-1 461.8 μs 442.0 μs -4.3%

@effectfully
Copy link
Contributor Author

/benchmark plutus-benchmark:validation

@iohk-devops
Copy link

Comparing benchmark results of 'plutus-benchmark:validation' on 'e59ade143' (base) and '50d93e7a6' (PR)

Script e59ade1 50d93e7 Change
auction_1-1 227.1 μs 206.9 μs -8.9%
auction_1-2 860.8 μs 828.3 μs -3.8%
auction_1-3 849.7 μs 819.5 μs -3.6%
auction_1-4 293.9 μs 268.0 μs -8.8%
auction_2-1 227.6 μs 209.8 μs -7.8%
auction_2-2 859.1 μs 830.3 μs -3.4%
auction_2-3 1.090 ms 1.054 ms -3.3%
auction_2-4 847.5 μs 819.9 μs -3.3%
auction_2-5 294.6 μs 268.1 μs -9.0%
crowdfunding-success-1 267.9 μs 246.0 μs -8.2%
crowdfunding-success-2 267.2 μs 246.3 μs -7.8%
crowdfunding-success-3 267.5 μs 245.4 μs -8.3%
currency-1 321.4 μs 306.5 μs -4.6%
escrow-redeem_1-1 464.5 μs 435.5 μs -6.2%
escrow-redeem_1-2 465.2 μs 436.2 μs -6.2%
escrow-redeem_2-1 545.0 μs 512.3 μs -6.0%
escrow-redeem_2-2 547.8 μs 511.0 μs -6.7%
escrow-redeem_2-3 547.2 μs 511.3 μs -6.6%
escrow-refund-1 200.5 μs 184.9 μs -7.8%
future-increase-margin-1 321.8 μs 306.2 μs -4.8%
future-increase-margin-2 725.7 μs 690.3 μs -4.9%
future-increase-margin-3 723.9 μs 689.9 μs -4.7%
future-increase-margin-4 676.7 μs 643.6 μs -4.9%
future-increase-margin-5 1.054 ms 1.021 ms -3.1%
future-pay-out-1 321.8 μs 306.3 μs -4.8%
future-pay-out-2 721.8 μs 691.0 μs -4.3%
future-pay-out-3 720.6 μs 692.2 μs -3.9%
future-pay-out-4 1.049 ms 1.028 ms -2.0%
future-settle-early-1 320.6 μs 306.9 μs -4.3%
future-settle-early-2 720.8 μs 691.1 μs -4.1%
future-settle-early-3 724.7 μs 691.7 μs -4.6%
future-settle-early-4 809.1 μs 778.7 μs -3.8%
game-sm-success_1-1 524.8 μs 494.7 μs -5.7%
game-sm-success_1-2 249.6 μs 228.0 μs -8.7%
game-sm-success_1-3 845.9 μs 818.3 μs -3.3%
game-sm-success_1-4 289.3 μs 266.4 μs -7.9%
game-sm-success_2-1 526.9 μs 493.2 μs -6.4%
game-sm-success_2-2 249.4 μs 227.1 μs -8.9%
game-sm-success_2-3 852.3 μs 817.4 μs -4.1%
game-sm-success_2-4 288.9 μs 265.8 μs -8.0%
game-sm-success_2-5 846.3 μs 818.6 μs -3.3%
game-sm-success_2-6 288.8 μs 265.3 μs -8.1%
multisig-sm-1 535.6 μs 512.8 μs -4.3%
multisig-sm-2 525.0 μs 499.4 μs -4.9%
multisig-sm-3 530.9 μs 506.6 μs -4.6%
multisig-sm-4 536.9 μs 510.6 μs -4.9%
multisig-sm-5 753.7 μs 727.4 μs -3.5%
multisig-sm-6 536.7 μs 510.9 μs -4.8%
multisig-sm-7 524.9 μs 499.1 μs -4.9%
multisig-sm-8 531.4 μs 504.6 μs -5.0%
multisig-sm-9 537.0 μs 508.8 μs -5.3%
multisig-sm-10 751.8 μs 731.6 μs -2.7%
ping-pong-1 440.3 μs 419.5 μs -4.7%
ping-pong-2 441.2 μs 419.0 μs -5.0%
ping-pong_2-1 264.3 μs 247.0 μs -6.5%
prism-1 209.3 μs 189.3 μs -9.6%
prism-2 568.8 μs 535.1 μs -5.9%
prism-3 482.6 μs 449.1 μs -6.9%
pubkey-1 176.0 μs 162.2 μs -7.8%
stablecoin_1-1 1.178 ms 1.130 ms -4.1%
stablecoin_1-2 242.7 μs 222.9 μs -8.2%
stablecoin_1-3 1.343 ms 1.285 ms -4.3%
stablecoin_1-4 258.6 μs 235.3 μs -9.0%
stablecoin_1-5 1.687 ms 1.610 ms -4.6%
stablecoin_1-6 320.5 μs 294.6 μs -8.1%
stablecoin_2-1 1.176 ms 1.131 ms -3.8%
stablecoin_2-2 243.1 μs 222.2 μs -8.6%
stablecoin_2-3 1.348 ms 1.289 ms -4.4%
stablecoin_2-4 258.6 μs 236.8 μs -8.4%
token-account-1 243.1 μs 229.3 μs -5.7%
token-account-2 430.5 μs 408.3 μs -5.2%
uniswap-1 535.4 μs 516.4 μs -3.5%
uniswap-2 288.2 μs 270.1 μs -6.3%
uniswap-3 2.186 ms 2.063 ms -5.6%
uniswap-4 435.6 μs 392.5 μs -9.9%
uniswap-5 1.514 ms 1.421 ms -6.1%
uniswap-6 417.6 μs 378.1 μs -9.5%
vesting-1 461.3 μs 438.9 μs -4.9%

@effectfully
Copy link
Contributor Author

effectfully commented Apr 2, 2022

@michaelpj this adds customizable unlifting and propagates it all the way up to EvaluationContext. The old immediate unlifting gets faster by 4.59% and the new deferred unlifting is faster than master by 5.77%. We're practically inlining readKnown and makeKnown here without storing them in any data type, which is probably what causes the speedup. It is beneficial to do unlifting in the same place where the value is used, more opportunities for inlining, worker-wrapping etc.

mkEvaluationContext now takes an UnliftingMode and dispatches on it. However I noticed that validation benchmarks don't really use that, they just reach straight for defaultCekParameters IIUC. validation-full on other hand uses evalCtxForTesting, which is something that I don't understand at all, because that one seems to use mempty as CostModelParams, which I assume is not what happens on the chain.

I'm now very confused: I don't know how an EvaluationContext is created and handled by the ledger people and I don't understand how our validation-full benchmarks are even representative and how to incorporate the two ways of doing unlifting into the validation benchmarks (like, what would that even mean? Benchmarking everything twice? Hardcoding only the favorite way and ignoring the other one?).

I still need to polish the code and document it, but I once I do that, could you take if from there?

Copy link
Contributor

@michaelpj michaelpj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Needs a little documentation, and I made some suggestions for what to do in the EvaluationContext module. I think @bezirg can fix that up afterwards.

@@ -245,10 +227,10 @@ class uni ~ UniOf val => MakeKnownIn uni val a where
-- See Note [Cause of failure].
-- | Convert a Haskell value to the corresponding PLC val.
-- The inverse of 'readKnown'.
makeKnown :: Maybe cause -> a -> ExceptT (ErrorWithCause MakeKnownError cause) Emitter val
makeKnown :: Maybe cause -> a -> ExceptT (ErrorWithCause ReadKnownError cause) Emitter val
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems weird. Why does makeKnown throw a ReadKnownError? If we're just not distinguishing them any more, let's give it a better name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because readKnown is now deferred to the same place where makeKnown happens. I'll change the name.

plutus-core/plutus-core/src/PlutusCore/Builtin/Meaning.hs Outdated Show resolved Hide resolved
plutus-core/plutus-core/src/PlutusCore/Builtin/Runtime.hs Outdated Show resolved Hide resolved
plutus-core/plutus-core/src/PlutusCore/Builtin/Runtime.hs Outdated Show resolved Hide resolved
-> Maybe EvaluationContext
mkEvaluationContext newCMP =
EvaluationContext . inline Plutus.mkMachineParameters <$> Plutus.applyCostModelParams Plutus.defaultCekCostModel newCMP
mkEvaluationContextUnliftingImmediate :: Plutus.CostModelParams -> Maybe EvaluationContext
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This distinction isn't the ledger team's problem, rather we will make the decision based on the protocol version and the language version. So this function would need to take a protocol version - I'll check that that's okay with the ledger team.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, I think just put this back the way it was and pass defaultUnliftingMode and we (i.e. @nikos ;) ) will sort it out afterwards.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, I realised from asking Jared about it that probably what we should do for now is this:

  • Put both the deferred and the immediate unlifting versions into the EvaluationContext
  • Pull out the one that we need in evaluateScript based on the protocol version

That way we avoid requiring a protocol version in mkEvaluationContext (although we may want one eventually anyway). Doable here because there are only two options!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, makes sense to me.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After reading these comments, now I understand why we need both unlifting modes: Are we planning to switch to another unlifting mode in new language version?


-- | A class that allows us to derive a polytype for a builtin.
class KnownPolytype (binds :: [Some TyNameRep]) val args res a | args res -> a, a -> res where
class KnownMonotype val args res a =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was a little surprised by this! To be clear, this is the monotype that corresponds to the type after stripping off the polymorphic arguments, right?

Copy link
Contributor Author

@effectfully effectfully Apr 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After stripping off the all constructors binding type variables. There's a comment about the naming:

We use two type classes for automatic derivation of type schemes: 'KnownMonotype' and
'KnownPolytype'. The terminology is due to https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system#The_Hindley%E2%80%93Milner_type_system

I should remove the "monomorphic" (right down below the quote) word from that Note, though.

Now KnownMonotype is a superclass of KnownPolytype, because we don't need to have toImmediateF and toDeferredF in KnownPolytype, since for polytypes those are the same as for their corresponding monotypes. Hence I just added the constraint. KnownPolytype only allows us to all-bind type variables and after than it's just

instance KnownMonotype val args res a => KnownPolytype '[] val args res a where
    knownPolytype = knownMonotype
    knownPolyruntime = knownMonoruntime @val @args @res

so no reason to thread toImmediateF and toDeferredF through KnownPolytype given that none of them is of any relevance to any all-bound type variables.

@michaelpj michaelpj requested a review from bezirg April 4, 2022 10:51
@effectfully effectfully force-pushed the effectfully/builtins/unlift-both-ways branch from b3130e4 to 3b26af5 Compare April 6, 2022 14:12

-- | Once we've run out of term-level arguments, we return a 'TypeSchemeResult'.
instance (res ~ res', KnownTypeAst (UniOf val) res, MakeKnown val res) =>
KnownMonotype val '[] res res' where
knownMonotype = TypeSchemeResult
knownMonoruntime = RuntimeSchemeResult

toImmediateF = makeKnown (Just ())
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove this Just () nonsense in a follow-up.

@effectfully
Copy link
Contributor Author

/benchmark plutus-benchmark:validation

Comment on lines +78 to +80
defaultUnliftingMode :: UnliftingMode
defaultUnliftingMode = UnliftingImmediate

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait, i read in some comment above the 'deferred' is the default mode

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh maybe i am reviewing a forced-push commit for benchmarking-only.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure? There's a comment about it being "preferred", but it does not make it default quite yet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we want deferred to be the default but immediate matches the current behaviour

Comment on lines +46 to +49
toMachineParameters :: EvaluationContext -> DefaultMachineParameters
toMachineParameters = case defaultUnliftingMode of
UnliftingImmediate -> machineParametersImmediate
UnliftingDeferred -> machineParametersDeferred
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in real-world (on-chain), do we have to keep both unlifting modes around? as long as we commit in a single one being the default, isn't that enough to keep around?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it does not matter that much since it is cached anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See Michael's comment. Basically, we have to keep both the versions and pick one depending on the language version. The "default" then is whatever the last language version uses. This PR doesn't implement the branching on the language version, it just lays out all the infrastructure to support that. @michaelpj will you implement the branching yourself in a follow-up? In any case, I think it should be done in a follow-up, so that we don't keep this one unmerged for too long, 'cause it blocks some other things.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I'll do it.

Copy link
Contributor

@bezirg bezirg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I "think I understand" what is happening here.

@iohk-devops
Copy link

Comparing benchmark results of 'plutus-benchmark:validation' on 'e59ade143' (base) and 'e80dbb757' (PR)

Script e59ade1 e80dbb7 Change
auction_1-1 226.0 μs 211.3 μs -6.5%
auction_1-2 856.1 μs 830.1 μs -3.0%
auction_1-3 851.6 μs 817.6 μs -4.0%
auction_1-4 294.5 μs 270.6 μs -8.1%
auction_2-1 226.9 μs 211.1 μs -7.0%
auction_2-2 859.0 μs 827.8 μs -3.6%
auction_2-3 1.088 ms 1.049 ms -3.6%
auction_2-4 849.5 μs 816.3 μs -3.9%
auction_2-5 295.0 μs 269.3 μs -8.7%
crowdfunding-success-1 268.2 μs 245.4 μs -8.5%
crowdfunding-success-2 267.9 μs 246.0 μs -8.2%
crowdfunding-success-3 268.6 μs 246.3 μs -8.3%
currency-1 323.3 μs 306.4 μs -5.2%
escrow-redeem_1-1 465.4 μs 437.3 μs -6.0%
escrow-redeem_1-2 465.9 μs 438.2 μs -5.9%
escrow-redeem_2-1 544.3 μs 513.1 μs -5.7%
escrow-redeem_2-2 544.4 μs 512.9 μs -5.8%
escrow-redeem_2-3 544.5 μs 514.4 μs -5.5%
escrow-refund-1 199.7 μs 186.5 μs -6.6%
future-increase-margin-1 321.2 μs 308.1 μs -4.1%
future-increase-margin-2 719.9 μs 690.0 μs -4.2%
future-increase-margin-3 722.4 μs 689.7 μs -4.5%
future-increase-margin-4 677.1 μs 639.6 μs -5.5%
future-increase-margin-5 1.054 ms 1.018 ms -3.4%
future-pay-out-1 322.0 μs 306.7 μs -4.8%
future-pay-out-2 722.4 μs 686.6 μs -5.0%
future-pay-out-3 721.5 μs 688.8 μs -4.5%
future-pay-out-4 1.050 ms 1.012 ms -3.6%
future-settle-early-1 321.3 μs 306.2 μs -4.7%
future-settle-early-2 720.7 μs 685.6 μs -4.9%
future-settle-early-3 722.7 μs 684.2 μs -5.3%
future-settle-early-4 808.5 μs 773.3 μs -4.4%
game-sm-success_1-1 527.2 μs 494.4 μs -6.2%
game-sm-success_1-2 249.0 μs 228.5 μs -8.2%
game-sm-success_1-3 850.5 μs 816.4 μs -4.0%
game-sm-success_1-4 289.5 μs 266.3 μs -8.0%
game-sm-success_2-1 524.5 μs 491.2 μs -6.3%
game-sm-success_2-2 249.0 μs 228.9 μs -8.1%
game-sm-success_2-3 846.3 μs 815.3 μs -3.7%
game-sm-success_2-4 289.1 μs 266.8 μs -7.7%
game-sm-success_2-5 847.9 μs 813.8 μs -4.0%
game-sm-success_2-6 289.1 μs 266.3 μs -7.9%
multisig-sm-1 535.4 μs 508.4 μs -5.0%
multisig-sm-2 525.3 μs 497.5 μs -5.3%
multisig-sm-3 531.0 μs 503.4 μs -5.2%
multisig-sm-4 538.6 μs 509.7 μs -5.4%
multisig-sm-5 753.0 μs 724.3 μs -3.8%
multisig-sm-6 537.6 μs 510.0 μs -5.1%
multisig-sm-7 527.5 μs 496.5 μs -5.9%
multisig-sm-8 533.8 μs 503.3 μs -5.7%
multisig-sm-9 538.4 μs 507.9 μs -5.7%
multisig-sm-10 754.2 μs 722.8 μs -4.2%
ping-pong-1 441.0 μs 417.0 μs -5.4%
ping-pong-2 440.0 μs 416.4 μs -5.4%
ping-pong_2-1 263.2 μs 245.0 μs -6.9%
prism-1 209.8 μs 188.7 μs -10.1%
prism-2 566.6 μs 529.9 μs -6.5%
prism-3 479.6 μs 448.9 μs -6.4%
pubkey-1 176.0 μs 161.8 μs -8.1%
stablecoin_1-1 1.176 ms 1.121 ms -4.7%
stablecoin_1-2 243.5 μs 223.3 μs -8.3%
stablecoin_1-3 1.342 ms 1.275 ms -5.0%
stablecoin_1-4 258.1 μs 236.9 μs -8.2%
stablecoin_1-5 1.689 ms 1.598 ms -5.4%
stablecoin_1-6 320.4 μs 294.1 μs -8.2%
stablecoin_2-1 1.172 ms 1.128 ms -3.8%
stablecoin_2-2 242.9 μs 223.9 μs -7.8%
stablecoin_2-3 1.340 ms 1.280 ms -4.5%
stablecoin_2-4 259.2 μs 237.3 μs -8.4%
token-account-1 243.6 μs 230.6 μs -5.3%
token-account-2 430.4 μs 405.4 μs -5.8%
uniswap-1 536.8 μs 515.3 μs -4.0%
uniswap-2 287.6 μs 270.1 μs -6.1%
uniswap-3 2.176 ms 2.038 ms -6.3%
uniswap-4 432.6 μs 390.8 μs -9.7%
uniswap-5 1.502 ms 1.408 ms -6.3%
uniswap-6 414.7 μs 376.1 μs -9.3%
vesting-1 458.9 μs 437.3 μs -4.7%

@bezirg
Copy link
Contributor

bezirg commented Apr 6, 2022

Instead of Length perhaps call it Arity,?

@effectfully
Copy link
Contributor Author

I've optimized the immediate unlifting a little, now it's -5.88%, i.e. pretty much the same as the deferred one.

@bezirg

Instead of Length perhaps call it Arity?

It's literally Length, it gets called over a type-level list of arguments, not a function type. We do get the type-level list by chopping up a function type. We used to handle function types directly without going through type-level lists, but it was a complete mess and indexing by a list (and so handling a list) turned out to be way more convenient.

@effectfully
Copy link
Contributor Author

Comments addressed, ready for a final review.

@michaelpj is the alignment fine now? All the infrastructure for branching on the language version is there, but that actual logic is not, we still use the default way of doing unlifting, which is the immediate one.


-- See Note [MakeKnownM and ReadKnownM being type synonyms].
-- | The monad that 'makeKnown' runs in.
type MakeKnownM cause = ExceptT (ErrorWithCause KnownTypeError cause) Emitter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an existing note where we explain that we only allow emitting effects at the end?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is described in the docs above the default sets of builtins, plus attempting to use Emitter in argument position gives you a nice custom type error saying you can't do that.

Technically speaking... For deferred unlifting we could as well allow Emitter in argument position due to unlifting happening in the same place where lifting happens anyway. I'm not sure if that could be useful and it most likely would slow things down a bit (unless! We give up on transformers, which is something that I'm going to try anyway).

toDeferredF getF = \arg ->
-- The bang is very important: without it GHC thinks that the argument may not be needed in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

@effectfully
Copy link
Contributor Author

Ok, two approves, I'm pressing merging to keep me going. @kwxm sorry for not giving you enough time to review, please do that anyway and I'll address the comments separately.

@effectfully effectfully merged commit dbefda3 into master Apr 7, 2022
@effectfully effectfully deleted the effectfully/builtins/unlift-both-ways branch April 7, 2022 11:18
Copy link
Contributor

@kwxm kwxm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems OK, as far as I can tell. I'm impressed that it's possible to support both things at once, but let's hope that ultimately we don't need to...

michaelpj pushed a commit that referenced this pull request Apr 13, 2022
This adds customizable unlifting and propagates it all the way up to `EvaluationContext`. The old immediate unlifting gets faster by 5.88% and the new deferred unlifting is faster than `master` by about the same amount. We're practically inlining `readKnown` and `makeKnown` here without storing them in any data type, which is probably what causes the speedup. It is beneficial to do unlifting in the same place where the value is used, more opportunities for inlining, worker-wrapping etc.

`EvaluationContext` now has two sets of parameters:  one is with immediate unlifting and the other one is with deferred unlifting. We have to keep both of them, because depending on the language version either one has to be used or the other. We also compile them separately due to all the inlining and optimization that need to happen for things to be efficient.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants