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] Split 'KnownTypeIn' into two classes #4420

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 '0397f83b8' (base) and '200e29234' (PR)

Script 0397f83 200e292 Change
auction_1-1 278.3 μs 291.5 μs +4.7%
auction_1-2 935.9 μs 966.2 μs +3.2%
auction_1-3 932.7 μs 961.8 μs +3.1%
auction_1-4 364.5 μs 381.6 μs +4.7%
auction_2-1 281.1 μs 291.4 μs +3.7%
auction_2-2 938.1 μs 966.9 μs +3.1%
auction_2-3 1.192 ms 1.230 ms +3.2%
auction_2-4 933.1 μs 964.1 μs +3.3%
auction_2-5 363.9 μs 383.7 μs +5.4%
crowdfunding-success-1 331.0 μs 347.1 μs +4.9%
crowdfunding-success-2 329.8 μs 346.1 μs +4.9%
crowdfunding-success-3 330.0 μs 346.0 μs +4.8%
currency-1 366.6 μs 379.7 μs +3.6%
escrow-redeem_1-1 535.4 μs 554.4 μs +3.5%
escrow-redeem_1-2 535.6 μs 554.9 μs +3.6%
escrow-redeem_2-1 626.1 μs 648.2 μs +3.5%
escrow-redeem_2-2 624.9 μs 645.7 μs +3.3%
escrow-redeem_2-3 624.5 μs 646.6 μs +3.5%
escrow-refund-1 247.1 μs 255.4 μs +3.4%
future-increase-margin-1 369.5 μs 378.5 μs +2.4%
future-increase-margin-2 815.6 μs 838.6 μs +2.8%
future-increase-margin-3 814.6 μs 838.6 μs +2.9%
future-increase-margin-4 754.9 μs 771.5 μs +2.2%
future-increase-margin-5 1.147 ms 1.176 ms +2.5%
future-pay-out-1 366.5 μs 379.5 μs +3.5%
future-pay-out-2 811.8 μs 839.0 μs +3.4%
future-pay-out-3 814.3 μs 842.6 μs +3.5%
future-pay-out-4 1.147 ms 1.180 ms +2.9%
future-settle-early-1 365.7 μs 382.0 μs +4.5%
future-settle-early-2 813.9 μs 840.9 μs +3.3%
future-settle-early-3 814.4 μs 840.8 μs +3.2%
future-settle-early-4 891.6 μs 910.9 μs +2.2%
game-sm-success_1-1 599.7 μs 619.4 μs +3.3%
game-sm-success_1-2 310.7 μs 325.0 μs +4.6%
game-sm-success_1-3 939.4 μs 966.7 μs +2.9%
game-sm-success_1-4 362.2 μs 380.5 μs +5.1%
game-sm-success_2-1 597.5 μs 617.4 μs +3.3%
game-sm-success_2-2 310.3 μs 323.7 μs +4.3%
game-sm-success_2-3 940.0 μs 968.7 μs +3.1%
game-sm-success_2-4 363.3 μs 380.9 μs +4.8%
game-sm-success_2-5 939.2 μs 971.3 μs +3.4%
game-sm-success_2-6 362.5 μs 380.8 μs +5.0%
multisig-sm-1 606.1 μs 622.3 μs +2.7%
multisig-sm-2 594.3 μs 608.6 μs +2.4%
multisig-sm-3 602.5 μs 615.8 μs +2.2%
multisig-sm-4 610.1 μs 622.6 μs +2.0%
multisig-sm-5 835.7 μs 854.1 μs +2.2%
multisig-sm-6 608.9 μs 623.3 μs +2.4%
multisig-sm-7 597.1 μs 612.6 μs +2.6%
multisig-sm-8 602.1 μs 618.6 μs +2.7%
multisig-sm-9 610.2 μs 625.0 μs +2.4%
multisig-sm-10 836.1 μs 854.4 μs +2.2%
ping-pong-1 501.2 μs 517.0 μs +3.2%
ping-pong-2 500.1 μs 515.0 μs +3.0%
ping-pong_2-1 309.0 μs 321.3 μs +4.0%
prism-1 260.1 μs 270.7 μs +4.1%
prism-2 648.0 μs 667.0 μs +2.9%
prism-3 554.7 μs 577.4 μs +4.1%
pubkey-1 221.0 μs 230.6 μs +4.3%
stablecoin_1-1 1.309 ms 1.375 ms +5.0%
stablecoin_1-2 305.1 μs 318.6 μs +4.4%
stablecoin_1-3 1.502 ms 1.588 ms +5.7%
stablecoin_1-4 324.2 μs 338.8 μs +4.5%
stablecoin_1-5 1.902 ms 2.042 ms +7.4%
stablecoin_1-6 401.6 μs 422.1 μs +5.1%
stablecoin_2-1 1.305 ms 1.379 ms +5.7%
stablecoin_2-2 304.3 μs 319.5 μs +5.0%
stablecoin_2-3 1.491 ms 1.587 ms +6.4%
stablecoin_2-4 324.6 μs 339.3 μs +4.5%
token-account-1 285.2 μs 293.8 μs +3.0%
token-account-2 500.2 μs 514.7 μs +2.9%
uniswap-1 593.8 μs 610.4 μs +2.8%
uniswap-2 341.9 μs 352.6 μs +3.1%
uniswap-3 2.459 ms 2.575 ms +4.7%
uniswap-4 532.5 μs 555.4 μs +4.3%
uniswap-5 1.719 ms 1.796 ms +4.5%
uniswap-6 508.0 μs 530.0 μs +4.3%
vesting-1 521.0 μs 536.6 μs +3.0%

