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

External benchmarks for older solc versions #15561

Merged
merged 4 commits into from
Nov 8, 2024

Conversation

cameel
Copy link
Member

@cameel cameel commented Nov 1, 2024

Adds benchmarks for older OpenZeppelin and Uniswap versions, which can be compiled by older solc versions (down to 0.8.10 in some cases).

I also tried to quickly find some new projects that would compile with a larger range of solc versions. Two seemed promising: liquity and farcaster. Unfortunately they did not prove useful for this. They may be useful in general though so I'm still adding them.

Finally, the PR refactors the setup script to make it less repetitive, especially when using multiple versions of the same project.

@cameel
Copy link
Member Author

cameel commented Nov 1, 2024

Benchmark results

Values averaged over 2 runs.

Compilation time

version OZ 5.0.2 OZ 4.9.0 OZ 4.8.0 OZ 4.7.0 Uniswap 2024-06-06 Uniswap 2022-06-16 liquity 2024-10-30 eigenlayer 0.3.0
0.8.10 100 s 139 s 118 s
0.8.11 92 s 138 s 117 s
0.8.12 93 s 136 s 122 s 64 s
0.8.13 102 s 144 s 123 s 63 s
0.8.14 101 s 140 s 122 s 60 s
0.8.15 154 s 142 s 73 s
0.8.16 138 s 126 s 68 s
0.8.17 139 s 123 s 68 s
0.8.18 137 s 120 s 64 s 2958 s
0.8.19 138 s 122 s 63 s 2896 s
0.8.20 142 s 120 s 64 s 2738 s
0.8.21 114 s 100 s 51 s 2282 s
0.8.22 118 s 103 s 52 s 2253 s
0.8.23 112 s 102 s 53 s 2254 s
0.8.24 112 s 96 s 424 s 50 s 124 s 2194 s
0.8.25 113 s 96 s 433 s 51 s 124 s 2270 s
0.8.26 38 s 46 s 70 s 63 s 236 s 28 s 69 s 1227 s
0.8.27 37 s 46 s 79 s 67 s 158 s 23 s 52 s 684 s
0.8.28 33 s 44 s 69 s 63 s 134 s 20 s 50 s 560 s

Peak memory use

version OZ 5.0.2 OZ 4.9.0 OZ 4.8.0 OZ 4.7.0 Uniswap 2024-06-06 Uniswap 2022-06-16 liquity 2024-10-30 eigenlayer 0.3.0
0.8.10 558 MiB 660 MiB 512 MiB
0.8.11 557 MiB 660 MiB 515 MiB
0.8.12 556 MiB 663 MiB 524 MiB 274 MiB
0.8.13 566 MiB 668 MiB 527 MiB 277 MiB
0.8.14 582 MiB 684 MiB 526 MiB 278 MiB
0.8.15 716 MiB 578 MiB 307 MiB
0.8.16 716 MiB 576 MiB 305 MiB
0.8.17 717 MiB 578 MiB 306 MiB
0.8.18 706 MiB 576 MiB 304 MiB 4892 MiB
0.8.19 707 MiB 576 MiB 304 MiB 4758 MiB
0.8.20 726 MiB 593 MiB 314 MiB 4882 MiB
0.8.21 2049 MiB 1722 MiB 808 MiB 22200 MiB
0.8.22 2053 MiB 1726 MiB 811 MiB 22270 MiB
0.8.23 2053 MiB 1725 MiB 811 MiB 22269 MiB
0.8.24 2053 MiB 1726 MiB 5244 MiB 812 MiB 1766 MiB 22272 MiB
0.8.25 2048 MiB 1730 MiB 5202 MiB 817 MiB 1747 MiB 22122 MiB
0.8.26 1074 MiB 1240 MiB 1774 MiB 1490 MiB 4478 MiB 712 MiB 1524 MiB 19011 MiB
0.8.27 1218 MiB 1420 MiB 2058 MiB 1743 MiB 4806 MiB 789 MiB 1686 MiB 20368 MiB
0.8.28 505 MiB 580 MiB 736 MiB 584 MiB 1498 MiB 304 MiB 675 MiB 4464 MiB

@cameel
Copy link
Member Author

cameel commented Nov 1, 2024

Plots of all data

Here are plots showing all the info from the tables.

First compilation time. On two separate plots, because the slower projects dwarf everything else:
compilation-time-smaller-projects
compilation-time-bigger-projects

I did not bother with that for memory, because there is nothing interesting happening there. Looks like the inclusion of unnecessary JSON artifacts in 0.8.21 made it explode for a few versions, but other than that memory use is not a significant factor.
peak-memory-use

Plots of relevant data

And here's a subset that's actually worth showing:

compilation-time-oz-uniswap
compilation-time-eigenlayer

Generating the plots

In case there's a need to adjust those, here's the Python script I used to create them (requires matplotlib).

Script used to generate the plots
import matplotlib.pyplot as plt
import numpy as np

time = [
    ["version", "OpenZeppelin 5.0.2", "OpenZeppelin 4.9.0", "OpenZeppelin 4.8.0", "OpenZeppelin 4.7.0", "Uniswap 2022-06-16", "Liquity 2024-10-30", "Uniswap 2024-06-06", "Eigenlayer 0.3.0"],
    [ "0.8.10",                 None,                  100,                  139,                  118,                 None,                 None,                 None,               None],
    [ "0.8.11",                 None,                   92,                  138,                  117,                 None,                 None,                 None,               None],
    [ "0.8.12",                 None,                   93,                  136,                  122,                   64,                 None,                 None,               None],
    [ "0.8.13",                 None,                  102,                  144,                  123,                   63,                 None,                 None,               None],
    [ "0.8.14",                 None,                  101,                  140,                  122,                   60,                 None,                 None,               None],
    [ "0.8.15",                 None,                 None,                  154,                  142,                   73,                 None,                 None,               None],
    [ "0.8.16",                 None,                 None,                  138,                  126,                   68,                 None,                 None,               None],
    [ "0.8.17",                 None,                 None,                  139,                  123,                   68,                 None,                 None,               None],
    [ "0.8.18",                 None,                 None,                  137,                  120,                   64,                 None,                 None,               2958],
    [ "0.8.19",                 None,                 None,                  138,                  122,                   63,                 None,                 None,               2896],
    [ "0.8.20",                 None,                 None,                  142,                  120,                   64,                 None,                 None,               2738],
    [ "0.8.21",                 None,                 None,                  114,                  100,                   51,                 None,                 None,               2282],
    [ "0.8.22",                 None,                 None,                  118,                  103,                   52,                 None,                 None,               2253],
    [ "0.8.23",                 None,                 None,                  112,                  102,                   53,                 None,                 None,               2254],
    [ "0.8.24",                 None,                 None,                  112,                   96,                   50,                  124,                  424,               2194],
    [ "0.8.25",                 None,                 None,                  113,                   96,                   51,                  124,                  433,               2270],
    [ "0.8.26",                   38,                   46,                   70,                   63,                   28,                   69,                  236,               1227],
    [ "0.8.27",                   37,                   46,                   79,                   67,                   23,                   52,                  158,                684],
    [ "0.8.28",                   33,                   44,                   69,                   63,                   20,                   50,                  134,                560],
]

memory = [
    ["version", "OpenZeppelin 5.0.2", "OpenZeppelin 4.9.0", "OpenZeppelin 4.8.0", "OpenZeppelin 4.7.0", "Uniswap 2022-06-16", "Liquity 2024-10-30", "Uniswap 2024-06-06", "Eigenlayer 0.3.0"],
    [ "0.8.10",                 None,                  558,                  660,                  512,                 None,                 None,                 None,               None],
    [ "0.8.11",                 None,                  557,                  660,                  515,                 None,                 None,                 None,               None],
    [ "0.8.12",                 None,                  556,                  663,                  524,                  274,                 None,                 None,               None],
    [ "0.8.13",                 None,                  566,                  668,                  527,                  277,                 None,                 None,               None],
    [ "0.8.14",                 None,                  582,                  684,                  526,                  278,                 None,                 None,               None],
    [ "0.8.15",                 None,                 None,                  716,                  578,                  307,                 None,                 None,               None],
    [ "0.8.16",                 None,                 None,                  716,                  576,                  305,                 None,                 None,               None],
    [ "0.8.17",                 None,                 None,                  717,                  578,                  306,                 None,                 None,               None],
    [ "0.8.18",                 None,                 None,                  706,                  576,                  304,                 None,                 None,               4892],
    [ "0.8.19",                 None,                 None,                  707,                  576,                  304,                 None,                 None,               4758],
    [ "0.8.20",                 None,                 None,                  726,                  593,                  314,                 None,                 None,               4882],
    [ "0.8.21",                 None,                 None,                 2049,                 1722,                  808,                 None,                 None,              22200],
    [ "0.8.22",                 None,                 None,                 2053,                 1726,                  811,                 None,                 None,              22270],
    [ "0.8.23",                 None,                 None,                 2053,                 1725,                  811,                 None,                 None,              22269],
    [ "0.8.24",                 None,                 None,                 2053,                 1726,                  812,                 1766,                 5244,              22272],
    [ "0.8.25",                 None,                 None,                 2048,                 1730,                  817,                 1747,                 5202,              22122],
    [ "0.8.26",                 1074,                 1240,                 1774,                 1490,                  712,                 1524,                 4478,              19011],
    [ "0.8.27",                 1218,                 1420,                 2058,                 1743,                  789,                 1686,                 4806,              20368],
    [ "0.8.28",                  505,                  580,                  736,                  584,                  304,                  675,                 1498,               4464],
]

