cry-wasm speeds up Ruby code using Crystal
OTHER License
⚡ cry-wasm speeds up Ruby code.
By applying simple type restrictions to Ruby code, convert it to Crystal code, compile it to WebAssembly, and call it with Wasmer or Wasmtime.
👾 experimental
require 'cry/wasm'
class Fibonacci
extend Cry::Wasm # (1) Extend your class
cry [:Int32], :Int32 # (2) Write type signatures
def fib(n)
return 1 if n <= 2
fib(n - 1) + fib(n - 2)
end
cry_build # (3) Compile Wasm
end
Fibonacci.new.fib(40) # (4) Call Wasm Function
[arg_t1, arg_t2], ret_t
(Symbol or String).fib_bench.rb - 10 x faster on the Fibonacci benchmark.
user system total real
ruby fib(40) 5.305503 0.000000 5.305503 ( 5.305696)
wasmtime fib(40) 0.462232 0.000000 0.462232 ( 0.462247)
wasmer fib(40) 0.381384 0.000000 0.381384 ( 0.381401)
flowchart LR
style id1 fill:#c5c,stroke:#f66,stroke-width:1px,color:#fff
style id2 fill:#555,stroke:#3ff,stroke-width:1px,color:#fff
style id3 fill:#66f,stroke:#f66,stroke-width:1px,color:#fff
style id4 fill:#c5c,stroke:#ff1,stroke-width:1px,color:#fff
id1(Ruby Methods) -- Ripper + Sorcerer --> id2(Crystal Functions) -- Crystal Compiler --> id3[WebAssembly]
id4(Ruby Code) <-- Wasmer/Wasmtime --> id3[WebAssembly]
cry
method to restrict argument types and return types.cry_build
method to build the crystal code blocks.cry_load(path)
to pre-load your crystal source code.Ruby class | Crystal class |
---|---|
Integer |
UInt8 Int8 UInt16 Int16 UInt32 Int32 UInt64 Int64
|
Float |
Float32 Float64
|
Array<Integer> |
UInt8* Int8* UInt16* Int16* UInt32* Int32* UInt64* Int64*
|
Array<Integer> |
Array(UInt8) Array(Int8) Array(UInt16) Array(Int16) Array(UInt32) Array(Int32) Array(UInt64) Array(Int64)
|
Array<Float> |
Float32* Float64*
|
Array<Float> |
Array(Float32) Array(Float32)
|
String |
String |
Crystal class | Ruby class |
---|---|
UInt8 Int8 UInt16 Int16 UInt32 Int32 UInt64 Int64
|
Integer |
Float32 Float64
|
Float |
UInt8* Int8* UInt16* Int16* UInt32* Int32*
|
View object of Wasmer (wasmer only) |
Array(UInt8) Array(Int8) Array(UInt16) Array(Int16) Array(UInt32) Array(Int32) Array(UInt64) Array(Int64)
|
Array<Integer> |
Array(Float32) Array(Float32)
|
Array<Float> |
String |
String |
Void |
Nil |
Symbol
not supported?In the Crystal language, Symbol is converted to an integer at compile time, so there is no way to get Symbol from a String; use String
instead of Symbol
.
Cry::Numeric
can use Refinements to add methods such as to_i8
, to_u8
, and to_f32
to Ruby's numeric classes. These methods are the same as to_i
and to_f
(the range of values is not checked). These are useful if you want to prevent errors when running your code as Ruby and get the same results as if you had run it as Crystal.
Currently reading memory in wasm and converting it to Ruby arrays takes quite a bit of time. As a result, it may take longer to run with cry-wasm than when run as pure Ruby. Also note that currently (2022/12) wasmtime-rb is faster than wasmer-ruby when it comes to reading memory. If you are interested in improving these issues, please consider contributing to wasmer-ruby or wasmtime-rb.
Requirements
brew install llvm
brew ls llvm | grep wasm-ld
.wasm-ld
can be called.sudo apt install lld
.dpkg -L lld | grep wasm-ld
.wasm-ld-9
or wasm-ld-10
.rake vendor:wasi_libs
task to download the libs to the vendor directory.CRYSTAL_LIBRARY_PATH
environment variable.Installation
bundle install
bundle exec rake vendor:wasi_libs
bundle exec rake install
Please note that cry-wasm depends on the latest API of wasmer-ruby and wasmtime-rb, so we have to use the GitHub master rather than the stable version.
Tested on macOS and Ubuntu using Github Actions. Windows is not yet supported.
git clone https://github.com/kojix2/cry-wasm
cd cry-wasm
bundle install
bundle exec rake vendor:wasi_libs
bundle exec rake spec
Even small improvements like fixing typos are welcome! Please feel free to send us your PR.
MIT