@effectfully
Copy link
Contributor Author

I hate you GHC.

@michaelpj
Copy link
Contributor

Weird.

@michaelpj
Copy link
Contributor

This still seems like it ought to be good in principle, maybe worth another try on top of the inlining changes?

@effectfully
Copy link
Contributor Author

This still seems like it ought to be good in principle, maybe worth another try on top of the inlining changes?

That's the intention.

@effectfully effectfully force-pushed the effectfully/builtins/split-KnownTypeIn-into-two-classes branch from 200e292 to ddb543f Compare March 21, 2022 14:29
@effectfully
Copy link
Contributor Author

/benchmark plutus-benchmark:validation

@iohk-devops
Copy link

Comparing benchmark results of 'plutus-benchmark:validation' on 'dc9275462' (base) and 'ddb543f8e' (PR)

Script dc92754 ddb543f Change
auction_1-1 242.8 μs 240.5 μs -0.9%
auction_1-2 886.4 μs 873.7 μs -1.4%
auction_1-3 880.2 μs 864.9 μs -1.7%
auction_1-4 314.5 μs 312.2 μs -0.7%
auction_2-1 242.9 μs 242.7 μs -0.1%
auction_2-2 884.1 μs 878.0 μs -0.7%
auction_2-3 1.121 ms 1.113 ms -0.7%
auction_2-4 874.8 μs 870.8 μs -0.5%
auction_2-5 313.3 μs 313.5 μs +0.1%
crowdfunding-success-1 284.2 μs 284.3 μs +0.0%
crowdfunding-success-2 285.1 μs 283.9 μs -0.4%
crowdfunding-success-3 284.7 μs 283.9 μs -0.3%
currency-1 336.9 μs 334.1 μs -0.8%
escrow-redeem_1-1 486.6 μs 483.7 μs -0.6%
escrow-redeem_1-2 485.5 μs 483.1 μs -0.5%
escrow-redeem_2-1 570.6 μs 567.2 μs -0.6%
escrow-redeem_2-2 571.6 μs 567.0 μs -0.8%
escrow-redeem_2-3 573.2 μs 568.2 μs -0.9%
escrow-refund-1 214.9 μs 213.0 μs -0.9%
future-increase-margin-1 337.4 μs 333.9 μs -1.0%
future-increase-margin-2 751.9 μs 744.6 μs -1.0%
future-increase-margin-3 750.0 μs 743.7 μs -0.8%
future-increase-margin-4 696.0 μs 695.7 μs -0.0%
future-increase-margin-5 1.077 ms 1.077 ms 0.0%
future-pay-out-1 336.3 μs 336.4 μs +0.0%
future-pay-out-2 748.9 μs 748.0 μs -0.1%
future-pay-out-3 747.8 μs 746.0 μs -0.2%
future-pay-out-4 1.075 ms 1.073 ms -0.2%
future-settle-early-1 335.9 μs 335.2 μs -0.2%
future-settle-early-2 751.3 μs 745.6 μs -0.8%
future-settle-early-3 752.0 μs 745.5 μs -0.9%
future-settle-early-4 828.8 μs 823.5 μs -0.6%
game-sm-success_1-1 549.2 μs 546.7 μs -0.5%
game-sm-success_1-2 267.4 μs 266.9 μs -0.2%
game-sm-success_1-3 876.0 μs 865.9 μs -1.2%
game-sm-success_1-4 311.8 μs 311.3 μs -0.2%
game-sm-success_2-1 549.9 μs 548.1 μs -0.3%
game-sm-success_2-2 266.7 μs 267.9 μs +0.4%
game-sm-success_2-3 877.8 μs 869.6 μs -0.9%
game-sm-success_2-4 313.1 μs 311.8 μs -0.4%
game-sm-success_2-5 879.7 μs 868.9 μs -1.2%
game-sm-success_2-6 312.7 μs 312.1 μs -0.2%
multisig-sm-1 560.5 μs 554.6 μs -1.1%
multisig-sm-2 548.7 μs 546.0 μs -0.5%
multisig-sm-3 555.4 μs 551.5 μs -0.7%
multisig-sm-4 561.6 μs 559.0 μs -0.5%
multisig-sm-5 778.5 μs 774.4 μs -0.5%
multisig-sm-6 560.9 μs 557.5 μs -0.6%
multisig-sm-7 547.0 μs 545.3 μs -0.3%
multisig-sm-8 553.2 μs 551.1 μs -0.4%
multisig-sm-9 559.4 μs 558.9 μs -0.1%
multisig-sm-10 775.9 μs 772.1 μs -0.5%
ping-pong-1 460.4 μs 458.5 μs -0.4%
ping-pong-2 460.9 μs 459.0 μs -0.4%
ping-pong_2-1 275.6 μs 275.1 μs -0.2%
prism-1 223.4 μs 223.1 μs -0.1%
prism-2 593.5 μs 592.6 μs -0.2%
prism-3 502.6 μs 501.7 μs -0.2%
pubkey-1 189.3 μs 188.1 μs -0.6%
stablecoin_1-1 1.212 ms 1.206 ms -0.5%
stablecoin_1-2 260.8 μs 260.2 μs -0.2%
stablecoin_1-3 1.398 ms 1.385 ms -0.9%
stablecoin_1-4 278.2 μs 278.6 μs +0.1%
stablecoin_1-5 1.760 ms 1.748 ms -0.7%
stablecoin_1-6 344.7 μs 346.3 μs +0.5%
stablecoin_2-1 1.218 ms 1.211 ms -0.6%
stablecoin_2-2 261.6 μs 261.0 μs -0.2%
stablecoin_2-3 1.390 ms 1.378 ms -0.9%
stablecoin_2-4 277.9 μs 277.9 μs 0.0%
token-account-1 253.9 μs 252.7 μs -0.5%
token-account-2 452.0 μs 448.3 μs -0.8%
uniswap-1 554.9 μs 553.0 μs -0.3%
uniswap-2 301.4 μs 301.3 μs -0.0%
uniswap-3 2.247 ms 2.237 ms -0.4%
uniswap-4 459.6 μs 459.1 μs -0.1%
uniswap-5 1.562 ms 1.558 ms -0.3%
uniswap-6 440.7 μs 440.0 μs -0.2%
vesting-1 478.6 μs 477.2 μs -0.3%

