-
Notifications
You must be signed in to change notification settings - Fork 746
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
contracts: Support RISC-V bytecode #115
Comments
Just a quick FYI to anyone reading - regarding my RISC-V experiment, soon I will be writing a more detailed writeup of my research into this and what I've learned in more detail (I just need to finish dealing with some higher priority issues first). The TLDR version is that the RISC-V target is very promising, we should explore it further, and in my opinion is definitely a better target than eBPF in almost every aspect. |
Here's a link to the full writeup of my experience: https://forum.polkadot.network/t/exploring-alternatives-to-wasm-for-smart-contracts/2434 |
Can we make it directly support LLVM ByteCode? |
I don't think that's a good idea. LLVM bytecode is significantly more complex, will arbitrarily change in the future (it's not a stable target like RISC-V is) and requires costly register allocation step to JIT it into native code (since it's in the SSA form). It essentially has all of the downsides of WASM, and more. |
Question: if the goal is optimize the smart-contract execution, I also think you must also consider update the SEAL interface for something that more likely supports parallel smart-contract execution. Solana have a solution called Sealevel, which basically allows them to deterministically execute smart-contracts in parallel:
Support for parallelism must be thinking from the beginning, and honestly must be considered for the Runtime too, the support for |
Nvm, it was already explored by wasmi: wasmi-labs/wasmi#314 (comment) |
I'd say the main goal is simplification; extra performance's just a bonus.
It's a neat idea for speeding up interpreters, but from the example generated machine code in the README it most likely would be significantly slower. (For that particular example my RISC-V recompiler can directly map a RISC-V |
Ok now I'm confused, to be able to generate 1:1 machine code, you need to compile the RISC-V into Host's machine code, and the |
That's the plan, which is why it's important to keep it simple. |
I believe state parallelism remains a general parachain/parathread issue, not smart contract specific. We'll simply cram more parachain blocks into the window between relay chain blocks, so those blocks would not themselves be parallel, aka they have a sequence, but they'll all have different approval checkers, so their workload becomes parallel to the relay chain and its validators. We'll hold inclusion and finality upon them all being included or approved. |
Please not discuss parallelism here. It is completely orthogonal and not at all related to pallet-contracts. If we ever decide that we want parallel runtimes (AFAIK as of right now we don't) we can look into this. I know about sea level and the required changes to our interface if that day will come. But it has nothing to do with RISC-V. |
Is it possible to do first step with gccrs ? As GCC already has RVE support in upstream? |
No. Right now
Doesn't matter. In the current experiment we're not even using the native stack at all. (Which could be worse for performance, but it's nice due to its simplicity.) |
Getting the patch into LLVM seems much closer than getting gcc to work. |
This issue has been mentioned on Polkadot Forum. There might be relevant details there: https://forum.polkadot.network/t/ebpf-contracts-hackathon/1084/13 |
This issue has been mentioned on Polkadot Forum. There might be relevant details there: https://forum.polkadot.network/t/polkadot-release-analysis-v1-5-0/5358/1 |
Some updates:
|
* fix coverage * fix codecov config --------- Co-authored-by: claravanstaden <Cats 4 life!>
Run RISC-V contracts with: https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/revive |
Here is a write up by @koute with more information: https://forum.polkadot.network/t/exploring-alternatives-to-wasm-for-smart-contracts/2434
Why we need a new bytecode
The idea of supporting an alternative to WebAssembly (wasm) on
pallet-contracts
is an idea that developed for the last couple of month. It started with discussions between various engineers. We came to the conclusion that wasm is not the optimal byte code to formulate contracts in. It comes down to few key insights but from which a lot of consequences arise:The bottom line is that we want a different byte code that does not have this properties. It was unclear so far if want to use an existing architecture or write our own (based on an existing design of course).
First trial: BPF
As a first attempt to check whether supporting a new bytecode is viable we hacked together a node which supports the BPF on pallet-contracts. I strongly recommend reading this report: https://forum.polkadot.network/t/ebpf-contracts-hackathon/1084
eBPF is an interesting target because it is designed to be trivially compileable to the architectures the Linux kernel supports. Essentially just a mapping between instructions. The key inside is that it needs to be RISC and low general purpose register count at the same time. However, BPF has its problems. It is not designed for performance and the upstream LLVM backend doesn't compile all code. This is because it is designed for in-kernel use. Hence we can't use the stock Rust compiler.
While this was an interesting experiment it is probably not the bytecode we want to settle for.
Better: RISC-V
This is another bytecode that was floated as a candidate for a while. It is a logical choice: A modern clean sheet design that is modular instead of incremental just as wasm is. Quite exceptional for a real world architecture. That allows us to only support the instructions we need for contracts. The only downside when compared to BPF is that it has
32
general purpose registers instead of11
. This is a problem as our main host architectureamd64
has only16
registers. This prevents us from mapping RISC-V registers 1to1 to native host registers. But being able to do that is what enables us to have the best of both worlds: Compile as fast as wasmi while emitting code that performs in the same order of magnitude as native code.However, after reaching out to @koute for help he came to the conclusion that RISC-V is still a viable target and we have the following option which all come with their caveats:
riscv32e
target for contracts which has a reduced register set (16 regs). This is the preferred solution. However, the LLVM backend for this target is not merged and hence it is not yet supported by upstream Rust.riscv32i
(32 regs) program to ariscv32e
program. This would be added tocargo-contract
. Since it happens offline it can do non linear optimizations and register allocations. However, writing and maintaining this would probably be more work than just spilling the registers in JIT. It might still be worth it to reduce complexity of consensus critical code.I cannot stress enough how instrumental @koute was for the research into RISC-V. He wrote a RISC-V to amd64 JIT in a day to proof that the plan to have a trivial JIT is viable. This is why we can be somewhat confident that RISC-V is the way forward.
This is the execution performance of that JIT (lower is better):
Keep in mind that zero optimization went into the JIT. It is a completely naive implementation just to proof that it works. It is reasonable to expect that we eventually perform better than wasmer singlepass while having interpreter style startup speeds.
cc @pepyakin
Next Steps
The text was updated successfully, but these errors were encountered: