7 ms·
This is a good decision. SIMD.js never made sense to me. Writing vector code that outperforms scalar code requires not only fine-grained control over issues lik
by millstone 9y ago
This is a good decision. SIMD.js never made sense to me. Writing vector code that outperforms scalar code requires not only fine-grained control over issues like alignment, but also requires targeting specific SIMD instruction sets. You must write your vector code with the emitted assembly in mind, because if you fall off the fast path and the compiler switches to scalar code or does a library call or something, you've lost any performance gain and then some.
A generic SIMD API on a high-level language like JavaScript is as bad as it gets. I looked at what it would take to port some of my vector code to SIMD.js and it wasn't remotely plausible.
Also saving 10% of the v8 code size is enormous.
The right path forwards is for JITs to emit SIMD code when possible, and for JS engines to provide OpenCL-like GPGPU-targeted APIs, following the trail that WebGL blazed with JS shaders.
- pcwalton 9y ago> The right path forwards is for JITs to emit SIMD code when possible "Just rely on autovectorization" is what people have wanted to do for over a decade. We have yet to see satisfactory results for C. Why would JS be any easier? > and for JS engines to provide OpenCL-like GPGPU-targeted APIs, following the trail that WebGL blazed with JS shaders. Please don't! Nobody wants more APIs that rely on passing a string for a driver blob to compile. Standardize an IR (Web Assembly makes the most sense here).
- marmaduke 9y ago> We have yet to see satisfactory results for C... That's not a fair assessment. Major compilers (LLVM, GCC, Intel) are able to vectorize real world code to a useful extent. No, they won't reorganize data to be more SIMD friendly but they can take the hard work out of writing ISA specific assemmbly.
- dagss 9y agoI think the parent with "satisfactory" meant "possible to achieve the maximum performance the hardware will support" (after all why settle for less?) You are answering another question. Also, the point where you have reorganized your whole computation to be AVX-friendly it is just extra obfuscation to try to wrtie regular C and then check that the compiler outputs what you meant. Just using SIMD instructions is WYSIWYG; writing pure C is like competing in an obfuscated C contest. Keep in mind it is not only SIMD, one might use shuffles and permutations in registers etc to communicate between the SIMD "threads". I think the SSE/AVX intrinsics are nice to work with; they do what they say, but GCC will also turn them into something else if not supported, and perhaps apply some extra optimizations.
- marmaduke 9y agoYeah I didn't mean that I would be over backwards to make it work, just that I happen to see great speed ups for my real world code with almost no effort. For more complex stuff I'd be looking at ISPC or OpenCL before assembly since I can't afford to write ISA specific code.
- marmaduke 9y agoAlso, in my experience, maximum performance for most algorithms is not a clear cut line that I fall short of for lack of motivation. I see that maximum as a rather fuzzy unknown, approaching it is has diminishing returns on the time spent optimizing.
- brian-armstrong 9y agoThis isn't actually true for any meaningful speedup. You will at least need to use intrinsics to start to get as much as you can from the cpu
- marmaduke 9y agoThe C kernel I've written here https://github.com/numba/llvmlite/issues/270 https://github.com/numba/llvmlite/issues/270 is contrived but the structure resembles code I maintain related to differential equation integration. Autovec provides a very nice speed up for very little effort.
- tmyklebu 9y ago> Major compilers (LLVM, GCC, Intel) are able to vectorize real world code to a useful extent. Try compiling this with recent gcc: uint8_t dumb_checksum(uint8_t *ar) { uint8_t ans = 0; for (int i = 0; i < 320; i++) ans += ar[i]; return ans; } You don't get satisfactory results. I, at least, don't have a clear mental model of when gcc will do something reasonable and when it will generate a large amount of bad code.
- marmaduke 9y agoSure there are bugs. There are also compiler flags which elucidate the model of loops it has and how it makes its decisions.
- z3t4 9y agowhat about __wasm {} in JS !? you can sort of already do that.
- coldtea 9y ago>"Just rely on autovectorization" is what people have wanted to do for over a decade. We have yet to see satisfactory results for C. That's because C is crap in that aspect and doesn't give enough guarantees and intents. With a better language you could have great autovectorization in ever higher level code than C.
- sillysaurus3 9y agoThis is a good decision. SIMD.js never made sense to me. Writing vector code that outperforms scalar code requires not only fine-grained control over issues like alignment, but also requires targeting specific SIMD instruction sets. You must write your vector code with the emitted assembly in mind, because if you fall off the fast path and the compiler switches to scalar code or does a library call or something, you've lost any performance gain and then some. I think this highlights the absurdity of writing vector code in higher-level constructs rather than the direct ASM. Writing in ASM is not that hard, and the gains can be enormous. I've seen graphics operations sped up by 5x or more, just by writing hand-optimized vector ops in assembly. This is one of Visual Studio's core strengths vs GCC. Writing an __asm { } block is much more pleasant than the syntax GCC forces on you. Unfortunately this inertia is one reason games tend to be windows-only, even in the post-Apple era. In other words, phrases like "You must write your vector code with the emitted assembly in mind, because if you fall off the fast path and the compiler switches to scalar code" invokes a feeling of "What? Why does the compiler get any say in what the vector code looks like? Oh, right, everybody shies away from writing ASM by hand nowadays." Which is valid, but sometimes having ultra control is extremely nice. It just feels cool to get a 2x speedup by being persistent and clever. (Those speedups come with future technical debt, though, so there are good arguments against it.)
- sddfd 9y agoThe compiler should vectorize functions automatically, without user intervention. Writing assembly code to use SIMD instructions is a vote of no confidence on your compiler. If your compiler of choice can't do automatic vectorization switch to one that can, or get people to implement that feature in your compiler of choice.
- dagss 9y agoWell, the compilers don't do a good enough job, end of story (at least using C; not sure about OpenCL). To achieve top performance it is necessary to make sure everything in the computation is organized in the right way. And try out multiple strategies on the high level of the program, to see what achieves best performance at the low level. At that point, trying to obfuscate your SIMD logic in regular C so that the C compiler maybe figure out what you meant is just frustrating anyway. What you are saying is basically "you don't need top performance, just deal with what the compiler gives you". But sometimes you work on stuff where the whole point is to be best in class in performance (libsharp in my case). If you think that what you are suggesting is possible, feel free to improve the compilers so that normal C code beats OpenBLAS. You will be famous. I will wait....
- rurban 9y agoYes, their explanation is here: https://bugs.chromium.org/p/v8/issues/detail?id=6020&desc=2 https://bugs.chromium.org/p/v8/issues/detail?id=6020&desc=2 Supporting it in WebAssembly transparently is a much better way to go forward.
- markdog12 9y ago> A generic SIMD API on a high-level language like JavaScript is as bad as it gets. Dart VM SIMD API seems pretty nice to me: https://www.dartlang.org/articles/dart-vm/simd https://www.dartlang.org/articles/dart-vm/simd double computeAverage(Float32x4List list) { Float32x4 sum = new Float32x4.zero(); for (int i = 0; i < list.length; i++) { sum += list[i]; } // Perform horizontal operations once. double average = sum.x + sum.y + sum.z + sum.w; return average / (list.length*4); } You may not be able to squeeze out the same perf, but seems worth having to me. > JS engines to provide OpenCL-like GPGPU-targeted API This is an interesting project, deep neural nets running on WebGPU: https://mil-tokyo.github.io/webdnn/ https://mil-tokyo.github.io/webdnn/