Apologies for the broad question! I'm learning WASM and have created a Mandelbrot algorithm in C:
int iterateEquation(float x0, float y0, int maxiterations) {
float a = 0, b = 0, rx = 0, ry = 0;
int iterations = 0;
while (iterations < maxiterations && (rx * rx + ry * ry <= 4.0)) {
rx = a * a - b * b + x0;
ry = 2.0 * a * b + y0;
a = rx;
b = ry;
iterations++;
}
return iterations;
}
void mandelbrot(int *buf, float width, float height) {
for(float x = 0.0; x < width; x++) {
for(float y = 0.0; y < height; y++) {
// map to mandelbrot coordinates
float cx = (x - 150.0) / 100.0;
float cy = (y - 75.0) / 100.0;
int iterations = iterateEquation(cx, cy, 1000);
int loc = ((x + y * width) * 4);
// set the red and alpha components
*(buf + loc) = iterations > 100 ? 255 : 0;
*(buf + (loc+3)) = 255;
}
}
}
I'm compiling to WASM as follows (filename input / output omitted for clarity)
clang -emit-llvm -O3 --target=wasm32 ...
llc -march=wasm32 -filetype=asm ...
s2wasm --initial-memory 6553600 ...
wat2wasm ...
I'm loading in JavaScript, compiling, then invoking as follows:
instance.exports.mandelbrot(0, 300, 150)
The output is being copied to a canvas, which enables me to verify that it is executed correctly. On my computer the above function takes around 120ms to execute.
However, here's a JavaScript equivalent:
const iterateEquation = (x0, y0, maxiterations) => {
let a = 0, b = 0, rx = 0, ry = 0;
let iterations = 0;
while (iterations < maxiterations && (rx * rx + ry * ry <= 4)) {
rx = a * a - b * b + x0;
ry = 2 * a * b + y0;
a = rx;
b = ry;
iterations++;
}
return iterations;
}
const mandelbrot = (data) => {
for (var x = 0; x < 300; x++) {
for (var y = 0; y < 150; y++) {
const cx = (x - 150) / 100;
const cy = (y - 75) / 100;
const res = iterateEquation(cx, cy, 1000);
const idx = (x + y * 300) * 4;
data[idx] = res > 100 ? 255 : 0;
data[idx+3] = 255;
}
}
}
Which only takes ~62ms to execute.
Now I know WebAssembly is very new, and is not terribly optimised. But I can't help feeling that it should be faster than this!
Can anyone spot something obvious I might have missed?
Also, my C code writes directly to memory starting at '0' - I am wondering if this is safe? Where is the stack stored in the paged linear memory? Am I going to risk overwriting it?
Here's a fiddle to illustrate:
https://wasdk.github.io/WasmFiddle/?jvoh5
When run, it logs the timings of the two equivalent implementations (WASM then JavaScript)