Live data from Hacker News

The Performance Impact of C++'s `final` Keyword

16bpp.net

41–50 of 385 posts

Re: The Performance Impact of C++'s `final` Keyword

#41
post #26

I don't do much C++, but I have definitely found that engineers will just assert that something is "faster" without any evidence to back that up. Quick example, I got in an argument with someone a few years ago that claimed in C# that a `switch` was better than an `if(x==1) elseif(x==2)...` because switch was "faster" and rejected my PR. I mentioned that that doesn't appear to be true, we went back and forth until I…

In my opinion, the only things that really matter are algorithmic complexity and readability. And even algorithmic complexity is usually only an issue a certain scales. Whether or not an 'if' is faster than a 'switch' is the micro of micro optimizations -- you better have a good reason to care. The question I would have for you is was your bunch of ifs more readable than a switch would be.

Re: The Performance Impact of C++'s `final` Keyword

#42
post #20
post #3

I'm surprised that it has any impact on performance at all, and I'd love to see the codegen differences between the applications. Mostly the `final` keyword serves as a compile-time assertion. The compiler (sometimes linker) is perfectly capable of seeing that a class has no derived classes, but what `final` assures is that if you attempt to derive from such a class, you will raise a compile-time error. This is simil…

"inline" is confusing in C++, as it is not really about inlining. Its purpose is to allow multiple definitions of the same function. It is useful when you have a function defined in a header file, because if included in several source files, it will be present in multiple object files, and without "inline" the linker will complain of multiple definitions. It is also an optimization hint, but AFAIK, modern compiler ig…

GCC does not ignore inline for inlining purposes:

Need a way to make inlining heuristics ignore whether a function is inline https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93008