def column(array, selected_column_index):
    return [
        item
        for row_index, row in enumerate(array)
        for column_index, item in enumerate(row)
        if column_index == selected_column_index and row_index > 0
    ]

(figure, axes) = plt.subplots(figsize=(20, 10))
axes.set_title("Compilation time of benchmarked projects across compiler versions (smaller projects)")
axes.set_xlabel("solc version")
axes.set_ylabel("Compilation time (seconds)")
for y_column in range(1, len(time[0]) - 2):
    plot = axes.plot(column(time, 0), column(time, y_column), label=time[0][y_column])
axes.set_ylim(bottom=0)
axes.legend()
axes.grid()
plt.savefig('compilation-time-smaller-projects.svg')

(figure, axes) = plt.subplots(figsize=(20, 10))
axes.set_title("Compilation time of benchmarked projects across compiler versions (bigger projects)")
axes.set_xlabel("solc version")
axes.set_ylabel("Compilation time (seconds)")
for y_column in range(len(time[0]) - 2, len(time[0])):
    plot = axes.plot(column(time, 0), column(time, y_column), label=time[0][y_column])
axes.set_ylim(bottom=0)
axes.legend()
axes.grid()
plt.savefig('compilation-time-bigger-projects.svg')

(figure, axes) = plt.subplots(figsize=(20, 10))
axes.set_title("Peak memory use during compilation of benchmarked projects across compiler versions")
axes.set_xlabel("solc version")
axes.set_ylabel("Peak memory (MiB)")
for y_column in range(1, len(memory[0])):
    plot = axes.plot(column(memory, 0), column(memory, y_column), label=memory[0][y_column])
axes.set_ylim(bottom=0)
axes.legend()
axes.grid()
plt.savefig('peak-memory-use.svg')

(figure, axes) = plt.subplots(figsize=(20, 10))
axes.set_title("Compilation time of benchmarked projects across compiler versions (part 1)")
axes.set_xlabel("solc version")
axes.set_ylabel("Compilation time (seconds)")
plot = axes.plot(column(time, 0), column(time, 3), label="OpenZeppelin")
plot = axes.plot(column(time, 0), column(time, 5), label="Uniswap")
axes.set_ylim(bottom=0)
axes.legend()
axes.grid()
plt.savefig('compilation-time-oz-uniswap.svg')

(figure, axes) = plt.subplots(figsize=(20, 10))
axes.set_title("Compilation time of benchmarked projects across compiler versions (part 2)")
axes.set_xlabel("solc version")
axes.set_ylabel("Compilation time (seconds)")
plot = axes.plot(column(time, 0), column(time, 8), label="Eigenlayer")
axes.set_ylim(bottom=0)
axes.set_xlim(left=0)
axes.legend()
axes.grid()
plt.savefig('compilation-time-eigenlayer.svg')

plt.show()

@cameel
Copy link
Member Author

cameel commented Nov 1, 2024

Summary

Overall impact

Overall we can summarize that compared to 0.8.18 compilation time went down by:

  • 50% for OpenZeppelin
  • 69% for Uniswap
  • 81% for Eigenlayer

