4 ms·
If you work in real time embedded systems you become aware of code constructs that will deliver better performance. I always study the instruction set to see w
by robomartin 5y ago
If you work in real time embedded systems you become aware of code constructs that will deliver better performance. I always study the instruction set to see what tools it might reveal.
For example, most people might write something like this (pseudocode, "MAX" being a constant):
for i=0; i < MAX; i++
<some code>
On most processors this runs faster:
for i=MAX; i != 0; i--
<some code>
This is because most processors have the equivalent of a "CJNZ" or "CJZ" (Compare and Jump if Not Zero; Compare and Jump if Zero) instruction. It is much faster (generally one clock cycle) to determine if the value in a register or accumulator is zero than to load multiple registers and determine "less than" or "less than or equal to".
As far as I know, these are not optimizations a compiler is capable of.
- mhh__ 5y agoThat depends if the loop has side effects such that the optimization would be unsound. The actual transformation is dead simple albeit possibly not that profitable on a modern processor that will be macro and micro fusing to hell and back
- ladberg 5y agoThat's absolutely something a compiler can do, and it's easily verifiable: https://godbolt.org/z/3Tze5q594 https://godbolt.org/z/3Tze5q594
- gumby 5y ago> As far as I know, these are not optimizations a compiler is capable of. If <some code> has side effects I don’t want the compiler to make that optimization as the order might be important and there is no way to tell. (If there are no side effects the compiler can optimize — by removing the loop!). You can tell the compiler you don’t care about order by replacing the for loop with an algorithm like for_each which is allowed to do this kind of thing, and can take a parallel policy too. (Though is there an implementation that uses execution policies?)
- saagarjha 5y agoCompilers can and do perform these optimizations; they maintain internal tables of instruction costs that guide what code is emitted. It’s just that modern processors don’t really have these kinds of differences, and the ones that do are generally not amenable to high-level compilers for other reasons (extreme register pressure, etc.)
- DoingIsLearning 5y agoI work in embedded systems and generally I think the priorities still are: 1. Correctness 2. Readability 3. Performance A lot of people worry too much about time constraints and performance, at the end of the day, correctness is the most important, readability second _specially_ if you are consulting and leaving that codebase behind for someone else to maintain. Performance is important but only to the extent that it is specified. So many times people write performance enhacements for functionality that has no hard real-time deadlines. If the performance objective is not in a specification then the optimization is not adding value (other than personal satisfaction).
- robomartin 5y ago> If the performance objective is not in a specification then the optimization is not adding value Very true. I agree 100%. I only resort to "sculpting" the code for performance when standard code will not meet timing requirements. Sometimes you just don't have the option to increase clock rates or change processors and have to make things work if at all possible. In general terms, if things are too tight it, it means you are using the wrong processor or should consider going up to a higher speed grade. That said, I can't tell you how many times I have faced apparent limits that absolutely evaporated by taking detailed control of the low level implementation. The easiest example I can provide was a custom dynamic RAM controller I designed for a Xilinx FPGA. It had a microcoded control architecture necessary for the specific application it targeted. This particular device (I think it was an XC2-V1000) could not get much past 160 MHz no matter what we did. Compiler optimizations didn't help much past this point. I decided to hand-wire and hand-place the design. This means locating each logic element by hand and wiring them by hand within the FPGA fabric. If I remember correctly, the hand-placed design could reliably reach 250 MHz. We didn't need to go that fast, I think we backed it down to 200 MHz with the comfort of knowing that we had good margin. It was tested for reliability in a thermal chamber, where it easily exceeded design requirements. Not doing this would have meant moving up to a more expensive speed grade or an even more expensive member of the Xilinx family. Taking intimate control of the implementation likely saved well over a million dollars over the life of the product. I have also been at the opposite end of the scale, where you are trying to squeeze the last bit of performance out of a $0.57 microcontroller because the design can't support a $0.75 chip. Sometimes life forces your hand that way.