We can use exactly the same trick that Sergei came up with and do asynchronous gas metering, and the implementation should be fairly trivial. (Mostly because I knew I’ll be doing it right from the start, so the VM is designed to make it easy.)
So essentially there are two approaches to gas metering:
- The traditional way: at each basic block consume gas and synchronously check if we’re out of gas; if we are, then trap. This will deterministically always trap at the same place.
- The asynchronous way that Sergei came up with: at each basic block consume gas, but do not check it right away. Instead check it 1) periodically from a separate auxiliary thread, and 2) check it once the guest program finishes. This removes an extra branch at each basic block, so it’s a lot faster. The major downside here is that it’s not deterministic where/when exactly it will trap. What is deterministic however is whether the whole execution finishes successfully or fails due to running out of gas, so if our executions are atomic anyway (that is, partial executions don’t change the state) then this approach can be used.
Recently I’ve been talking with Gav about some of his ideas, and unfortunately what he wants to do is fundamentally incompatible with asynchronous gas metering due to the exact interruption not being deterministic, so for that we might be forced to use the slower synchronous gas metering.
However, I have also been thinking about whether we couldn’t come up with a third way to do it, and I have a crazy idea I want to try out.
Here are the properties we’d like to have in an ideal gas metering scheme:
- It’s synchronous and always deterministically traps immediately when we run out of gas.
- It’s cheap, ideally a single machine instruction.
- It’s branchless, and the CPU will automatically notify us when we run out of gas.
- It doesn’t waste general purpose registers.
- It doesn’t unnecessarily pollute the CPU’s branch predictor, the TLB, the cache, etc.
- It doesn’t compete for CPU resources (execution ports, etc.) with the guest program.
So here’s the crazy idea: maybe we could do gas metering in floating point?
Unlike the CPU’s integer unit the FPU can be configured to automatically trap on underflow/overflow/etc., on modern superscalar CPUs the FPU runs concurrently with the integer units, and we don’t support floating point in our VM anyway so this part of the CPU is essentially completely unused and wasted. So… why don’t we just use it for gas metering? If it works it could be the holy grail - fast, deterministic and synchronous.
Now, don’t get too excited. I don’t know yet if this is possible. I haven’t seen anyone do this before. (Although I’ve seen a research paper where they did successfully use the FPU to speed up bounds checking of memory accesses.) It’s just a random idea I had that I will have to test out. I’m just putting it out here since you’ve asked.