Skip to content

Commit

Permalink
More work
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelpj committed Feb 6, 2023
1 parent 0d458e5 commit d331050
Showing 1 changed file with 134 additions and 106 deletions.
240 changes: 134 additions & 106 deletions CIP-????/README.md
Expand Up @@ -99,11 +99,14 @@ This specification has two parts: firstly a change to Plutus Core, and secondly

The following new term constructors are added to the Plutus Core language:[^typed-plutus-core]
```
-- Packs the fields into a constructor value tagged with i
(constr i t...)
-- Inspects the tag on t and passes its fields to the corresponding case branch
(case t c...)
t ::=
...
-- Packs the fields into a constructor value tagged with i
| (constr i t...)
-- Inspects the tag on t and passes its fields to the corresponding case branch
| (case t t...)
```

Tags start from 0, with 0 being the first case branch, and so on.
Expand Down Expand Up @@ -185,6 +188,9 @@ Our benchmarks[^see-appendix-3] show that this CIP leads to

1. A 0-30% real-time speedup in example programs that do not work with the script context (the 0% is a primality tester that is mostly doing arithmetic, the 30% is mostly doing datatype manipulation).
2. A complete removal of the significant cost of decoding the script context.
3. A small global slowdown of 2-4%.

Note that the speedup from point 1 is inclusive of the slowdown from point 3.

[^see-appendix-3]: See Appendix 3 for the tables of results and more discussion.

Expand Down Expand Up @@ -266,16 +272,19 @@ We could instead separate these two parts out and have an introduction and elimi

That would look something like this:
```
-- Tags a term with a tag
(tag i t)
-- Inspects a tagged term for the tag, and passes the
-- inner term to the case function corresponding to the tag
(case t cs)
-- Constructs a product with the given fields
(prod ts)
-- Accesses the i'th field of the given product
(index i t)
t ::=
...
-- Tags a term with a tag
| (tag i t)
-- Inspects a tagged term for the tag, and passes the
-- inner term to the case function corresponding to the tag
| (case t t...)
-- Constructs a product with the given fields
| (prod t...)
-- Accesses the i'th field of the given product
| (index i t)
```

This is cleaner in some ways, and was the first prototype we implemented, but it has the following problems:
Expand Down Expand Up @@ -341,17 +350,24 @@ Plutus Core was originally conceived of as a typed language, and making sure tha

We add one new type constructors and one auxiliary constructor to the type language of Typed Plutus Core:
```
-- List of types. This is an auxiliary constructor, not a type!
[ty...]
-- Sum-of-products type, has n children, each of which is a list of types
(sop tyls...)
-- List of types. This is an auxiliarry syntactic form, not a type!
tyl ::= [ty...]
ty ::=
...
-- Sum-of-products type, has n children, each of which is a list of types
| (sop tyl...)
```
This corresponds to a sum-of-products type, and it has one list of types for each constructor, giving the argument types.

We add the following new term constructors to the Typed Plutus Core language:
```
(constr ty i t...)
(case ty t c...)
t ::=
...
| (constr ty i t...)
| (case ty t t...)
```

