wazero
wazero copied to clipboard
Add option to limit CPU usage
split from #417 requested by @inkeliz
Also, would be interesting to limit the CPU usage, but I think it's hard to track the CPU usage, that could be more useful when WASM supports thread directly.
Prior art
- wasmtime re-implemented a Lucet feature similar to this https://github.com/bytecodealliance/wasmtime/pull/2611
- any credit/balance system ex https://httpwg.org/specs/rfc7540.html#WINDOW_UPDATE
Related
#421 could be a similar or the same implementation, as if you have a concept of a runtime-wide credit you can deplete it to stop all commands, though what happens when out of credit is likely different (exit instead of pause)
here's something from ewasm that may be relevant https://ewasm.readthedocs.io/en/mkdocs/determining_wasm_gas_costs/
@JanFalkin do you mind commenting on which metering/limiting features you need and any links if a standard practice?
@codefromthecrypt Our need was for actual billing for our content-fabric. Things we serve up and the effort to do so as a function of bitcode. Ultimately I would like to know cpu and memory usage of the bitcode itself. I was hoping just for any type of metering even if they were pseudo cycles that had a basis in reality. This was one of the main reasons I was heading for Wasmer, as they have metering built in at an opcode level. So you can submit a list of "costs" per wasm opcode and Wasmer will track this as a measure of work done. I did not look that carefully at whether Wasmer was using a Cranelift feature or it had implemented it's own opcode metering. As for limiting execution, it would be very interesting, but it was not our must have at release features.
👋 , having used the fuel feature in Wasmtime linked above, that's also something that I would love to be able to use in wazero. The main benefits would:
- guarantee that a process will eventually stop – when running out of fuel
- it could provide the necessary hook points to yield to the host to be able to interrupt execution based on external signals.
thanks @pims I can see some related pull requests on wasmtime, and also they had another impl iirc also. sounds like the status quo "fuel" one is good enough. there are differences between this and wasmer, and also its inspiration. I wonder if anyone has it speced or this will be the only thing they decide not to make into a new wasm/wasi spec? :D
@evacchi wanna take this from analysis to some form of impl once we're through the 1.0 stdlib/wasi gauntlet?
Set gas for each WASM instruction, support host function custom setting gas value, so that the gas used by wasm execution is calculated, and if the gas limit is exceeded, wasm will automatically exit, which will be simpler than calculating the CPU and other methods, and also meet the basic needs
@springrain For those of of us that want to use this as more of a "metering" then your minimal feature isn't quite enough. Perhaps a WithGasExhaustedCallback(...func name..) which is called when gas is exhausted and can return either true or false with false meaning "kill the wasm program".
The reason this is so important to folks like me is precisely because we want to kill programs that exhaust their gas ... but we want to have some mode of operational testing so folks can "get a notice" when their gas is exhausted, but not exit. Without this, the exit of the program is very hard to avoid as you would have no data about what you can/cannot do without running out of gas.
@iansmith Calculating gas is the core function, and the exit logic of gas exhaustion can add a function configuration WithGasExhaustedCallback(...func name..)
There are some technical notes in https://github.com/tetratelabs/wazero/pull/1108 as to why we closed this issue. This will remain closed until we have new information. It won't be re-opened without new information.
@codefromthecrypt I've read #1108 and any related issues, but I still don't understand what's blocking this implementation. Especially everything related to the gas/ cost implementation.
#1108 mentions that the newly added flag (WithCloseOnContextDone) may be used to implement such a cost thing. But as of now, I don't see a possibility to implement it – there's is no interpretation middleware/ hook option; no statistics; etc.
WithCloseOnContextDone allows you to kill your guest asynchronously, do it easily based on a time limit, or any other signal that can be wrapped in a Context which is the standard way to do it in Go.
WithMemoryLimitPages let's you limit memory.
For IO you can use FunctionListenerFactory to "meter" WASI/host function calls, and cancel a Context if a limit is exceeded.
All of this is supported, and only tracing IO depends on experimental features.
I'm a maintainer, but not the project lead, so take the rest of this post with a grain of salt. That said…
What you're asking for is to, instead, somehow, assign a (configurable?) cost to each WASM instruction and WASI/host call, track this cost at runtime, allow you (the guest?) to query this cost, and kill the guest according to this cost instead of Context cancellation.
This is a lot of work, both design/architecture/development work (we need to decide what "cost" is, design an API to configure it, rearchitect the project to measure it, implement and test the whole thing) and a lot of runtime work (every WASM instruction, every host function call, needs to add to this cost, vs. now periodically, checking if the context is done).
The naïve implementation would be so slow you wouldn't want it, we'd need an optimising compiler (currently in development) to make it remotely palatable.
If lots of people coalesce around this being important, and on a coherent, detailed feature request, it should have legs to stand on. Drive by requests, are much less likely to get traction.