4 ms·
Got me thinking. How easy is it to write Assembly that looks good but is slower than C? Like can you be really good with Assembly and still not be certain your
by Waterluvian 3y ago
Got me thinking. How easy is it to write Assembly that looks good but is slower than C?
Like can you be really good with Assembly and still not be certain your effort is actually worth not doing it in a higher language?
- hoten 3y agoTrivially easy. Just try to beat a C compilers optimization for constant integer division. https://clang.godbolt.org/z/MrMxo678x https://clang.godbolt.org/z/MrMxo678x
- tekknolagi 3y agoAdd -O2 for even fewer instructions :)
- hoten 3y agoThanks, that was a silly oversight. Your comment is appreciated, as it saved an instruction in my game engine's JIT compilation :) https://github.com/ArmageddonGames/ZQuestClassic/commit/0a780d638671e91372675c2161cc0fa0131545b8 https://github.com/ArmageddonGames/ZQuestClassic/commit/0a78...
- tekknolagi 3y agoCool!!
- okaleniuk 3y agoHave you tried measuring the actual impact of this? This optimization is so old, I'm not even sure if it's still worth the effort. It definitely worked in the 90s. What you do here is you save on division, and lose on instruction cache. This might look good on a benchmark when all your code fits the cache nicely, but bite back in-vivo. You should try it out in an actual problem and see how it goes.
- hoten 3y agoI know it's an appeal to authority, but if clang does it at high optimization levels then that's good enough for me to know it's faster. Division is really really slow in CPUs, as I understand it. Like, CPUs are just awful at it. It being an old opt doesn't mean it is invalid. I'm not aware of CPUs getting meaningfully better at division.
- okaleniuk 3y agoYou have to measure. It's a contextual optimization, no compiler in existence measures contextual optimization for you. Even the profile-based optimization is a spray and pray thing. CPUs are not getting better at division per se, but they are getting better at all the ALU operations compared to the memory latency. You can add more transistors on a chip, but you can't cheat the light speed and make signal travel 30 cm in less than a nanosecond. So you need to bring your data closer, you need caches. Code, unsurprisingly, is also data, and it also goes through the instruction cache. This optimization is instruction latency vs. cache intake. It may or may not be beneficial depending on the rest of the program. I've already seen both Clang and GCC produce faster code with -Os rather than with -O3.
- stephencanon 3y agoPeople do this all the time. The world is littered with assembly code written by people who believe that modern x86 uarches are just like the Pentium IV they cut their teeth on, or that an M2 is just a fancy Cortex-A53, meticulously hand ordering instructions while entirely missing the big picture. If you’re going to take the trouble of writing assembly, you should do it right; figure out the fastest you can theoretically go, and see if you can get within a few percent of that without using assembly. If you can, stop. If not, figure out why you can’t, file compiler bugs as applicable, and then write assembly where it’s necessary. Re-measure, and if you aren’t within a few percent, figure out why not, then go back to step 1.
- okaleniuk 3y agoIf you're inclined to write fast code in assembly, you will. If not - not. The thing is, optimizing compilers don't actually do any optimization in the classical sense. They don't do run-measure-modify loop as programmers do so all they can apply to the code is the heuristics some other programmers taught them. Some things are trivial like loop unrolling or function inlining. Some are not, like trigonometric approximations. In the long run, when a compiler stops, a person goes further. That's why empirically, hand-made code is still faster than the compiled one. Of course you can write slow code in Assembly, but if you already decided to go low, you'll optimize your thing until satisfied with the result. One particular thing comes to mind, C is ridiculously bad with automatic superscalarization (try VTune's HPC characterization on any code you like and see). Sure, you can use intrinsics and implement things manually, but that would be essentially the same as writing in assembly. There is another contender though. Spiral (https://spiral.net/ https://spiral.net/) that actually do solve the optimization problem can in fact be as effective as a human programmer and at a fraction of the cost. Spiral is overly specialized, so it's not a threat to all the HPC, but a more generic thing may indeed become a gamechanger.