These are identical to their untyped cousins, except that they include a type annotation for the type of the whole term.
Expand Down Expand Up @@ -400,7 +416,7 @@ Let’s consider four programs, corresponding to creation and destruction of `da

```
[
{ P1 r}
{ P1 r }
-- case alternatives
(\(x : X) (y : Y) -> b1)
(\(z : Z) -> b2
Expand Down Expand Up @@ -471,8 +487,8 @@ Difference 2 does not seem to make as large a difference. If we did see a big di
### Appendix 3: Benchmark results

Throughout, the following commits are referenced:
- `master`: d123f85ca93de6974661e8b1e7bdf068dad2f57f
- `sums-of-products`: e98b284204070053b2e64bb66c7aa0832520afec
- `master`: `d123f85ca93de6974661e8b1e7bdf068dad2f57f`
- `sums-of-products`: `e98b284204070053b2e64bb66c7aa0832520afec`

These represent somewhat arbitrary snapshots.
The `sums-of-products` branch represents the current prototype, and `master` is it's merge-base with `plutus`'s `master` branch.
Expand Down Expand Up @@ -555,89 +571,101 @@ They thus represent real-world workloads.
The validation benchmarks are _not_ recompiled, they are specific saved Plutus Core programs.
These benchmarks thus only show changes in the performance of the Plutus Core evaluator itself.

| Script | ece3115 | 3fc07dc | Change |
| :------ | :------: | :------: | :------: |
| auction_1-1 | 149.5 μs | 158.6 μs | +6.1% |
| auction_1-2 | 648.6 μs | 687.7 μs | +6.0% |
| auction_1-3 | 632.7 μs | 676.7 μs | +7.0% |
| auction_1-4 | 194.7 μs | 204.5 μs | +5.0% |
| auction_2-1 | 153.4 μs | 161.7 μs | +5.4% |
| auction_2-2 | 649.0 μs | 684.0 μs | +5.4% |
| auction_2-3 | 852.3 μs | 906.5 μs | +6.4% |
| auction_2-4 | 639.7 μs | 677.7 μs | +5.9% |
| auction_2-5 | 194.6 μs | 204.1 μs | +4.9% |
| crowdfunding-success-1 | 180.7 μs | 191.6 μs | +6.0% |
| crowdfunding-success-2 | 181.6 μs | 191.3 μs | +5.3% |
| crowdfunding-success-3 | 181.5 μs | 191.5 μs | +5.5% |
| currency-1 | 236.4 μs | 251.6 μs | +6.4% |
| escrow-redeem_1-1 | 329.5 μs | 348.3 μs | +5.7% |
| escrow-redeem_1-2 | 328.8 μs | 348.8 μs | +6.1% |
| escrow-redeem_2-1 | 383.5 μs | 406.0 μs | +5.9% |
| escrow-redeem_2-2 | 382.5 μs | 409.6 μs | +7.1% |
| escrow-redeem_2-3 | 385.7 μs | 409.2 μs | +6.1% |
| escrow-refund-1 | 134.0 μs | 141.9 μs | +5.9% |
| future-increase-margin-1 | 236.4 μs | 252.7 μs | +6.9% |
| future-increase-margin-2 | 521.4 μs | 549.5 μs | +5.4% |
| future-increase-margin-3 | 519.4 μs | 549.8 μs | +5.9% |
| future-increase-margin-4 | 487.5 μs | 513.7 μs | +5.4% |
| future-increase-margin-5 | 853.6 μs | 896.0 μs | +5.0% |
| future-pay-out-1 | 235.6 μs | 250.5 μs | +6.3% |
| future-pay-out-2 | 524.3 μs | 550.3 μs | +5.0% |
| future-pay-out-3 | 518.3 μs | 549.7 μs | +6.1% |
| future-pay-out-4 | 851.0 μs | 891.0 μs | +4.7% |
| future-settle-early-1 | 236.1 μs | 252.2 μs | +6.8% |
| future-settle-early-2 | 518.4 μs | 549.8 μs | +6.1% |
| future-settle-early-3 | 520.8 μs | 549.9 μs | +5.6% |
| future-settle-early-4 | 636.2 μs | 664.2 μs | +4.4% |
| game-sm-success_1-1 | 375.4 μs | 394.5 μs | +5.1% |
| game-sm-success_1-2 | 164.9 μs | 177.5 μs | +7.6% |
| game-sm-success_1-3 | 637.2 μs | 669.8 μs | +5.1% |
| game-sm-success_1-4 | 193.0 μs | 206.2 μs | +6.8% |
| game-sm-success_2-1 | 376.9 μs | 392.2 μs | +4.1% |
| game-sm-success_2-2 | 165.5 μs | 177.4 μs | +7.2% |
| game-sm-success_2-3 | 636.9 μs | 670.5 μs | +5.3% |
| game-sm-success_2-4 | 192.7 μs | 207.1 μs | +7.5% |
| game-sm-success_2-5 | 644.0 μs | 669.9 μs | +4.0% |
| game-sm-success_2-6 | 192.6 μs | 207.0 μs | +7.5% |
| multisig-sm-1 | 390.6 μs | 411.2 μs | +5.3% |
| multisig-sm-2 | 382.1 μs | 399.4 μs | +4.5% |
| multisig-sm-3 | 383.4 μs | 404.1 μs | +5.4% |
| multisig-sm-4 | 385.3 μs | 402.1 μs | +4.4% |
| multisig-sm-5 | 563.5 μs | 592.8 μs | +5.2% |
| multisig-sm-6 | 389.0 μs | 410.6 μs | +5.6% |
| multisig-sm-7 | 380.8 μs | 399.9 μs | +5.0% |
| multisig-sm-8 | 383.2 μs | 406.9 μs | +6.2% |
| multisig-sm-9 | 386.2 μs | 407.3 μs | +5.5% |
| multisig-sm-10 | 564.4 μs | 592.8 μs | +5.0% |
| ping-pong-1 | 317.0 μs | 338.1 μs | +6.7% |
| ping-pong-2 | 319.1 μs | 338.9 μs | +6.2% |
| ping-pong_2-1 | 180.2 μs | 193.6 μs | +7.4% |
| prism-1 | 138.5 μs | 150.2 μs | +8.4% |
| prism-2 | 403.6 μs | 419.1 μs | +3.8% |
| prism-3 | 336.7 μs | 356.9 μs | +6.0% |
| pubkey-1 | 118.1 μs | 126.8 μs | +7.4% |
| stablecoin_1-1 | 953.0 μs | 994.3 μs | +4.3% |
| stablecoin_1-2 | 162.5 μs | 174.7 μs | +7.5% |
| stablecoin_1-3 | 1.092 ms | 1.139 ms | +4.3% |
| stablecoin_1-4 | 172.7 μs | 185.1 μs | +7.2% |
| stablecoin_1-5 | 1.376 ms | 1.445 ms | +5.0% |
| stablecoin_1-6 | 214.3 μs | 228.4 μs | +6.6% |
| stablecoin_2-1 | 952.0 μs | 990.9 μs | +4.1% |
| stablecoin_2-2 | 162.6 μs | 174.8 μs | +7.5% |
| stablecoin_2-3 | 1.090 ms | 1.144 ms | +5.0% |
| stablecoin_2-4 | 172.9 μs | 185.5 μs | +7.3% |
| token-account-1 | 173.6 μs | 183.2 μs | +5.5% |
| token-account-2 | 310.8 μs | 332.8 μs | +7.1% |
| uniswap-1 | 407.2 μs | 430.7 μs | +5.8% |
| uniswap-2 | 202.7 μs | 214.1 μs | +5.6% |
| uniswap-3 | 1.758 ms | 1.839 ms | +4.6% |
| uniswap-4 | 279.8 μs | 296.1 μs | +5.8% |
| uniswap-5 | 1.130 ms | 1.188 ms | +5.1% |
| uniswap-6 | 275.3 μs | 289.7 μs | +5.2% |
| vesting-1 | 334.8 μs | 356.8 μs | +6.6% |

This is not good at all. We should not be having a negative impact on scripts that don't use the new constructs.
This must be resolved in the production implementation before we merge it.
| Script | `master` | `sums-of-products` | Change |
|:-------------------------|:--------:|:------------------:|:------:|
| auction_1-1 | 150.3 μs | 158.6 μs | +5.5% |
| auction_1-2 | 652.2 μs | 684.8 μs | +5.0% |
| auction_1-3 | 638.2 μs | 678.7 μs | +6.3% |
| auction_1-4 | 194.9 μs | 205.9 μs | +5.6% |
| auction_2-1 | 153.7 μs | 161.9 μs | +5.3% |
| auction_2-2 | 648.8 μs | 687.2 μs | +5.9% |
| auction_2-3 | 858.0 μs | 895.6 μs | +4.4% |
| auction_2-4 | 638.2 μs | 676.8 μs | +6.0% |
| auction_2-5 | 195.1 μs | 205.1 μs | +5.1% |
| crowdfunding-success-1 | 182.6 μs | 187.6 μs | +2.7% |
| crowdfunding-success-2 | 182.4 μs | 187.9 μs | +3.0% |
| crowdfunding-success-3 | 182.2 μs | 187.8 μs | +3.1% |
| currency-1 | 237.9 μs | 249.5 μs | +4.9% |
| escrow-redeem_1-1 | 331.7 μs | 342.8 μs | +3.3% |
| escrow-redeem_1-2 | 330.5 μs | 343.4 μs | +3.9% |
| escrow-redeem_2-1 | 386.0 μs | 403.0 μs | +4.4% |
| escrow-redeem_2-2 | 385.0 μs | 404.3 μs | +5.0% |
| escrow-redeem_2-3 | 386.4 μs | 403.7 μs | +4.5% |
| escrow-refund-1 | 134.9 μs | 140.9 μs | +4.4% |
| future-increase-margin-1 | 237.8 μs | 250.3 μs | +5.3% |
| future-increase-margin-2 | 522.0 μs | 538.2 μs | +3.1% |
| future-increase-margin-3 | 521.7 μs | 536.5 μs | +2.8% |
| future-increase-margin-4 | 489.9 μs | 508.8 μs | +3.9% |
| future-increase-margin-5 | 859.0 μs | 873.8 μs | +1.7% |
| future-pay-out-1 | 237.7 μs | 248.7 μs | +4.6% |
| future-pay-out-2 | 524.5 μs | 540.3 μs | +3.0% |
| future-pay-out-3 | 525.8 μs | 537.7 μs | +2.3% |
| future-pay-out-4 | 862.0 μs | 878.5 μs | +1.9% |
| future-settle-early-1 | 237.7 μs | 248.6 μs | +4.6% |
| future-settle-early-2 | 521.7 μs | 537.5 μs | +3.0% |
| future-settle-early-3 | 525.5 μs | 537.1 μs | +2.2% |
| future-settle-early-4 | 642.1 μs | 656.0 μs | +2.2% |
| game-sm-success_1-1 | 379.3 μs | 391.5 μs | +3.2% |
| game-sm-success_1-2 | 166.4 μs | 178.3 μs | +7.2% |
| game-sm-success_1-3 | 639.2 μs | 669.1 μs | +4.7% |
| game-sm-success_1-4 | 193.5 μs | 206.6 μs | +6.8% |
| game-sm-success_2-1 | 379.7 μs | 389.6 μs | +2.6% |
| game-sm-success_2-2 | 166.0 μs | 178.5 μs | +7.5% |
| game-sm-success_2-3 | 641.2 μs | 670.1 μs | +4.5% |
| game-sm-success_2-4 | 193.3 μs | 207.1 μs | +7.1% |
| game-sm-success_2-5 | 644.1 μs | 668.8 μs | +3.8% |
| game-sm-success_2-6 | 193.6 μs | 206.5 μs | +6.7% |
| multisig-sm-1 | 394.5 μs | 405.5 μs | +2.8% |
| multisig-sm-2 | 385.2 μs | 392.8 μs | +2.0% |
| multisig-sm-3 | 386.5 μs | 394.5 μs | +2.1% |
| multisig-sm-4 | 385.8 μs | 404.2 μs | +4.8% |
| multisig-sm-5 | 567.7 μs | 583.0 μs | +2.7% |
| multisig-sm-6 | 391.7 μs | 405.5 μs | +3.5% |
| multisig-sm-7 | 382.7 μs | 394.3 μs | +3.0% |
| multisig-sm-8 | 389.3 μs | 395.8 μs | +1.7% |
| multisig-sm-9 | 387.1 μs | 404.4 μs | +4.5% |
| multisig-sm-10 | 567.4 μs | 583.3 μs | +2.8% |
| ping-pong-1 | 320.6 μs | 327.4 μs | +2.1% |
| ping-pong-2 | 319.1 μs | 327.0 μs | +2.5% |
| ping-pong_2-1 | 182.2 μs | 190.6 μs | +4.6% |
| prism-1 | 139.2 μs | 150.2 μs | +7.9% |
| prism-2 | 404.5 μs | 412.2 μs | +1.9% |
| prism-3 | 339.4 μs | 359.4 μs | +5.9% |
| pubkey-1 | 118.6 μs | 123.7 μs | +4.3% |
| stablecoin_1-1 | 962.4 μs | 976.3 μs | +1.4% |
| stablecoin_1-2 | 163.7 μs | 174.2 μs | +6.4% |
| stablecoin_1-3 | 1.103 ms | 1.120 ms | +1.5% |
| stablecoin_1-4 | 174.0 μs | 185.4 μs | +6.6% |
| stablecoin_1-5 | 1.391 ms | 1.418 ms | +1.9% |
| stablecoin_1-6 | 215.4 μs | 227.5 μs | +5.6% |
| stablecoin_2-1 | 962.4 μs | 981.3 μs | +2.0% |
| stablecoin_2-2 | 163.5 μs | 174.2 μs | +6.5% |
| stablecoin_2-3 | 1.099 ms | 1.117 ms | +1.6% |
| stablecoin_2-4 | 173.6 μs | 184.8 μs | +6.5% |
| token-account-1 | 174.1 μs | 181.2 μs | +4.1% |
| token-account-2 | 312.8 μs | 334.3 μs | +6.9% |
| uniswap-1 | 408.0 μs | 425.4 μs | +4.3% |
| uniswap-2 | 203.9 μs | 211.7 μs | +3.8% |
| uniswap-3 | 1.779 ms | 1.830 ms | +2.9% |
| uniswap-4 | 282.6 μs | 297.6 μs | +5.3% |
| uniswap-5 | 1.139 ms | 1.180 ms | +3.6% |
| uniswap-6 | 276.2 μs | 288.4 μs | +4.4% |
| vesting-1 | 339.8 μs | 356.0 μs | +4.8% |

This is an average slowdown of 4%, which is not good at all. We do not want to have a negative impact on scripts that don't use the new constructs.

However, this slowdown is very difficult to avoid.
The GHC Core (GHC's intermediate language for Haskell programs) for both versions looks nearly identical, with the only differences being the introduction of new code for the new cases.
We believe that this indicates that GHC simply produces slightly slower code when we have more constructs, even if those code paths are not used.
In particular, there are some threshold effects when you cross certain numbers of constructors.

We tested this by doing an experiment that simply adds new unused constructors to the Plutus Core term type and evaluator frame type.
This caused a slowdown of on average 2%.
That's not enough to completely explain the loss, but we suspect that similar causes account for the rest (investigation is ongoing).

This is still bad -- a slowdown is still a slowdown -- but it's less bad because it's unavoidable if we ever want to increase the size of the language.
We will pay this cost whenever we decide expand the language.
Especially if the cost comes from threshold effects, it may be a one-time cost that we just have to pay on some occasion.

## Copyright

Expand Down

0 comments on commit d331050

Please sign in to comment.