Exploring SIMD performance improvements in WebAssembly (2021)
awelm.com
awelm.com
#define ITERATIONS 1000
int main()
{
const size_t BUFFER_SIZE = 64ul \* 1024 \* 1024;
__m128i\* data_buffer = (__m128i *)memalign(64, BUFFER_SIZE);
const __m128i all_ones = _mm_set1_epi8(0xFF);
for (size_t i = 0; i < ITERATIONS; i++)
{
__m128i* data = data_buffer;
for (size_t b = 0; b < BUFFER_SIZE;) {
_mm_stream_si128(&data[0], all_ones);
_mm_stream_si128(&data[1], all_ones);
_mm_stream_si128(&data[2], all_ones);
_mm_stream_si128(&data[3], all_ones);
data += 4;
b += 16 * 4;
}
}
}
$ time ./fill_buffer.elf
real 0m1,832s
$ time ./wasmer fill_buffer.wasm -i fillBufferWithSIMD 1000
real 0m4,237s
I had to fixup the WAT because set_local and get_local don't exist anymore. They are called local.get and local.set now.At higher number of iterations the C version converges on about 1.7 seconds per 1000, while the WASM version seems to remain the same at 4.2 secs per 1000. This leaves native 2.5x faster for this particular operation, on my machine.
If native performance is "very very very" not fast enough then that's supercomputer work and it doesn't really matter if WASM is 3x native or 0.3x native. So that context should be where you're the least depressed.
today's laptop work is late 90's supercomputer's work (and it was even more depressing back then).
That doesn't really change my argument. When you're looking at languages that are used for small tasks today, their speed doesn't have much relevance to how vastly bigger tasks are accomplished. And by the time those tasks can be run on a laptop, WASM implementations are going to be much better and we still might not be using it at all for those larger tasks.
Have you tried with the llvm backend? I believe the results might be even better there!
$ time ./wasmer run --llvm fill_buffer.wasm -i fillBufferWithSIMD 1000real 0m5,233s
It seems to be a 25% longer run-time with LLVM backend. I did not know about that option! Very interesting.
Could you share the fill_buffer.wasm (or the WAT file) so I can do some tests? Thanks!
Hopefully I did not mess anything up!
But it seems that WebAssembly doesn't have length-agnostic SIMD instructions yet. There is an open proposal to add this though: https://github.com/WebAssembly/flexible-vectors
zig cc -Ofast --target=wasm32-wasi -mcpu=generic+simd128 example.c
zig c++ -Ofast --target=wasm32-wasi -mcpu=generic+simd128 example.cpp
Or with a build file: zig build -Drelease-fast -Dtarget=wasm32-wasi -Dcpu=generic+simd128[1] https://github.com/awelm/simd-wasm-profiling/blob/master/fil...