Hey,
I'm trying to replace wasmi with wasmtime in the following ZKWASM project https://github.com/DelphinusLab/zkWasm, in order to do that I need to get execution traces working with wasmtime, specifically traces for opcodes that run, memory read/writes and jumps.
As I understand wasmtime doesn't offer these features atm right?, I'd would love to be referred to relevant materials, src code, articles, libs and people that could help me code such a trace generator for wasmtime
:pray:
Could you clarify what you mean by a trace? Are you looking for something like a backtrace for all memory/jump opcodes that execute?
more like a trace of execution, all of the opcodes/memory/jumps that happened during the execution of code
Do you mean like a Vec<u32>
where each entry is the address of an opcode within the original wasm file?
In either case though I don't believe wasmtime currently supports this feature. I'm not sure there's prior art to draw on either, but if you're interested in seeing what it might take to implement it I'd recommend reading over wasmtime's cranelift lowering and how it interacts with the host through the VMContext
I mean something like this
ah sorry I don't know how to understand that picture myself (maybe others do?), but my guess is that Wasmtime doesn't currently have the native support to produce something like that
yeah the picture isn't so clear, sorry, it's basicly every opcode that ran in an execution. So your recommending that I read about cranelift lowering? Who would be the expert on that?
Yes I'd recommend reading up on the translation wasmtime does from wasm to cranelift.
I'll also point out though that while we can help with questions here if you're looking for more of a mentor relationship with a much higher bandwidth for questions about the code and implementation details I think it'd be best to line that up first. I'm not available for that myself. Without having someone set up ahead of time there may be some time between when questions are asked here and when someone gets to them, and some questions may go un-answered if they require a lot of context to boot up on and a chunk of time to answer as well
yeah I know these are difficult questions, I can arrange for some kind of payment if needed for someone that is well equipped to answer this question, pls lmk if there is someone that might be relevant for this, i feel like it has to be someone who has experience with cranelift?
Q: would it be possible to turn off the JIT in cranelift so that instructions aren't turned into machine code? <- we prob need this for the trace
I don't think payment is needed, this is mostly a question of bandwidth of team members -- I too have not much bandwidth available, but every once in a while I can answer a question on Zulip
to your question: no, there's no way to turn off JIT (or AOT) -- wasmtime+cranelift is fundamentally based on compiled code
to add tracing you'd want to insert calls to a "libcall" (call back into the runtime) at every point in the compiled code that you've executed another op
this is theoretically possible -- see translate_after_op
in cranelift/wasm/src/code_translator.rs (I think)
it'd just be really slow :-)
speed is definitely not a problem for us, because the proving stage is way slower,
i can't find translate_after_op in the whole repo, maybe there is a typo? would you be able to get the effects of the machine instruction by using libcall?
I don't remember the exact name but there is a hook that runs after translating every op, you'll have to find it by reading the code starting from FuncEnvironment
I think the easiest way to do this would be to add a script that inserts Wasm-level instrumentation before giving Wasmtime the Wasm. it could be done on a per-block level (or minimum spanning tree back edge if you want to get fancy)
then have your wasmtime embedding provide the host hooks that the instrumentation calls into
this wouldn't require any changes to wasmtime itself
@fitzgen (he/him) will i be able to get the SP, memory access and results after each instruction this way?
ah I thought you just wanted a trace of each wasm instruction executed.
this method will only give you wasm-level traces, not machine-level traces
@monkeyontheloose do you mean the machine SP, or the wasm virtual machine SP?
the VM SP and the VM memory
you can model that as part of instrumentation that you add to the wasm then -- I agree with @fitzgen (he/him) , that's the more elegant and overall simpler approach
fitzgen (he/him) said:
I think the easiest way to do this would be to add a script that inserts Wasm-level instrumentation before giving Wasmtime the Wasm. it could be done on a per-block level (or minimum spanning tree back edge if you want to get fancy)
hey @fitzgen (he/him) how would this design look like? is the plan to add a callback after each instruction? how will this work for jumps?
also what would be the best way to implement this? what tools should i use, articles i should read? :pray:
Given the suggestion of implementing this in pure wasm rather than wasmtime itself, you might be better off taking the discussion to a larger community, like the general wasm discord server (invite link here: https://webassembly.org/community/resources/)
thanks for the help guys, took this to the wasm discord, i guess you can wrap all the opcodes in a wasm file with tracing opcodes that call an imported function for logging, and with this create a full stack trace - total noob here but thats what im thinking right now
Q: do you guys think it might be possible to create full traces by running wasmtime in debug mode?
I'm guessing by "debug mode" you mean something like setting RUST_LOG=debug
in the environment? no, wasmtime tries to generate fast native code, so it doesn't call out to a runtime library or logging function for each wasm instruction. there is no way to trace the executed instructions except by changing what code is generated, and the easiest way to do that in this case is to modify the wasm you're running to do its own logging. that's especially important since wasmtime is an optimizing compiler and will re-order or delete instructions if it can do so without changing the results of the program, so even trying to trace what it actually ran would not give you the answer you're looking for.
Q1. is there no way to turn off the wasmtime compiler optimizer?
Q2. Can you run wasmtime in debug mode by connecting to a debugger (I am a noob in this area), like step by step, opcode by opcode?
Q3. I'm researching how to add log calls to make the wasm log it self, but it seems like a complex and patchy solution, what communities can I leverage for help on getting this done except webassembly.org's discord/reddit and stackoverflow, is there a place where really good wasm devs hang out?
ty!
Q1: No, many peephole optimizations happen while lowering from clif ir to machine code. These optimizations can't be disabled. Lowering from wasm to clif ir also erases all stack manipulation opcodes.
Q2: In debug mode the line tables applying to wasm are transformed into line tables applying to the produced machine code. The actual machine code is not affected, so if two source lines get lowered into a single instruction, only one of them wil be preserved in the final line table and if an instruction is optinized away, the respective line in the line table will be gone too if that was the only instruction at that line.
Question just to make sure I understand this correctly, is wasmtime the only runtime that implements component model wasm? Are there any runtime that are working or planning on support it?
Also, how does the component model work? is the host VM responsible for all the conversions? how do the executables differ from reg wasm?
is the host VM responsible for all the conversions?
Not necessarily. If a guest component is calling another guest component, the host may not be involved at all (apart from anything a particular VM may do to facilitate any core module->module export call).
how do the executables differ from reg wasm?
Yes. This is probably the best explanation of how they differ: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md
in addition to wasmtime, jco transpile
is an implementation the component model for js engines https://github.com/bytecodealliance/jco
Ryan Levick (rylev) said:
how do the executables differ from reg wasm?
Yes. This is probably the best explanation of how they differ: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md
I was wondering about how the binarys differ, is there a wasm2wat tool for component model wasm?
Pat Hickey said:
in addition to wasmtime,
jco transpile
is an implementation the component model for js engines https://github.com/bytecodealliance/jco
I mean are there any other wasm runtimes that are planning to support the component model? like ones that run on the host not on the browser
the wasm-tools
cli can perform wat to/from binary conversion and various other useful operations on components
jco works for node.js and other js engines running outside the browser. but as far as standalone wasm engines, to my knowledge none have shipped component support yet.
monkeyontheloose said:
is there a wasm2wat tool for component model wasm?
https://github.com/bytecodealliance/wasm-tools
wasm-tools print my-component.wasm
fitzgen (he/him) said:
I think the easiest way to do this would be to add a script that inserts Wasm-level instrumentation before giving Wasmtime the Wasm. it could be done on a per-block level (or minimum spanning tree back edge if you want to get fancy)
hey, im trying to implement this, what would be the best way to get this done? I want to support components and aslo use python, i know wasm-tools can decompile/compile into txt format, but I don't know what tools would be best to parse this txt in python, where do i search for lib that just does this? do i need to create bindings for wasm-tools libs?
monkeyontheloose said:
fitzgen (he/him) said:
I think the easiest way to do this would be to add a script that inserts Wasm-level instrumentation before giving Wasmtime the Wasm. it could be done on a per-block level (or minimum spanning tree back edge if you want to get fancy)
hey, im trying to implement this, what would be the best way to get this done? I want to support components and aslo use python, i know wasm-tools can decompile/compile into txt format, but I don't know what tools would be best to parse this txt in python, where do i search for lib that just does this? do i need to create bindings for wasm-tools libs?
@Alex Crichton can someone help me with this pls :pray:
Many of us are unlikely to have the time to mentor you on this task unfortunately (although someone else can jump in at any time of course). I don't have much to offer over what was said already, but this will likely require a good investment of time on your part if you'd like to see this work get done
sure, im going to get this done, you don't have to mentor me, i'm just asking about what libs are currently available (dono how to search for this, i asked bard and it hallucinates) that might help me with this task of loading wasm code (with and without component model) into python and then recompiling (not sure this is the right word) it
I'd recomend looking at this repository. That's all in Rust, however. I don't know if there are libraries for Python.
Last updated: Dec 23 2024 at 14:03 UTC