3 ms·
I can't help but feel we're going to think of these as the bad old years, and that at some point we'll have migrated off of C to a language with much less UB. I
by kstrauser 2y ago
I can't help but feel we're going to think of these as the bad old years, and that at some point we'll have migrated off of C to a language with much less UB. It's so easy to express things in C that compile but that the compiler couldn't possibly guess the intent of because C doesn't have a way to express it.
For instance, in Python you can write something like:
result = [something(value) for value in set_object]
Because Python's set objects are unordered, it's clear that it doesn't matter in which order the items are processed, and that the order of the results doesn't matter. That opens a whole lot of optimizations at the language level that don't rely on brilliant compilers implying what the author meant. Similar code in another language with immutable data can go one step further: since something(value1) can't possibly affect something(value2), it can execute those in parallel with threads or processes or whatever else makes it go fast.
Much of the optimization of C compilers is looking at patterns in the code and trying to find faster ways to do what the author probably meant. Because C lacks the ability to express much intent compared to pretty much any newer language, they have the freedom to guess, but also have to make those kinds of inferences to get decent performance.
On the plus side, this might be a blessing in disguise like when the Hubble telescope needed glasses. We invented brilliant techniques to make it work despite its limitations. Once we fixed its problems, those same techniques made it perform way better than originally expected. All those C compiler optimizations, applied to a language that's not C, may give us superpowers.
- unclad5968 2y agoWhile all that makes sense in theory none of it has actually demonstrated to be faster than C. The compiler doesn't need to guess what the programmer is trying to do because C is close enough to the actual hardware that the programmer can just tell it what to do.
- pjmlp 2y agoNote that C code has hardly fast outside big iron UNIX, during the 1980's and up to the mid 1990's, any half clever developer could easily outperform the generated machine code, with manually written Assembly code. Hence why games for 8 and 16 bit home computers were mostly written in Assembly, and there were books like the Zen of Assembly Programming. It was the way that optimizating compilers started to exploit UB in C, that finally made it fast enough for modern times. Modern hardware has nothing to do with C abstract machine.
- remexre 2y agohttps://research.microsoft.com/en-us/um/people/simonpj/papers/ndp/haskell-beats-C.pdf https://research.microsoft.com/en-us/um/people/simonpj/paper...
- dathinab 2y agoFunnily part of why Python is well, one of the slowest widely used languages is that any AOT compiler has a really hard time guessing what it does ("slowest" for pure python only, it's still often more then fast enough). Through then the "cognitive"/"risk" overhead of large complicated C code bases in typical company use cases (*1) makes it so that you have to be very strict/careful about doing any optimizations in C at all. In which case ironically your perf. can easily be below that of e.g. go, Rust, C#, Java etc. (depending on use case). I.e. in the typical code base the additional optimizations the compiler can do due to better understanding as well as less risky but limited/simple ad-hoc human optimizations beat out C quite often. In a certain way it's the same story as back then with ASM, in theory in some use-cases it's faster but in practice for a lot of real world code with real world constraints of dev-hours and dev-expertise writing C was the better business choice. (1) I.e. hardly any resources for optimization for most code. Potentially in general a few to little devs for the tasks/deadlines. Definitely no time to chase UB bugs.
- o11c 2y agoIt's certainly true that there's room for semantic optimization, but my observation is that such optimization is largely around memory allocation. And AFAIK the only languages which tend to implement such memory optimizations are Java-like, and the only reason they bother is because of their up-front aggressive pessimization ... which the optimization can't make up for. Edit: my point is: yes C sucks, but everybody else is worse
- dzaima 2y agoOn the Python example, the downside is that, even though the order is unspecified, people may still rely on some properties, and have their code break when an optimizer changes the order. Basically the same as UB really, though potentially resulting in wrong results, not necessarily safety issues (at least not immediately; but wrong results can turn into safety issues later on). And, unlike with UB, having a "sanitizer" that verifies that your code works on all possible set orders is basically impossible. gcc/clang do have a variety of things for providing low-level hints to the compiler that are frequently absent in other languages - __builtin_expect/__builtin_unpredictable, __builtin_unreachable/__builtin_assume, "#pragma clang loop vectorize(assume_safety)"/"#pragma GCC ivdep", more pragmas for disabling loop unrolling/vectorizing or choosing specific values. Biggest thing imo missing being some "optimization fences" to explicitly disallow the compiler to reason about a value from its source (__asm__ can, to an extent, do this, but has undesired side-effects, and needs platform-specific register kind names). There's certainly potential in higher-level intent-based optimization though. Things coming to mind being reserving space in an arraylist before a loop with n pushes, merging hashmap lookups in code doing contains→get→put with the same key, simplifying away objects/allocations from ability to locally reason about global allocation behavior.