@effectfully
Copy link
Contributor Author

Achievement unlocked: GHC defeated.

Now need to finish it off.

@effectfully
Copy link
Contributor Author

I mean, the PR, not GHC.

@michaelpj
Copy link
Contributor

Okay, so we made it not worse than the status quo... but do we expect it to actually benefit us with other changes? It seems like it should, so I'm kind of surprised it's so nothing-y.

@michaelpj
Copy link
Contributor

I kind of like it anyway, though, it's nice seeing where we need each direction.

@effectfully
Copy link
Contributor Author

effectfully commented Mar 22, 2022

Okay, so we made it not worse than the status quo... but do we expect it to actually benefit us with other changes?

The main reason I've been bothering with this is that I want to get helpful compile-time error messages when someone uses EvaluationResult or Emitter in argument position instead of a runtime failure. It may also make sense to forbid using SomeConstant in result position, because that is currently slower (by the tiniest bit) than using Opaque, but with deferred unlifting we may (or may not) solve this problem once and for all and then it'll be fine to use SomeConstant in result position.

I didn't have much hope for things to become faster, because even though RuntimeSchemes become a bit tidier, we only construct them once anyway, so allocations don't change. I.e. this was intended as a purely semantic and UX improvement PR.

@effectfully
Copy link
Contributor Author

because even though RuntimeSchemes become a bit tidier

Maybe that half a percent speedup that we see in the results above is not noise, but a true half a percent speedup due RuntimeSchemes becoming tidier, it's really hard to tell without a dedicated set of benchmarks for the builtins machinery.

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, there's some commented out bits and TODOs to fix.

