• Stars
    star
    28
  • Rank 882,216 (Top 18 %)
  • Language
    Ruby
  • License
    Other
  • Created almost 2 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

cry-wasm speeds up Ruby code using Crystal

cry-wasm

CI Docs Latest

⚑ 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

Quick Start

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
  1. Extend Cry::Wasm module to your Ruby class.
  2. Write Crystal type signatures for Ruby methods. The syntax is [arg_t1, arg_t2], ret_t (Symbol or String).
  3. Crystal compiler compile the Ruby methods into WebAssembly as Crystal functions.
  4. Finally, call the wasm function!

Benchmark

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)

  • In this benchmark, Wasmer is about 10% faster than Wasmtime as of December 2022.
  • Both Wasmer and Wasmtime tend to take a little longer for the first call. (see line graph at n=1)
  • Wasm is only about twice as slow as native functions, making it highly efficient. (according to my measurements)

How does this work?

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]
  1. Extend the Cry::Wasm module to the target class.
  2. Write the type information just before the method.
    1. Use the cry method to restrict argument types and return types.
  3. Once the method is defined, Cry::Wasm captures the source code.
    1. Ripper converts source code to S-expression.
    2. Extracts the S-expression of the target method from the S-expression.
    3. Sorcerer recovers the Ruby source code of the target method from the S-expression.
    4. Add Crystal type restrictions to the Ruby source code to generate a Crystal code block.
    5. Cry::Wasm stores the Crystal code block.
  4. The Crystal compiler and wasm-ld compile the Crystal code into WebAssembly.
    1. Call the cry_build method to build the crystal code blocks.
  5. The compiled byte_code is read, and an instance of Wasmer/Wasmtime is created.
  6. The target methods are dynamically redefined to call Wasmer/Wasmtime functions.

Usage

It define crystal functions, not Crystal methods

  • Default arguments, keyword arguments, and block arguments are not available.
  • Instance variables and class variables are not available on the top level function.
  • To use your own Crystal class, use cry_load(path) to pre-load your crystal source code.

Type conversion

Arguments ( Ruby --> Crystal )

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

Return values ( Crystal --> Ruby )

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

Why is 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 uses Refinement to add methods to Ruby's numeric classes

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.

Why is it very slow to return arrays?

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.

Installation

Requirements

  1. Crystal - Follow the installation instructions here for your platform.
  2. Rust - Rust is required to compile the wasmer-ruby or wasmtime-rb.
  3. LLVM for macOS:
    1. Install LLVM by running brew install llvm
    2. Find the path to wasm-ld by running brew ls llvm | grep wasm-ld.
    3. Set the PATH environment variable so that wasm-ld can be called.
  4. LLD for Ubuntu:
    1. Install LLD by running sudo apt install lld.
    2. Find the path to wasm-ld by running dpkg -L lld | grep wasm-ld.
    3. If necessary, create a symbolic link for wasm-ld-9 or wasm-ld-10.
  5. WebAssembly Libs for WASI
    1. Use the rake vendor:wasi_libs task to download the libs to the vendor directory.
    2. If you install the libs outside the given directory, set the 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.

Development

git clone https://github.com/kojix2/cry-wasm
cd cry-wasm
bundle install
bundle exec rake vendor:wasi_libs
bundle exec rake spec
  • Trying out WASM Support - A thread in the Crystal Forum on how to compile a wasm from crystal.
  • wasm-libs - WebAssembly Libs for WASI. You need to download the compiled wasm library.

Even small improvements like fixing typos are welcome! Please feel free to send us your PR.

license

MIT

More Repositories

1

LibUI

A portable GUI library for Ruby
Ruby
203
star
2

chatgpt-cli

Yet another ChatGPT command line tool
Crystal
25
star
3

deepl-cli

Simple command line tool for DeepL
Crystal
24
star
4

rubio-radio

Rubio is a simple GUI radio player
Ruby
14
star
5

ruby-minimap2

Powerful long read aligner for Ruby
Ruby
13
star
6

RDatasets

Ruby gem for loading datasets in R
Ruby
11
star
7

ruby-htslib

HTSlib bindings for Ruby
Ruby
10
star
8

ruby-umappp

Uniform Manifold Approximation and Projection for Ruby
C++
7
star
9

tiktoken-c

C API for tiktoken-rs
Rust
7
star
10

nuplot

Running Gnuplot with Crystal.
Crystal
6
star
11

ffi-bitfield

Bit field for Ruby-FFI
Ruby
5
star
12

rurema-chrome-extension

γ‚‹γ‚ŠγΎγ‚΅γƒΌγƒ
JavaScript
4
star
13

tiktoken-cr

Tiktoken for Crystalists
Crystal
4
star
14

blingfire-crystal

Crystal
3
star
15

ruby-alglib

C++
3
star
16

ruby-libssw

Fast Smith-Waterman algorithm for Ruby
Ruby
3
star
17

suikabox

Suika GUI
Ruby
3
star
18

seaborn-command

seaborn as a command line tool
Python
3
star
19

libui_paradise

[Unofficial] libui_paradise repository. This repository automatically fetches RubyGem and creates pull requests with Github Actions. The copyright of the code belongs to shevy, not to kojix2.
Ruby
2
star
20

covid-net-docker

Dockerfile
2
star
21

htsgrid

Simple HTS viewer
Ruby
2
star
22

chai

Daru https://github.com/SciRuby/daru
Ruby
2
star
23

zenity.cr

Zenity wrapper for Crystal
Crystal
2
star
24

icalmaker

Ruby
2
star
25

red-amber-view

R's View() for RedAmber
Ruby
2
star
26

ruby-edlib

ruby-edlib is a wrapper for edlib
C++
2
star
27

gray_scott_gtk3

Ruby implementation of the Reaction diffusion system (Gray-Scott model)
Ruby
2
star
28

ollamachat

Ruby
2
star
29

multipull

Git pull multiple repositories at once
Ruby
1
star
30

exline

Ruby
1
star
31

nn_visualization

Visualize neural network druby and Ruby/Tk using the MNIST
Ruby
1
star
32

sdust.cr

Reimplementation of Sdust in the Crystal language
Crystal
1
star
33

narray-vgg16

VGG16 object recognition network with Ruby NArray
Ruby
1
star
34

bat-c

C API for bat
Rust
1
star
35

cowsay.cr

The Crystal version of Cowsay
Crystal
1
star
36

syntect-c

Rust
1
star
37

wombat

Crystal
1
star
38

uing

experimental
C
1
star
39

pandoc-japanese-docker

Makefile
1
star
40

deepl.cr

Crystal library for the DeepL language translation API.
Crystal
1
star
41

randn.cr

Generate a normally-distributed random number
Crystal
1
star
42

fastx.cr

Crystal
1
star
43

kojix2

Forked from https://github.com/oprypin/oprypin
1
star
44

easyclip

Easy copy and paste for Crystal
Crystal
1
star
45

nworkers.cr

Crystal
1
star