6 ms·
I'm completely ignorant of the subject, but most surprising to me in his example was that the compiler didn't optimize away the inefficiency. Is there something
by version_five 4y ago
I'm completely ignorant of the subject, but most surprising to me in his example was that the compiler didn't optimize away the inefficiency. Is there something about exception handling that makes it not get taken into account during optimization?
- cma 4y agoWithout profile guided optimization you normally assume it will want a slow path. For one, handling it far away rather than nearby inline, which would hurt cache efficiency (either wasted within a cache line or extra wasted prefetching) if there weren't exceptions being thrown.
- vgatherps 4y agoC++ exceptions have a lot of machinery behind the scenes, and I don’t think anybody has ever really put the effort in to optimize pathological edge cases like this.
- int_19h 4y agoA lot of time and effort went into optimizing the most common case (no exceptions - ideally this should be no-cost) at the expense of everything else. It's very much by design.
- vgatherps 4y agoYes, 100%! This is exactly the machinery the makes it hard for a compiler to elide the exception. I don’t think there’s anything in the standard that prevents the compiler from optimizing away said exception completely, but neither gcc or clang do so even in extremely trivial cases where the exception is identical to an if statement: https://godbolt.org/z/8Y81bzo5s https://godbolt.org/z/8Y81bzo5s
- jamesfinlayson 4y agoI'm no C++ expert but I think it must be hard for the compiler to figure out - the noexcept keyword exists in C++ to denote a method that doesn't throw exceptions (so the compiler knows it doesn't need to add default exception handling code). Given that this is a manual thing up to the programmer it mustn't be straight forward for the compiler to infer.
- beached_whale 4y agonoexcept actually forces it, if it doesn’t know it must essentially wrap the function body in a try { …body… } catch(…) { terminate( ); }. So the compiler is doing the same amount of work inside the function. Outside it can assume that no exception will escape that function, yes. If it knows, it doesn’t need to.
- pclmulqdq 4y agoExceptions in C++ have a ton of slow machinery, so available optimization is limited, and they are assumed to be... exceptional... so they are not generally speed-optimized. If you are expecting an occasional exception in a C++ program, std::optional with error checking will make you a lot happier.
- shadowgovt 4y agoOn top of everything else, the behavior of exceptions when mixed with setjmp and longjmp is undefined, which can be a real problem if you're using any libraries that you haven't exhaustively analyzed to confirm that they don't use that feature. If memory serves, this includes things like the Lua interpreter (ETA: this used to be true. ca 2008, the Lua interpreter was changed so that it can conditionally compile to implement its try/catch via setjmp / longjmp or via C++ exceptions). I generally consider exceptions in C++ harmful and avoid them if possible. It is not, unfortunately, always possible, as exceptions are the only way the language defines for constructors to fail.
- deleted 4y ago[deleted]
- neonsunset 4y agoC++ exceptions and by extension Rust panics and C# exceptions (with caveats) involve stack unwinding as well as gathering of corresponding details and producing an exception object (C#). It is very expensive and using it as a normal condition in general is not the best idea. It is by definition cannot be optimized in a way that gets both good performance and keeps all existing side effects. That's why Rust's Result<T, E> is vastly superior because it out of box pushes the users to very efficient and idiomatic error handling mechanism which is based on its enum types that enjoy a lot of compiler optimizations. You can also achieve fairly good results with struct-based custom Result<T, E> implementations in C# but until the language gets the support of proper discriminated unions, it will always be inferior. Thankfully, in C# and, I assume, in other exception-based languages the compiler is smart enough to recognize exceptions as cold paths and correctly reorder emitted code to minimize their impact when you do not throw them. But traversing try-catch blocks still tends to pessimize the codegen significantly hence heavy reliance of C# on various throw helpers to keep hot paths clean.
- User23 4y agoI don't know how it is now, but back in the day C++ exceptions were so messy and non-performant that Google forbid their use in company C++ code. And they employed at least one member of the standards committee!
- photochemsyn 4y agoLooks to still be the case: https://google.github.io/styleguide/cppguide.html#Exceptions https://google.github.io/styleguide/cppguide.html#Exceptions One could argue this is something of a technical debt issue, as the rationale notes: > "Given that Google's existing code is not exception-tolerant, the costs of using exceptions are somewhat greater than the costs in a new project. The conversion process would be slow and error-prone. We don't believe that the available alternatives to exceptions, such as error codes and assertions, introduce a significant burden." > "Our advice against using exceptions is not predicated on philosophical or moral grounds, but practical ones. Because we'd like to use our open-source projects at Google and it's difficult to do so if those projects use exceptions, we need to advise against exceptions in Google open-source projects as well. Things would probably be different if we had to do it all over again from scratch."
- tsimionescu 4y agoExceptions in all modern C++ compilers are implemented in a way that prioritizes the performance of cases where an exception is NOT thrown at the cost of performance when an exception is thrown. Note that this means C++ code should be slightly faster than equivalent C/Go/Rust-style code that has to do an if/else after every function call that can fail to check if it did. Once this decision was made, investing time in optimizing programs that use exceptions for regular control flow became very very low in the priority list of all C++ compilers. This would include recognizing cases where an exception could be replaced with a single if/else, and optimizations for the unhappy path in general.
- mcqueenjordan 4y agoBranch prediction.