(Bug saw a few updates recently, that's how I remembered.)

As a workaround, if you need the linkage aspect of the inline keyword, you currently have to write fake templates instead. Not great.

Re: The Performance Impact of C++'s `final` Keyword

#43
post #26

I don't do much C++, but I have definitely found that engineers will just assert that something is "faster" without any evidence to back that up. Quick example, I got in an argument with someone a few years ago that claimed in C# that a `switch` was better than an `if(x==1) elseif(x==2)...` because switch was "faster" and rejected my PR. I mentioned that that doesn't appear to be true, we went back and forth until I…

> But there's tons of this stuff like this in CS

Reminds me of the classic https://stackoverflow.com/questions/24848359/which-is-faster...

Re: The Performance Impact of C++'s `final` Keyword

#44
post #26

I don't do much C++, but I have definitely found that engineers will just assert that something is "faster" without any evidence to back that up. Quick example, I got in an argument with someone a few years ago that claimed in C# that a `switch` was better than an `if(x==1) elseif(x==2)...` because switch was "faster" and rejected my PR. I mentioned that that doesn't appear to be true, we went back and forth until I…

In my opinion, the only things that really matter are algorithmic complexity and readability. And even algorithmic complexity is usually only an issue a certain scales. Whether or not an 'if' is faster than a 'switch' is the micro of micro optimizations -- you better have a good reason to care. The question I would have for you is was your bunch of ifs more readable than a switch would be.

But a switch and an if-else *is* a matter of algorithmic complexity. (Well, at least could be for a naive compiler). A switch could be converted to a constant time jump, but the if-else would be trying each case linearly.

Re: The Performance Impact of C++'s `final` Keyword

#45
The main case where I use final and where I would expect benefits (not covered well by the article) is when you are using an external library with pure virtual interfaces that you implement.

For example, the AWS C++ SDK uses virtual functions for everything. When you subclass their classes, marking your classes as final allows the compiler to devirtualize your own calls to your own functions (GCC does this reliably).

I'm curious to understand better how clang is producing worse code in these cases. The code used for the blog post is a bit too complicated for me to look at, but I would love to see some microbenchmarks. My guess is that there is some kind of icache or code side problem. where inlining more produces worse code.

Re: The Performance Impact of C++'s `final` Keyword

#46
I profiled this project and there are abundant opportunities for devirtualization. The virtual interface `IHittable` is the hot one. However, the WITH_FINAL define is not sufficient, because the hot call is still virtual. At `hit_object |= _objects[node->object_index()]->hit` I am still seeing ` mov (%rdi),%rax; call *0x18(%rax)` so the application of final here was not sufficient to do the job. Whatever differences are being measures are caused by bogons.

Re: The Performance Impact of C++'s `final` Keyword

#47
post #26

I don't do much C++, but I have definitely found that engineers will just assert that something is "faster" without any evidence to back that up. Quick example, I got in an argument with someone a few years ago that claimed in C# that a `switch` was better than an `if(x==1) elseif(x==2)...` because switch was "faster" and rejected my PR. I mentioned that that doesn't appear to be true, we went back and forth until I…

I've encountered similar situations before. It's insane to me when people hold up PRs over that kind of thing.

Re: The Performance Impact of C++'s `final` Keyword

#48
post #26

I don't do much C++, but I have definitely found that engineers will just assert that something is "faster" without any evidence to back that up. Quick example, I got in an argument with someone a few years ago that claimed in C# that a `switch` was better than an `if(x==1) elseif(x==2)...` because switch was "faster" and rejected my PR. I mentioned that that doesn't appear to be true, we went back and forth until I…

Even if one of these constructs is faster it doesn't matter 99% of the time. Writing well structured readable code is typically far more important than making it twice as fast. And those times can rarely be predicted beforehand, so you should mostly not worry about it until you see real performance problems.

I mostly focus on "using stuff that won't break", and yeah "if it actually matters".

For example, much to the annoyance of a lot of people, I don't typically use floating point numbers when I start out. I will use the "decimal" or "money" types of the language, or GMP if I'm using C. When I do that, I can be sure that I won't have to worry about any kind of funky overflow issues or bizarre rounding problems. There might be a performance overhead associated with it, but then I have to ask myself "how often is this actually called?"

If the answer is "a billion times" or "once in every iteration of the event loop" or something, then I will probably eventually go back and figure out if I can use a float or convert it to an integer-based thing, but in a lot of cases the answer is "like ten or twenty times", and at that point I'm not even 100% sure it would be even measurable to change to the "faster" implementations.

What annoys me is that people will act like they really care about speed, do all these annoying micro-optimizations, and then forget that pretty much all of them get wiped out immediately upon hitting the network, since the latency associated with that is obscene.

Re: The Performance Impact of C++'s `final` Keyword

#49
post #2

What final enables is devirtualization in certain cases. The main advantage of devirtualization is that it is necessary for inlining. Inlining has other requirements as well -- LTO pretty much covers it. The article doesn't have sufficient data to tell whether the testcase is built in such a way that any of these optimizations can happen or is beneficial.

See this is why I find this odd. Is there a theory as to how devirtualisation could hurt performance?

Devirtualization maybe not necessarily, but inlining might make code fail to fit into instruction caches.

Re: The Performance Impact of C++'s `final` Keyword

#50

The main case where I use final and where I would expect benefits (not covered well by the article) is when you are using an external library with pure virtual interfaces that you implement. For example, the AWS C++ SDK uses virtual functions for everything. When you subclass their classes, marking your classes as final allows the compiler to devirtualize your own calls to your own functions (GCC does this reliably).…

Could easily just be a bad optimization pathway.

`final` tells the compiler that nothing extends this class. That means the compiler can theoretically do things like inlining class methods and eliminate virtual method calls (perhaps duplicating the method)?

However, it's quite possible that one of those optimizations makes the code bigger or misaligns things with the cache in unexpected ways. Sometimes, a method call can bet faster than inlining. Especially with hot loops.

All this being said, I'd expect final to offer very little benefit over PGO. Its main value is the constraint it imposes and not the optimization it might enable.

Post reply on HN