News for hackers. Stuff that matters.
Re:C and C++ Prioritize Performance over Correctness by titzer on Friday August 18, 2023 @02:34PM (#37180101)
The solution is to have the compiler automatically split iteration into a known in-bounds part and a possibly-out-of-bounds part. In this case, generating an additional check that {ARRAY_WIDTH < (INT_MAX - offset)} would be sufficient to guarantee that {i + offset} doesn't wrap around, enabling further reasoning in a specialized copy of the loop. (In this example, it's unclear what the relation to ARRAY_WIDTH is to in and out).

The HotSpot C2 compiler (and AFAIK, Graal) do partitition iteration spaces in this way.

This does have some complexity cost in the compiler, of course, and it produces more code, especially if the compiler generates multiple copies of the loop. But given that relatively few super-hot loops of this kind are in typical programs, it is worth it.

Re:C and C++ Prioritize Performance over Correctness by logicchains on Friday August 18, 2023 @02:39PM (#37180163)
>But given that relatively few super-hot loops of this kind are in typical programs, it is worth it.

In C programs these kind of super-hot loops are quite common, because if someone didn't have many such loops they probably wouldn't need to write in C/C++. And if C had the same overhead as Java in these cases, then people who needed to squeeze out every drop of performance would use a different language.

Re:C and C++ Prioritize Performance over Correctness by titzer on Friday August 18, 2023 @02:44PM (#37180254)
> these kind of super-hot loops are quite common

People say this, then they write microbenchmarks. Then compilers optimize the heck out of these microbenchmarks (and numerical kernels). Rinse and repeat for several decades, and every dirty trick that you can think of gets blessed under the guise of UB.

When in reality, real programs do not spend all their time in one (or even a handful) of super-hot loops. C was designed to let compilers have a field day so that 1980s supercomputers could get 5% more FP performance, by hook or by crook. This kind of dangerous optimizations do not make much different for the vast majority of application code, the majority of which spends its time chasing pointers and chugging through lots of abstraction layers.

Re:C and C++ Prioritize Performance over Correctness by haberman on Friday August 18, 2023 @03:31PM (#37180898)
> When in reality, real programs do not spend all their time in one (or even a handful) of super-hot loops.

This paper from 2015 finds that a large amount of CPU in Google data centers is spent in a relatively small number of core components, known as the "datacenter tax": https://static.googleusercontent.com/media/research.google.c...

    > [We] identify common building blocks in the lower levels of the software stack.
    > This “datacenter tax” can comprise nearly 30% of cycles
    > across jobs running in the fleet, which makes its constituents
    > prime candidates for hardware specialization in future server
    > systems-on-chips.
Some of the components they identify are memmove() (definitely a loop), protocol buffers (proto parsing is a loop), and compression/decompression (a loop).
Re:C and C++ Prioritize Performance over Correctness by TapamN on Friday August 18, 2023 @03:49PM (#37181146)
>C was designed to let compilers have a field day so that 1980s supercomputers could get 5% more FP performance, by hook or by crook.

C was designed to help create Unix. It just happened to turn out to be something that could be compiled into more efficient code than most other languages at the time, without being overly difficult to work with.

From what I understand, 80s supercomputers were more likely to run Fortran. Fortran has fewer problems with pointer aliasing than C, so a Fortran compiler could generate better code than a C compiler for the type of code they would be running.

Re:C and C++ Prioritize Performance over Correctness by kllrnohj on Friday August 18, 2023 @04:41PM (#37181817)
The idea that only a tiny portion of code is "hot" is just not true.

But you're also missing the entire idea anyway. It's not about bounds checking, it's about at what point overflow occurs. `int` is a sized type, so if overflow is defined for it then it has to also overflow at that size. This prevents using native size of the machine if it's larger than that of `int`. Which these days it very often is since int is 32bit. So you couldn't promote it to a 64bit relative address as then it'll overflow at 64bits instead of 32bits.

Re:C and C++ Prioritize Performance over Correctness by titzer on Friday August 18, 2023 @08:16PM (#37183984)
> This prevents using native size of the machine if it's larger than that of `int`.

Having implemented multiple compiler backends for 64-bit machines, this is not true. All 64-bit machines I am aware of, and certainly all modern ones, do 32-bit arithmetic just fine.

Re:C and C++ Prioritize Performance over Correctness by kllrnohj on Saturday August 19, 2023 @11:48AM (#37189945)
Yes it is, see x86 example in https://youtu.be/yG1OZ69H_-o at about the 40 minute mark for a real world example
Re:C and C++ Prioritize Performance over Correctness by titzer on Saturday August 19, 2023 @03:45PM (#37192377)
It's actually really annoying to get an example from a video, but nevertheless...

The example shows you still didn't really seem to grok my point, which I will state again. A compiler can introduce additional checks for overflow that guard a large region (e.g. the repeated code in that example plus the loop after--maybe even the whole function!) and then make exactly the same transformations in the guarded region. The result is exactly the same machine code. It will go fast and not go out-of-bounds or wrap around. If the program would go out-of-bounds or wrap around, the guard will dynamically catch than and branch to a slower copy of the code that does exactly the right behavior at the right place. This is exactly how Java JITs approach C code quality. They use all the same tricks, they just have to try harder to handle the edge cases.

And besides, there are several other ways to get that code--instead of using int32_t, it could have been uintptr_t, which replaces UB with platform-specific behavior but nevertheless lets the compiler do the LEA and other addressing mode tricks. No need to resort to UB.

The entire mindset of opening holes in the language specification to allow compilers to optimize without thinking hard is just wrong. Programs have bugs. They go out of bounds. Preserving the exact out-of-bounds behavior is what allows programmers to debug their code. Checking bounds is what keeps programs from getting pwned all the time. It's not an opportunity for magic go-fast at the expense of security and debuggability.

We're here in this muck today because of a persistent and deliberate choice to be hostile to programmers, programs, and people running those programs because compiler designers didn't want to work hard. That doesn't fly in literally any other programming language domain; C is the odd duck and it's frankly ruined people's reasoning centers.

Re:C and C++ Prioritize Performance over Correctness by kllrnohj on Saturday August 19, 2023 @06:51PM (#37194145)
> The entire mindset of opening holes in the language specification to allow compilers to optimize without thinking hard is just wrong.

I would counter that 2's compliment overflow is a worse design in practice as easily 99% of the time overflow happening at all is a bug. Rust almost got this right by making overflow be a panic in debug builds, but then they took the worst option in making it defined 2's compliment in release builds

But also the mindset that everything must be extensively defined is just wrong. Nobody's standard library does this anyway, but also it's not feasible to do. You cannot define the exact outcome of data races, for example. UB is inevitable, it'll always exist in all languages. The debate is as such over where you put that line, not whether or not it exists at all

Re:C and C++ Prioritize Performance over Correctness by titzer on Saturday August 19, 2023 @08:31PM (#37194785)
> UB is inevitable

There's a huge difference between UB (as in C/C++) and nondeterminism, so I don't accept this assertion. UB in C gives no semantics to executions containing it; it is neither spatially nor temporally contained. No other programming language has such a ridiculous and program- and programmer-hostile concept. And for good reason. It makes reasoning about buggy programs a non-starter. And all programs have bugs. We debug them by analyzing their runtime behavior! Crashing immediately upon a bug, exactly the same way on every machine, is the absolute best way to find and fix bugs that cannot be caught statically.

Re:C and C++ Prioritize Performance over Correctness by memefrog on Friday August 18, 2023 @08:28PM (#37184059)
It is more true in good code than it is in bad code. If you use atomic reference counting everywhere or you're constantly allocating memory and freeing it all over the place, like a lot of "modern" code, you do tend to get quite flat profiles. But in good code, which allocates very infrequently, and is designed around flat arrays of data being processed in loops, you naturally do sit in tight loops a lot.
Re:C and C++ Prioritize Performance over Correctness by kllrnohj on Saturday August 19, 2023 @11:55AM (#37190020)
No, it still isn't true. Consider things like a web browser. Huge codebases where damn near the entire thing is "hot." Or OS's like iOS and Android - again, huge codebases where everything is "hot" (everything is either impacting responsiveness or battery life, after all), and vanishingly few if any "super hot tight loops." Same again with game engines like Unreal. It does have data processing hot loops like physics simulations, but it also has audio paths, rendering, AI, etc... that are also all still very much hot. Even the code that does loading, a "rare" event, is still hot because the user is blocked on it.

The "hot data processing loop" definitely exists in some systems, notably those that really just do one single thing, but those are also far from even the majority case. At least not on anything where the end user is directly paying the computational bill (aka, very few client apps fit the "single hot loop" profile)

But if you go pitch Apple with a "hey, we want iOS to be 20-30% slower because some people are uncomfortable with narrow contracts" they would rightly laugh you right out of the room.

Re:C and C++ Prioritize Performance over Correctness by memefrog on Saturday August 19, 2023 @08:07PM (#37194666)
Web browsers are the worst offenders for what I described: highly dynamic retained-mode GUIs with huge amounts of memory allocation all over the place. They are bloated and very much badly designed, so even simple websites slow any 5+-year-old computer to a crawl.

If people cared about performance (including latency and power usage) on mobile they wouldnt write such heavy apps. Reality is, people plug their phones in every day and so power usage isnt actually that important. Kept in mind, but clearly not optimised for.