Java and SIMD
prestodb.rocks
prestodb.rocks
Ten years ago, in the SSE2/Altivec times, I thought that it would be matter of time having much smarter compilers making graphics/pixel processing code much faster, but not. So for JIT the case it can not be better, because is similar, as even taking runtime information, the auto-vectorization phase is equivalent. I would love to see smarter compilers, understanding the code, many steps over current hardwired pattern-matching based optimizations.
[1] https://software.intel.com/sites/landingpage/IntrinsicsGuide...
I had this small and simple C application I'd written years earlier that tried to find inputs whose corresponding MD5 hashes started with certain bytes. It was a good base because it was obviously vectorizable.
At first enabling the vectorizer didn't result in any changes to the binaries. I then correctly guessed that (potentially) calling printf function inside a hot loop might confuse it. After slight refactoring I got the compiler to output SSE instructions, which resulted in a nice 2.5× testing speed over the original (incidentally even without auto-vectorizing the refactored code resulted in faster binaries, which is not all that surprising).
Anyway, I also rewrote the application to use intrinsics. I hadn't used them before myself, but it didn't really take much time at all familiarize myself with them and write the code, and it was indeed quite a bit faster than what the compiler was capable of with resulting binary having 14× speed compared to the original, or over 5× compared to what the compiler could achieve without explicit hints from intrinsics.
Edit: added back a few words I had accidentally removed when rearranging sentences, causing a confusing incomplete sentence. Corrected comparing figures like for like.
And that’s more or less what I’m planning to do in a programming language I’m working on, actually—if you use a SIMD-compatible array type, the compiler will try to keep it in a vector register, and some operations will be faster (e.g., “+” on two Float32^4 values will compile to an addps) but it’s up to the programmer to use the instructions they actually want, or tell the compiler with a macro “please vectorise this loop or warn me about why you can’t”.
Why do you think this is? Does C being difficult to reason about contribute (e.g. statefulness and not knowing what can modify what)?
I've done some SIMD and other optimisations on Android in C for graphics related algorithms and small changes and hints can make a x10 or more difference so I understand your point.
Additionally, C/C++ are languages where the default is "anything can alias anything" (restrict, until very recent standards, isn't the panacea people think it is) and worse, it's really easy to end up with loop dependences, as well as non-computable loop trip counts, as well. Don't forget alignment, too!
This means inserting runtime checks.
So, assuming the compiler can reorder the loop to vectorize it (and honestly, with polyhedral optimizations, it almost always can if it's at all possible to do so), the question is: is it worth it to vectorize a loop but have to insert 5-6 runtime checks to test for aliasing/etc.
The answer is usually no.
Vectorization, sadly, is not one of those things where more is always better.
Vectorizing every loop/straight line in a program will generally make things much much slower.
(because now you have limited the execution resources to do the computation :P)
This varies very heavily depending on the programming language :)
C/C++ is not a language that easily enables one to guarantee things about aliasing or loop dependence.
Something like that could perhaps also be useful for auto-vectorization.
It'll be interesting when we get to that point. I wonder if it'll be in ML or compilers that "cognition" happens first?
If you're doing any kind of rapid context switching, or multiple workloads, depending on how your scheduler is setup, the OTHER workloads will show up as using more percentage of CPU time per work item. It's non-intuitive, and difficult to debug.
Large companies run a benchmark after each instance startup to check how noisy that instance's neighbors are. If it's bad then they simply terminate the instance and start another one[0].
[0] https://www.reddit.com/r/aws/comments/547xbx/netflix_found_5...
More likely though, they'll continue not to care. Performance is already hideously variable, it'll just get a bit worse.
We're currently trying to figure out how to do deal with this. Some ideas come from Google's CPI2 paper, and trying to dynamically schedule workloads with diversity if we think they interfere. Other thoughts have been simpler, like core pinning (knapsacking for latency, or throughput).
this is hard.
Disclaimer: These views represent my own, and not my employer's, or their vendor's views
http://cr.openjdk.java.net/~vlivanov/talks/2017_Vectorization_in_HotSpot_JVM.pdfOn the other hand, if you are asking whether or not some magic compiler optimization will take your crappy code and make it run fast on SIMD, not only is that the wrong question but you have already lost the race.
The winners of the race asked the question, "How can we add a capability to our Java application to run computations fast using SIMD?" and they found number of ways to do this without relying on magic. It might be a bit of work to code because you have to do it with intent, like the old timers who placed code and data carefully on their drum memory computers to make the code run much faster. You can code with intent in any language on any platform, but because your intent is stronger than the asthetic perfection of the platform, things can look a little grungy to an outsider. Comment your code and document it well.
And ask yourself whether offloading the computation to a GPU might not be cheaper and even faster than SIMD.
Besides, I wasn't asking for "magic compiler optimizations". I would prefer to use intrinsics directly. Is there a way to do that in Java?
https://www.slideshare.net/RednaxelaFX/green-teajug-hotspoti...
Here is also a presentation about them
https://www.youtube.com/watch?v=7J0RELNadks
Here is a list with some of them.
https://gist.github.com/apangin/7a9b7062a4bd0cd41fcc
The Panama JVM has more related to SIMD.
Of course all of this is JVM specific and each one has its own set.
Another issue is how you code it up - both in terms of delivering multiple versions depending on CPU support and in terms of shielding the developer from low-level assembly. I'm all for high level APIs (think `sum(a vec, b vec)`) that get compiled down to whatever is supported, but I haven't seen many good examples of this.