7 ms·
The statement that I found most powerful: > Compile time of this really simple example takes 2.85 seconds longer than the “simple C++” version. > Lest you thi
by tpush 8y ago
The statement that I found most powerful:
> Compile time of this really simple example takes 2.85 seconds longer than the “simple C++” version.
> Lest you think that “under 3 seconds” is a short time – it’s absolutely not. In 3 seconds, a modern CPU can do a gajillion operations. For example, the time it takes for clang to compile a full actual database engine (SQLite) in Debug build, with all 220 thousand lines of code, is 0.9 seconds on my machine. In which world is it okay to compile a trivial 5-line example three times slower than a full database engine?!
- jackewiehose 8y agoAnd that is a really old problem. I remember trying boost::phoenix about 10-15 years ago but it was completely unusable because even the hello-world-example took like 10 seconds. Thats incompatible to my C++-workflow. Today I'm trying to port some big old Embarcadero (Borland) C++ projects to their new clang-compiler but the compile times are so terrible that I'm not sure this will be usable at all (and these projects are mostly C++98).
- badsectoracula 8y agoWell, it doesn't help that Borland focused on compiler performance (i have Borland C++ 5.0 and i use it for a lot of my C coding since i write in C89+a few extensions that are supported anyway, because it takes around a second for a full rebuild for my code and is practically instant for a partial build - and that is for a singlethreaded compiler, for comparison the same code takes 4 seconds on a parallel build in gcc with make -j8). I don't know of any other (non-toy) compiler that focused on that. 15-16 years ago i used the free BC5.5 command line tools exclusively because on the crappy computer i had at the time (Pentium MMX at 200MHz with 32MB of RAM) it was the only that was fast enough to work with. I've also played a lot with Borland C++ Builder and the compile times for C++ (pre-C++98) are comparable (that is, practically instant).
- deleted 8y ago[deleted]
- leggomylibro 8y agoIn many ways the '++' in 'C++' comes from giving the compiler more information to work with. You can opt to trust the compiler much more than in C, and the idea is that you gain time at develop-time and hopefully run-time with the tradeoff of losing it at compile-time. At least, that's how I've usually understood it. And the example you mention seems like a complaint with C++20's Ranges in particular. I guess I'd fall into the, "but can't you just ignore the parts you don't like?" camp. This post is written in the context of game engines, but I see a lot of the same 'OG C' arguments made when people in embedded development resist giving C++ a try. We're all writing resource-constrained applications that work on tight time budgets, and none of us feel comfortable throwing up our hands and 'trusting the compiler' in that sort of atmosphere. But C isn't getting any younger, and it's hard to do polymorphism without getting hack-y. Now, who's turn is it to advocate Rust?
- swsieber 8y agoMe! Sort of. Rust is definitely further along the scale towards the end of "giving more to the compiler so it takes longer". I usually like the trade. Most of the time.
- adrianN 8y agoRust also has a saner module system that makes incremental builds much quicker. They're still pretty slow, but not as agonizingly slow as a clean build.
- nicoburns 8y agoRust is only fast compared to C++ (and then only sometimes). Literally every other language is significantly faster to compile. I'm hoping this can change though. Rust with fast compile times and a more complete library ecosystem (and ideally better IDE support) would be an incredibly productive language.
- dzdt 8y agoScala is slower to compile than C++ in large scale enterprise development. (The exception that proves the rule?)
- 21 8y ago> In which world is it okay to compile a trivial 5-line example three times slower than a full database engine Well, as explained in the article, those 5 lines generate hundred thousands of lines of code behind the scene. And you don't use C++ for fun, you use it because you have a serious performance problem. And in that case you'll wait the compile times, because there is no alternative. Let's not even go into link time code generation or profile guided optimizations, which increase compilation times by another order of magnitude.
- zozbot123 8y ago> those 5 lines generate hundred thousands of lines of code behind the scene. That's part of the problem; most of the time, the "thousands of lines of code" that are created from type-generic code have a lot of useless duplication, and the compiler has trouble coalescing the duplicated and redundant code (I don't even think a serious attempt is made, AIUI). There's a lot of scope for improvement.
- modeless 8y agoIf you really have a serious performance problem, the answer these days is more likely to be a GPU, DSP, FPGA, or even an ASIC. The era of C++ on CPUs being the right solution for most high performance computation problems is coming to a close now that Moore's Law is ending.
- aldanor 8y agoThis shouldn't have been downvoted.
- muro 8y agoIf you deploy the code on a large number of machines, especially out of your control, most of those don't apply. There is a large scale of problems that require/benefit from optimised non-GPU code: - OS and related tools - applications (e.g. image processing, spreadsheets, engineering applications) - browsers - games - compilers - low level libraries - databases Yyou are probably using many of those and would not enjoy them being slower.
- 8y ago
- userbinator 8y agoThe size comparisons are also very useful, if anything to show that even the simple "non-Modern" C++ program already has quite a bit of bloat. Compilation takes 0.064 seconds, produces 8480 byte executable I am experienced with Asm so I can come up with an instinctive order-of-magnitude estimate, but even those who aren't should try to roughly estimate how many machine instructions are required to implement that code, and come to the conclusion that over 8000 bytes for three nested loops with not much in them, a comparison, some arithmetic, and a handful of library function calls seems rather excessive. Even 800 would be on the high side --- somewhere around 100-200 bytes is my estimate. Also, watch this 4k demo (everything you see and hear is generated in realtime by a 4096-byte executable): https://www.youtube.com/watch?v=jB0vBmiTr6o https://www.youtube.com/watch?v=jB0vBmiTr6o
- jcelerier 8y agoI don't think that this is a very meaningful comparison at these sizes, because it entirely depends on your target. Just compiling a "foo.c" file with "int main() { }" for sole content through "gcc -Os" produces a 16kb executable on my linux machine, but I know very well that the exact same compiler will produce something much smaller if I compile for, say, a bare metal AVR target because the ELF file format has a lot of fluff.
- gumby 8y ago> because the ELF file format has a lot of fluff. I wouldn't call it fluff: even assuming no debugging info (which you won't have in your avr object file) it has info needed at runtime (program start time) such as where to load what into memory, how much initial uninitialised memory to allocate when starting up, etc. It all gets used.
- bnieuwen 8y agoI think the keyword might be an 8k executable, not 8k of code. If I compile the example with clang on my box (linux x86_64) I get a 17K executable, for which the .text section (containing pretty much the runnable code)is 0x291 (661) bytes with the debug build and 0x255 (597) bytes with -O3. If I dig into the .text segment of the optimized executable, only 235 bytes belong to the main function (others are stuff like __libc_csu_init and register_tm_clones). Looking at the assembly the loop would be about 123 bytes. So lots of overhead, but I wouldn't say it is in the nested loop.
- zozbot123 8y ago> Compile time of this really simple example takes 2.85 seconds longer than the “simple C++” version. Haskell, Rust, Scala etc. also have a lot of trouble with compile times. I wonder why, though - is it just a matter of priorities being placed on things other than optimizing the compiler, or is there some actual, inherent complexity in compiling these "modern" languages that doesn't apply to C or Go? (I suspect mostly the former, FWIW).
- kzrdude 8y agoIsn't it more about what the typical program looks like? The generic languages like Rust and C++ generate a ton of functions, wrapper types, and indirections that need to be seen through and mostly removed by the compiler. In C++, when compiling: for (; *it; ++it) { } it may look simple but deref is a function you insert (deref operator), `++it` is a function and so it continues on, with new function to generate each time it's a different iterator or even the same iterator with different template parameters.
- steveklabnik 8y agoWith Rust, a lot of the issue is monomorphization. Changing one line may make hundreds of lines be needed to recompile. Additionally, we produce more LLVM IR than we must, and rely on LLVM ago boil it away. It’s a complex set of issues that we’re constantly working on. (So yes, Go and C do not have generics, and so do not have this problem.)
- jules 8y agoDo you know what's causing that? 1. Maybe monomorphisation overduplicates code, so that different invocations produce the same machine code in the end? 2. If that's not happening, maybe idiomatic Rust code causes a lot of code to be generated where a C programmer would have written something differently, e.g. using a void* instead of passing by value? 3. If that's not happening either, maybe monomorphisation is more or less producing what a C programmer would have monomorphised manually, but it takes the compiler a long time to optimise away abstractions? It seems that in this C++ example the problem is #3: it takes a long time to optimise away the range & lambda abstraction.
- praptak 8y agoI remember Turbo Pascal 5.0 and its imperceptible delays between pressing F5 and seeing the program output. I hope some day we can have this in C++, even if it takes sorcery like speculative compilation as-you-type done on a gigawatt cluster of custom chips...
- Koshkin 8y agoI have seen a modern Oberon compiler building itself in 1/10-th of a second. (The Tiny C compiler does not take much longer, either.)
- int_19h 8y agoPascal (and the entire family - Modula etc) is a language designed by a guy with an academic background in PLs. This shows in the design: e.g. the syntax is verbose and has a very rigid structure, which can often be frustrating to the user (like the need to declare all variables in a separate declaration block at the beginning of each function), but which makes it extremely easy to parse with just a single token lookahead. Similarly, the semantics are such that they're easy for a compiler to implement. Borland still did a great job with their implementation performance-wise, and the legendary reputation of their Pascal compilers is well-deserved. But they had a solid foundation to build on in form of a tool-friendly language, which C++ just doesn't offer.
- pjmlp 8y agoThose rules are quite relaxed in Delphi, while still keeping the compilation speed. Same applies to C++ Builder, at least until they decided to move to clang.
- int_19h 8y agoBy now I think parsing is not exactly the bottleneck. But back in 90s, I'm sure that it has been a part of why TP and BP were as fast as they were, esp. compared to C++. Having precompiled units (and therefore no need to #include hundreds of kilobytes of headers for every translation unit) is probably a bigger deal today. Also, IIRC Delphi had only recently gotten generics, and they're still not heavily used? I suspect that code that's heavy on those will compile pretty slow.