Wasm-bindgen performance

Here is a simple example of using wasm-bindgen to call Rust functions from JavaScript.

This file (wasm-bind-demo/index.js at e37f8359b291a090341f3684515ee908e238616f · mvolkmann/wasm-bind-demo · GitHub) creates an array of 10 million random floating point numbers in a Float64Array.

It then calls a Rust function (wasm-bind-demo/lib.rs at e37f8359b291a090341f3684515ee908e238616f · mvolkmann/wasm-bind-demo · GitHub) to sum them, tracking the milliseconds required.

Then it does the same using a JavaScript function (wasm-bind-demo/index.js at e37f8359b291a090341f3684515ee908e238616f · mvolkmann/wasm-bind-demo · GitHub).

The Rust function takes about 10 times as long to run. Is there a more efficient way to make the Float64Array available to the Rust code?

Using this approach in the Rust code makes the performance even worse:

#[wasm_bindgen]
pub fn sum(arr: &Float64Array) -> f64 {
   let len = arr.length();
   let mut sum = 0.0;
   for i in 0..len {
       sum += arr.get_index(i);
   }
   sum
}

Moving data between JS and Rust will never be free.
And if you are doing very little work with the data, I doubt Rust will ever have a chance.
JIT compilers have gotten pretty good, and they don't have to copy any data.

I don't want to move the data. I want to use shared memory, but I haven't been able to arrive at the syntax for doing that yet.

#[wasm_bindgen]
struct Array {
    data: Vec<f64>
}

#[wasm_bindgen]
impl Array {
    pub fn new(size: usize) -> Array {
        Array { data: vec![0.0, size] }
    }
    pub fn arraybuffer(&mut self) -> Float64Array {
        unsafe {
            Float64Array::view_mut_raw(
                 self.data.as_mut_ptr(),
                 self.data.len()
            )
        }
    }
    pub fn sum(&self) -> f64 {
        self.data.iter().sum()
    }
}

however…

Views into WebAssembly memory are only valid so long as the backing buffer isn't resized in JS. Once this function is called any future calls to Box::new (or malloc of any form) may cause the returned value here to be invalidated. Use with caution!

You would call that function and fill the returned array in JS

let array = Array::new(1024);
let buffer = array.arraybuffer();
// fill buffer
let sum = array.sum();

There seems to be an issue with the JS syntax at the end of your last reply.
What is the current way to call the new function from JS?

Indeed.
The correct way is described here:
https://rustwasm.github.io/docs/wasm-bindgen/reference/attributes/on-rust-exports/constructor.html

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.