[HN Gopher] Exploring SIMD performance improvements in WebAssemb...
       ___________________________________________________________________
        
       Exploring SIMD performance improvements in WebAssembly (2021)
        
       Author : hackthesystem
       Score  : 49 points
       Date   : 2022-02-02 18:06 UTC (4 hours ago)
        
 (HTM) web link (www.awelm.com)
 (TXT) w3m dump (www.awelm.com)
        
       | fwsgonzo wrote:
       | I compared against native:                 #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.
        
       | akireu wrote:
       | It looks promising! But fixed-width lanes don't seem too cross-
       | platform? I don't just mean the v256 and v512 types that may
       | become ubiquitous in a few years, but also things like optimizing
       | for different L1 cache sizes, doing some operation macro-fusion
       | on the SIMD unit, or directly supporting leading/trailing
       | elements to reduce code size?
        
         | kevingadd wrote:
         | In practice it's not possible to optimize "generally" for all
         | possible target architectures your wasm will run on. You're
         | going to optimize for x86-64 or ARM, and probably going to
         | specifically optimize for modern intel, modern amd, or apple's
         | m1. If you try to optimize for everything you're going to run
         | into really painful tradeoffs and probably have mediocre
         | performance on a bunch of architectures after a lot of hard
         | work.
        
           | akireu wrote:
           | Why not? Fixed-size SIMD architectures use mostly the same
           | operations, so if you target SSE2 initially, the code should
           | run just fine on NEON. A runtime that ships a JIT compiler
           | also has the unique opportunity to further optimize SIMD code
           | by using more lanes or limiting the working set to the host
           | platform's L1 cache size. Even the AOT compilers like GCC or
           | clang emulate platform-specific intrinsics using generic
           | vector ones. This should count for something, no?
        
             | TinkersW wrote:
             | They are similar but not the same, for instance SSE has
             | movemask, but NEON does not, so it gets emulated(slowly)
             | when targeting that platform. The cross lane ops are
             | different enough that you might need to rewrite for other
             | platforms. And then you run into situations where an
             | instruction is very fast on one architecture but horribly
             | slow on another because its basically emulated.
        
         | hackthesystem wrote:
         | Thanks! Good points, I think in general the fixed-width
         | "packed" SIMD ISAs have the downsides that you mentioned.
         | 
         | 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
        
       | akireu wrote:
       | Did a similar test in plain C: https://godbolt.org/z/ffYcWhxz3
       | It's not quite the same: I've used an increment instead of
       | zeroing, otherwise the entire benchmark gets optimized away.
       | Still got just about the same result (3.7x speedup for 100
       | iterations), so wasm did good there. Actually, now that I think
       | of it, SIMD code performance probably depends on good register
       | allocation more than on any optimization.
        
       | nyanpasu64 wrote:
       | I wonder if the 4x performance boost of 128-bit SIMD over 32-bit
       | would drop to 2x if WebAssembly added 64-bit
       | registers/instructions.
        
         | hackthesystem wrote:
         | I actually tried comparing 128-bit SIMD to the 64-bit
         | performance and the difference was 2x. I only published the
         | results for the 4x comparison, but it should be pretty easy to
         | reproduce if you change the types in the non-SIMD code[1] from
         | i32 -> i64.
         | 
         | [1] https://github.com/awelm/simd-wasm-
         | profiling/blob/master/fil...
        
         | nynx wrote:
         | Webassembly has 64-bit locals and instructions.
        
       ___________________________________________________________________
       (page generated 2022-02-02 23:01 UTC)