views:

496

answers:

6
+3  Q: 

c++ optimization

I'm working on some existing c++ code that appears to be written poorly, and is very frequently called. I'm wondering if I should spend time changing it, or if the compiler is already optimizing the problem away.

I'm using Visual Studio 2008.

Here is an example:

void someDrawingFunction(....)
{
  GetContext().DrawSomething(...);
  GetContext().DrawSomething(...);
  GetContext().DrawSomething(...);
  .
  .
  .
}

Here is how I would do it:

void someDrawingFunction(....)
{
  MyContext &c = GetContext();
  c.DrawSomething(...);
  c.DrawSomething(...);
  c.DrawSomething(...);
  .
  .
  .
}
+11  A: 

If you're sure it's a performance problem, change it. If GetContext is a function call (as opposed to a macro or an inline function), then the compiler is going to HAVE to call it every time, because the compiler can't necessarily see what it's doing, and thus, the compiler probably won't know that it can eliminate the call.

Of course, you'll need to make sure that GetContext ALWAYS returns the same thing, and that this 'optimization' is safe.

Michael Kohne
Absolutely. Mind you, in a "DrawSomthing" context it is probably true that all the GetContext()s are the same.
dmckee
Inside the drawing function, the GetContext() will always return the same object reference (a member variable in the code I'm working with). As per Adam's suggestion, I'll try some profiling later and see if making some test changes affect performance.When drawing hundreds of thousands of objects to the screen, I'd be happy to make even the smallest of improvements.
Tim Rupe
Also, if GetContext() is something like a getter for a variable, it's probably as fast as a local variable. If it's fairly complicated, then you may be losing performance here. Testing and profiling is the only way to go.
David Thornley
David Thornley: Unless it's an inline function, then no, it's not going to be as fast as a local variable fetch because the compiler is going to have to push a return address, jump to another part of the code (with possible cache misses), etc, etc. GetContext can only be fast if it's an inline getter or if it's a macro that does something simple.
Michael Kohne
@Michael Kohne: Right, but it might be an inline getter. Many getters get defined in the class definition, which makes them inline by default, and the compiler is free to inline functions anyway if it likes.
David Thornley
+24  A: 

Don't guess at where your program is spending time. Profile first to find your bottlenecks, then optimize those.

As for GetContext(), that depends on how complex it is. If it's just returning a class member variable, then chances are that the compiler will inline it. If GetContext() has to perform a more complicated operation (such as looking up the context in a table), the compiler probably isn't inlining it, and you may wish to only call it once, as in your second snippet.

If you're using GCC, you can also tag the GetContext() function with the pure attribute. This will allow it to perform more optimizations, such as common subexpression elimination.

Adam Rosenfield
+1: Profile. And have a set of unittests before you make any changes. No unit tests means you could easily break something and never know.
S.Lott
+1. In particular, the compiler will need to see the source code for GetContext() in the same translation unit (e.g. via a header) in order to be able to either inline it or reason that it is pure and can be safely optimised out.
j_random_hacker
Even if GetContext() is not inlined, it seems unlikely that this "optimization" will make a measureable difference. You've gotta profile!
Mark Ransom
which version of GCC lets you use the pure attribute? Is this a C++0x feature or am I mistaken?
Carson Myers
@Carons Myers: It's a GCC extension; it's not a feature of C++98 or C++0x. It's available in GCC 2.96 and later, according to the documentation.
Adam Rosenfield
+2  A: 

Obviously, if GetContext() has side effects (I/O, updating globals, etc.) than the suggested optimization will produce different results.

So unless the compiler can somehow detect that GetContext() is pure, you should optimize it yourself.

nimrodm
+8  A: 

If it is logically correct to do it the second way, i.e. calling GetContext() once on multiple times does not affect your program logic, i'd do it the second way even if you profile it and prove that there are no performance difference either way, so the next developer looking at this code will not ask the same question again.

Shing Yip
I agree with this. Optimizations aside, the multiple calls to GetContext() force the programmer to ask what GetContext() is *doing*, such that it needs to be called multiple times.
Dan Breslau
+1  A: 

If you're wondering what the compiler does, look at the assembly code.

Paul Nathan
The problem is that this shows what this compiler is doing now, not what the next version will do. You can spot some slow spots this way (although assembly code is a lot more opaque in performance than it used to be), but you can't find if a construct is unsafe under other conditions (like the next service pack).
David Thornley
Well, yes. But if he was wondering what the compiler was doing, ASM is a good place to look at.
Paul Nathan
A: 

That is such a simple change, I would do it.
It is quicker to fix it than to debate it.

But do you actually have a problem?
Just because it's called often doesn't mean it's called TOO often.
If it seems qualitatively piggy, sample it to see what it's spending time at.
Chances are excellent that it is not what you would have guessed.

Mike Dunlavey