Skip to content
Permalink
Browse files

Add 'matrix multiplication' algorithm for Rust

  • Loading branch information...
marcomontalbano committed Feb 25, 2019
1 parent 700ea03 commit 75f3f82eee5caf0357bdca411bd46ac1f58d84e0
Showing with 86 additions and 18 deletions.
  1. +5 −5 README.md
  2. +1 −1 package.json
  3. +16 −2 src-js/libs/matrix.js
  4. +10 −2 src-js/libs/matrix.test.js
  5. +1 −4 src-js/main.js
  6. +2 −2 src-js/web/chart.js
  7. +1 −1 src-js/web/utility.js
  8. +47 −0 src/libs/matrix.rs
  9. +1 −0 src/libs/mod.rs
  10. +2 −1 src/main.rs
@@ -86,16 +86,16 @@ $ cargo build --release
Now that we have built our code, we can run it:

```sh
$ ./target/release/wa-vs-js-benchmark get_primes 11
$ ./target/release/wa-vs-js-benchmark primes-get_primes 11
```

We can also use `cargo run` to compile and then run it, all in one step:

```sh
$ cargo run get_primes 11
$ cargo run primes-get_primes 11
# compile and run our project with optimizations
$ cargo run --release get_primes 11
$ cargo run --release primes-get_primes 11
```

Last but not least, we'll compile our project to `.wasm`:
@@ -148,12 +148,12 @@ These benchmarks are recorded on a MacBook Pro (15-inch, 2016) having these spec

```sh
cargo build --release
hyperfine --warmup 3 './target/release/wa-vs-js-benchmark get_primes 100000'
hyperfine --warmup 3 './target/release/wa-vs-js-benchmark primes-get_primes 100000'
```

| Command | Mean [s] | Min…Max [s] |
|:---|---:|---:|
| `./target/release/wa-vs-js-benchmark get_primes 100000` | 1.204 ± 0.012 | 1.193…1.235 |
| `./target/release/wa-vs-js-benchmark primes-get_primes 100000` | 1.204 ± 0.012 | 1.193…1.235 |


### WebAssembly vs Javascript
@@ -18,7 +18,7 @@
"build:rs": "cargo build --release",
"build:js": "webpack --mode=production --config webpack.config.js",
"build": "npm run build:wasm && npm run build:js",
"benchmark": "npm run build:rs && hyperfine --export-markdown BENCHMARK.md --warmup 3 './target/release/wa-vs-js-benchmark get_primes 100000'",
"benchmark": "npm run build:rs && hyperfine --export-markdown BENCHMARK.md --warmup 3 './target/release/wa-vs-js-benchmark primes-get_primes 100000'",
"publish": "gh-pages -m 'Publish website.' -b 'gh-pages' -d 'dist' -r \"https://$GH_TOKEN@github.com/marcomontalbano/wa-vs-js-benchmark\""
},
"dependencies": {
@@ -1,4 +1,4 @@
export const multiply = (a, b) => {
export const _multiply = (a, b) => {
let c = [];
for (let i = 0; i < a.length; i++) {
for (let j = 0; j < b[0].length; j++) {
@@ -12,7 +12,14 @@ export const multiply = (a, b) => {
return c;
};

export const multiply_slower = (a, b) => {
export const multiply = (a, b) => {
return _multiply(
Array(a).fill(Array(a).fill(1)),
Array(b).fill(Array(b).fill(1)),
)[0][0];
};

export const _multiply_slower = (a, b) => {
let c = [];
for (let k = 0; k < b.length; k++) {
for (let j = 0; j < b[0].length; j++) {
@@ -25,3 +32,10 @@ export const multiply_slower = (a, b) => {
}
return c;
};

export const multiply_slower = (a, b) => {
return _multiply_slower(
Array(a).fill(Array(a).fill(1)),
Array(b).fill(Array(b).fill(1)),
)[0][0];
};
@@ -72,6 +72,14 @@ const createTestFor = method => {
}

describe('matrix', () => {
createTestFor('multiply');
createTestFor('multiply_slower');
createTestFor('_multiply');
createTestFor('_multiply_slower');

it('.multiply()', () => {
assert.deepEqual(matrix.multiply(10, 10), 10);
});

it('.multiply_slower()', () => {
assert.deepEqual(matrix.multiply_slower(10, 10), 10);
});
});
@@ -7,8 +7,5 @@ import { createBenchmarkChart } from './web/chart';

createBenchmarkChart({
method: 'multiply',
args: [
Array(500).fill(Array(500).fill(1)),
Array(500).fill(Array(500).fill(1)),
]
args: [500, 500]
});
@@ -81,11 +81,11 @@ const _runBenchmark = (payload, chart, times = 5) => {
return runBenchmark(payload, times,
value => {
_chart_addData(chart, `${value.workerName.toUpperCase()} Benchmark`, value.performance.measure.duration.toFixed(2));
// console.log(value);
console.log(value);
return value;
}
).then(value => {
// console.log(value);
console.log(value);
});
}

@@ -52,7 +52,7 @@ const _promiseSequential = fns => {

export const runBenchmark = (payload, times = 5, eachTime = value => value) => {
return _promiseSequential(_cloneArrayElements([
// () => rsWorker.postMessage(payload).then(eachTime),
() => rsWorker.postMessage(payload).then(eachTime),
() => jsWorker.postMessage(payload).then(eachTime),
], times));
}
@@ -0,0 +1,47 @@
extern crate wasm_bindgen;

use wasm_bindgen::prelude::*;

#[allow(dead_code)]
fn _multiply(a: Vec<Vec<i32>>, b: Vec<Vec<i32>>) -> Vec<Vec<i32>> {

let mut c: Vec<Vec<i32>> = Vec::new();

for i in 0..a.len() {
c.push(vec![0; b.len()]);
for j in 0..b[0].len() {
for k in 0..b.len() {
c[i][j] += a[i][k] * b[k][j];
}
}
}

return c;
}

#[wasm_bindgen]
pub fn multiply(a: usize, b: usize) -> i32 {
return _multiply(
vec![vec![1; a]; a],
vec![vec![1; b]; b]
)[0][0];
}

#[cfg(test)]
mod tests {

use super::*;

#[test]
fn test_private_multiply() {
assert_eq!(_multiply(
vec![vec![1, 2], vec![3, 4]],
vec![vec![1, 2], vec![3, 4]]
), vec![vec![7, 10], vec![15, 22]]);
}

#[test]
fn test_multiply() {
assert_eq!(multiply(10,10), 10);
}
}
@@ -1 +1,2 @@
pub mod primes;
pub mod matrix;
@@ -16,7 +16,8 @@ fn main() {
let s: String = invoked_fn.into();

match &s[..] {
"get_primes" => Box::new(libs::primes::get_primes(args[0].parse().unwrap())),
"primes-get_primes" => Box::new(libs::primes::get_primes(args[0].parse().unwrap())),
"matrix-multiply" => Box::new(libs::matrix::multiply(args[0].parse().unwrap(), args[1].parse().unwrap())),
_ => {Box::new(0)}
};
}

0 comments on commit 75f3f82

Please sign in to comment.
You can’t perform that action at this time.