@effectfully effectfully force-pushed the effectfully/builtins/split-KnownTypeIn-into-two-classes branch 4 times, most recently from 1ba266d to 4f49896 Compare March 22, 2022 21:33
@@ -27,6 +29,8 @@ liftOrdering LT = GLT
liftOrdering EQ = error "'liftOrdering': 'Eq'"
liftOrdering GT = GGT

type KnownType val a = (KnownTypeAst (UniOf val) a, MakeKnown val a)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Naming here doesn't make much sense, but I really don't want to spend a lot of time here refactoring these tests, at the very least not in this PR.

{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UndecidableSuperClasses #-}

module PlutusCore.Builtin.TestKnown
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Created a separate file just not to keep this scary looking stuff in the important KnownType module and in order not to introduce a dependency on KnownTypeAst in it, as the two concepts are explicitly orthogonal (described in a Note).

Copy link
Contributor

Choose a reason for hiding this comment

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

Why not put this rationale in the module comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point.

-- | An instance of this class not having any constraints ensures that every type (according to
-- 'Everywhere') from the universe has 'KnownTypeAst, 'ReadKnownIn' and 'MakeKnownIn' instances.
class
( uni `Everywhere` ImplementedKnownTypeAst uni
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We didn't have that ImplementedKnownTypeAst test before, now we do.

@effectfully
Copy link
Contributor Author

Code polished, old docs polished, new docs added, ready for review.

@effectfully effectfully requested review from michaelpj and kwxm March 22, 2022 21:36
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.

Not much to say, just a bunch of comments which turned out to be wrong 😅

-}

-- See Note [Performance of ReadKnownIn and MakeKnownIn instances].
class uni ~ UniOf val => MakeKnownIn uni val a where
Copy link
Contributor

Choose a reason for hiding this comment

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

No instances of these typeclasses ever fix val. What would happen if we did this?

class MakeKnownIn uni a where
  makeKnown :: forall val . (uni ~ UniOf val) => ...

I think so long as makeKnown gets inlined this is going to be no worse and it lets us get rid of a typeclass parameter.

Copy link
Contributor

Choose a reason for hiding this comment

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

Okay, you'd need to add a uni ~ UniOf val constraint in a few places (e.g. kin the definition of MakeKnown), but that seems okay.

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 you're not gaining that much, it just seems somewhat interesting to me that really these instances only care about the universe, and you can use the same instance for whatever val you like, so long as it has that universe.

Copy link
Contributor

Choose a reason for hiding this comment

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

Nope, I did miss something: the default implementation ultimately relies on HasConstantIn which does need to fix the term type. So you can't do the default instances without this. Leaving my comments just in case they're interesting 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.

I've been annoyed by this problem for years by now. Which is how #4172 emerged. It fixed the problem, but made the code slower and we reverted it. I'd been looking at it again today before I read your comments! I'm going to try it again now that we have a good inlining setup.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No instances of these typeclasses ever fix val

The Opaque instance does.

Copy link
Contributor

Choose a reason for hiding this comment

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

Interesting. We weren't even inlining makeKnown/readKnown at that point, so perhaps it's less surprising that the dictionary-passing overhead didn't get optimized away.

{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UndecidableSuperClasses #-}

module PlutusCore.Builtin.TestKnown
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not put this rationale in the module comment?


However it's also worth considering untangling 'RuntimeScheme' from 'TypeScheme' and generating the
two in parallel, so that we only need to optimize the former. Then we will be able to afford having
any kind of nonsense in 'TypeScheme'. Another reason for that would be the fact that Core output
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, this seems reasonable. It doesn't seem crazy that a value representing a type signature for a function should allow you to both lift and unlift the argument types. It's just that we don't need that at runtime, and that's what we have RuntimeScheme for.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure what you're saying. That what we have right now is already fine, given that MakeKnown only appears for arguments in TypeScheme and not RuntimeScheme?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, which I think is also what you were saying in the comment: that it seems conceptually fine, so long as it doesn't leak into the implementation of the RuntimeSchemes.

@effectfully effectfully force-pushed the effectfully/builtins/split-KnownTypeIn-into-two-classes branch from 4f49896 to f891cc6 Compare March 23, 2022 11:18
@michaelpj michaelpj merged commit 70787f8 into master Mar 23, 2022
@effectfully effectfully deleted the effectfully/builtins/split-KnownTypeIn-into-two-classes branch March 23, 2022 12:47
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.

3 participants