4 ms·
> Subscript checking optimizations had been figured out by the 1980s, so the performance penalty was coming down. well, we're in 2019 and replacing a few criti
by jcelerier 8y ago
> Subscript checking optimizations had been figured out by the 1980s, so the performance penalty was coming down.
well, we're in 2019 and replacing a few critical .at() by [] regularly allows me to gain a few % when benchmarking.
- Animats 8y agoThat's because the C++ compiler has no idea what you're doing. It can't hoist subscript checks out of loops, because it doesn't know they're subscript checks. They're something some template generated, and at bottom, they expand to an IF statement. The Go compiler, which knows about subscript checks, does some of those optimizations. For this optimization to work, the compiler has to be allowed to report subscript errors early. Frequent subscript checks that cause noticeable overhead tend to be inside loops. Often, the compiler could hoist the implicit assert inside the loop up to one assert checked before the loop is entered. It has to be allowed to report failure as soon as it become inevitable. If you have a loop from 0 to 100 over an array that's 0 to 99, and there's no way to exit the loop early, then failure is inevitable. As soon as failure is inevitable, it has to be OK to detect it. That means if you're printing values 0 to 100, you'll never even get the first one printed. You'll abort before entering the loop. This is a bit strange to C/C++ programmers. Once the assert has been hoisted out of the loop, the compiler may be able to prove that it can't fail. For FOR statements, this is usually easy. So the subscript checking overhead can completely disappear for many inner loops.
- int_19h 8y agoThen again, who uses at() inside a loop in C++? That's what iterators are for.
- pjmlp 8y agoPlenty of enteprise developers that learned some kind of C++ long back when, and never bothered to improve themselves in this area. I have seen plenty of code like that, specially when written by the occasional C++ coder that usually works in other languages.
- jcelerier 8y agodoing math code which requires computations on indices with iterators is the best way to drive developers to suicide
- Dylan16807 8y ago> As soon as failure is inevitable, it has to be OK to detect it. That means if you're printing values 0 to 100, you'll never even get the first one printed. You'll abort before entering the loop. This is a bit strange to C/C++ programmers. It's strange but compilers are allowed to do it and anyone sufficiently familiar with undefined behavior will not be surprised.
- comex 8y agoCompilers are not currently allowed to do it if “failure” is in the form of an abort from an inlined function, as in the case of .at(),
- deleted 8y ago[deleted]
- Dylan16807 8y agoAh, so the compiler doesn't understand it's a failure, and just sees normal program flow that it can't alter. That's a tricky thing to solve, yeah. At best, under current semantics, the compiler could emit a fast loop and a slow loop, and pick which one using an initial bounds check. But that's extremely awkward at best... Automatically handling the bounds check upfront is a type of control flow that's halfway between normal exceptions and undefined behavior, that C++ doesn't really grok.
- celrod 8y agoWhen I dabbled in gfortran, a feature I liked was that while no bounds-checking is the default, run time bounds-checks can be enabled with "-fcheck=bounds" or "-fcheck=all", which can be handy while developing/testing code. Alternatively, Julia has a macro "@inbounds" which disables checks, but this involves going through and annotating code after testing. You can also start Julia with the options "--check-bounds={yes|no}" to override declarations. Running testsuites enables all checks. Seems like it would be handy if these checks could be elided by defining a macro. Any reason this isn't done? The performance cost is often much higher than the time spent repeatedly checking bounds. It tends to defeat the auto-vectorizer. Another workaround is to manually check bounds before the loop. This lets the compiler prove all bounds checks pass if it gets to the loop, and solves the problem. I do wish that sort of thing could be automatic.