Or, compared to 0.8.15, which seems to have been the slowest:

  • 55% for OpenZeppelin
  • 73% for Uniswap

This is of course for older versions of projects, which should be noted:

  • OpenZeppelin 4.8.0
  • Uniswap snapshot from 2022-06-16
  • Eigenlayer 0.3.0

But this is in line with what we're seeing in incomplete data for newer versions. If anything, the newer versions seem to benefit more from these changes.

Plots vs changelog

The plots seem to mostly align with the entries from the changelog that I expected to have the biggest impact:

  • 0.8.28: General: Generate JSON representations of Yul ASTs only on demand to reduce memory usage.
  • 0.8.27: Yul Optimizer: Caching of optimized IR to speed up optimization of contracts with bytecode dependencies.
  • 0.8.26: Yul Optimizer: New, faster default optimizer step sequence.
  • 0.8.21: Yul Optimizer: Fix optimized IR being unnecessarily passed through the Yul optimizer again before bytecode generation.

There were a lot of smaller optimizations in optimizer steps before 0.8.21, but I'm not sure they are all listed in the changelog. Surprisingly, their impact seems to have been either very limited or overshadowed by other changes, because, at least based on the data we have here, the compilation time only started going significantly down with 0.8.21.

@cameel cameel force-pushed the external-benchmarks-for-older-solc branch 3 times, most recently from e2dc74c to 43f97b1 Compare November 1, 2024 04:44
@cameel cameel force-pushed the external-benchmarks-for-older-solc branch from 43f97b1 to 249c335 Compare November 1, 2024 04:44
@clonker
Copy link
Member

clonker commented Nov 1, 2024

We could have a plot with the speedup with respect to baseline (oldest version), so T_old / T_new - then there's also no problems with scales, either. And I would still like to see higher precision in the tables - especially when it's faster compilation times, averaged, and/or faster hardware, a second more or less can make a lot of difference.

@cameel
Copy link
Member Author

cameel commented Nov 8, 2024

Here's an attempt at the relative plots. Turned out surprisingly well despite the fact that we don't have a common baseline. I guess that's because the plots do mostly line up in the middle part.

compilation-time-change-vs-0 8 18
compilation-time-change-normalized

Script used to generate the plots
# Uses imports, data and `column()` from the previous script.

def make_relative(values, reference_value):
    return [
        round(value / reference_value * 100) if value is not None else None
        for value
        in values
    ]

(figure, axes) = plt.subplots(figsize=(20, 10))
axes.set_title("Change in compilation time of benchmarked projects across compiler versions, compared to solc 0.8.18")
axes.set_xlabel("solc version")
axes.set_ylabel("Compilation time (% of 0.8.18 time)")
for y_column in [4, 5, 8]:
    x_values = column(time, 0)
    y_values = column(time, y_column)
    reference_value = y_values[x_values.index("0.8.18")]
    plot = axes.plot(x_values, make_relative(y_values, reference_value), label=time[0][y_column])
axes.set_ylim(bottom=0)
axes.set_xlim(left=0)
axes.legend()
axes.grid()
plt.savefig('compilation-time-change-vs-0.8.18.svg')

(figure, axes) = plt.subplots(figsize=(20, 10))
axes.set_title("Change in compilation time of benchmarked projects across compiler versions (normalized)")
axes.set_ylabel("Compilation time (% of worst time)")
for y_column in [4, 5, 8]:
    x_values = column(time, 0)
    absolute_y_values = column(time, y_column)
    reference_value = max(x for x in absolute_y_values if x is not None)
    relative_y_values = make_relative(absolute_y_values, reference_value)
    plot = axes.plot(x_values, relative_y_values, label=time[0][y_column])

    first_non_empty_index = next(i for i, v in enumerate(absolute_y_values) if v is not None)
    axes.annotate(
        f"{absolute_y_values[first_non_empty_index]} s",
        (x_values[first_non_empty_index], relative_y_values[first_non_empty_index])
    )

axes.set_ylim(bottom=0)
axes.set_xlim(left=0)
axes.legend()
axes.grid()
plt.savefig('compilation-time-change-normalized.svg')

plt.show()

@cameel cameel merged commit 323ad93 into develop Nov 8, 2024
73 checks passed
@cameel cameel deleted the external-benchmarks-for-older-solc branch November 8, 2024 01:51
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.

2 participants