Conversation
|
Is it possible to instead use rule priorities to optimize the schedule instead? Would that yield the same performance benefit? Then, we wouldn't have as much duplication of the logic there. |
|
Another option would be to implement each schedule option/flag once, but wiht |
|
I'm not sure how you would use rule priorities to implement a constant-time algorithm here. At most you might save some of the time spent evaluating side conditions, but you would still end up having to recursively invoke the schedule operator a linear number of times in the number of hard forks. Even with this optimization, this function is a hotspot in the performance profile, so I don't think it's a good idea to keep a linear-time algorithm here, especially as the number of hard forks is only going to keep increasing. Using an |
|
Yeah, I figure that encoding it via the priorities will be faster than via function evaluation simply because it's built into the matcher directly. But who knows? Let me know how the experiment goes! |
|
I don't think that there is a major issue with maintaining all of the information explicitly per schedule, as @dwightguth suggests. The values should never be changed for previous schedules, and can easily be added for new schedules as well, by copying the values for the previous schedule and going from there. There is repetition, yes, but there is also clarity. |
Previously we were implementing the gas schedule in schedule.md in a fairly modular way, with each schedule defined in terms of its difference from the previous hard fork. As the number of hard forks in KEVM has increased, however, this has gradually become a significant performance cost, because the most common case is the evaluation of the gas cost of opcodes that have not changed in cost since FRONTIER, as a result of which, we end up repeatedly evaluating rules that tell us that the gas cost can be looked up in a previous schedule.
To optimize this, we change schedule.md so that we directly emit each gas schedule to each hard fork so that the gas cost of any operand can be looked up directly using pattern matching on the arguments. The resulting code is slightly less modular, but it also has the advantage of being somewhat more readable; it is easy to look up the exact cost of any constant in any given schedule directly in schedule.md without having to trace back and determine its exact value by following through all the forks of EVM.
There is one additional benefit to this approach: in later gas schedules, some of the constants in the schedule were defined in terms of other constants. However, the way this had been implemented in KEVM was such that if the dependent constant changed in a future hard fork, we would still have to update both constants in schedule.md. This gave the appearance of increased modularity, when in fact no such modularity actually existed. This change makes it much more apparent that such modularity does not in fact exist, thus decreasing the likelihood of bugs slipping through as a result of lack of test coverage when implementing a future hard fork.
There is one additional change that we make in this PR: we delete the
DEFAULTschedule. That schedule was essentially an alias forHOMESTEAD, but was deceptively named. Thus we replaceDEFAULTeverywhere explicitly withHOMESTEAD.