问题
I would like to know how to avoid wasting my time and risking typos by re-hashing source code when I'm integrating legacy code, library code or sample code into my own codebase.
If I give a simple example, based on an image processing scenario, you might see what I mean.
It's actually not unusual to find I'm integrating a code snippet like this:
for (unsigned int y = 0; y < uHeight; y++)
{
for (unsigned int x = 0; x < uWidth; x++)
{
// do something with this pixel ....
uPixel = pPixels[y * uStride + x];
}
}
Over time, I've become accustomed to doing things like moving unnecessary calculations out of the inner loop and maybe changing the postfix increments to prefix ...
for (unsigned int y = 0; y < uHeight; ++y)
{
unsigned int uRowOffset = y * uStride;
for (unsigned int x = 0; x < uWidth; ++x)
{
// do something with this pixel ....
uPixel = pPixels[uRowOffset + x];
}
}
Or, I might use pointer arithmetic, either by row ...
for (unsigned int y = 0; y < uHeight; ++y)
{
unsigned char *pRow = pPixels + (y * uStride);
for (unsigned int x = 0; x < uWidth; ++x)
{
// do something with this pixel ....
uPixel = pRow[x];
}
}
... or by row and column ... so I end up with something like this
unsigned char *pRow = pPixels;
for (unsigned int y = 0; y < uHeight; ++y)
{
unsigned char *pPixel = pRow;
for (unsigned int x = 0; x < uWidth; ++x)
{
// do something with this pixel ....
uPixel = *pPixel++;
}
// next row
pRow += uStride;
}
Now, when I write from scratch, I'll habitually apply my own "optimisations" but I'm aware that the compiler will also be doing things like:
- Moving code from inside loops to outside loops
- Changing postfix increments to prefix
- Lots of other stuff that I have no idea about
Bearing in mind that every time I mess with a piece of working, tested code in this way, I not only cost myself some time but I also run the risk that I'll introduce bugs with finger trouble or whatever (the above examples are simplified). I'm aware of "premature optimisation" and also other ways of improving performance by designing better algorithms, etc. but for the situations above I'm creating building-blocks that will be used in larger pipelined type of apps, where I can't predict what the non-functional requirements might be so I just want the code as fast and tight as is reasonable within time limits (I mean the time I spend tweaking the code).
So, my question is: Where can I find out what compiler optimisations are commonly supported by "modern" compilers. I'm using a mixture of Visual Studio 2008 and 2012, but would be interested to know if there are differences with alternatives e.g. Intel's C/C++ Compiler. Can anyone shed some insight and/or point me at a useful web link, book or other reference?
EDIT
Just to clarify my question
- The optimisations I showed above were simple examples, not a complete list. I know that it's pointless (from a performance point of view) to make those specific changes because the compiler will do it anyway.
- I'm specifically looking for information about what optimisations are provided by the compilers I'm using.
回答1:
I would expect most of the optimizations that you include as examples to be a waste of time. A good optimizing compiler should be able to do all of this for you.
I can offer three suggestions by way of practical advice:
- Profile your code in the context of a real application processing real data. If you can't, come up with some synthetic tests that you think would closely mimic the final system.
- Only optimize code that you have demonstrated through profiling to be a bottleneck.
- If you are convinced that a piece of code needs optimization, don't just assume that factoring invariant expression out of a loop would improve performance. Always benchmark, optionally looking at the generated assembly to gain further insight.
The above advice applies to any optimizations. However, the last point is particularly relevant to low-level optimizations. They are a bit of a black art since there are a lot of relevant architectural details involved: memory hierarchy and bandwidth, instruction pipelining, branch prediction, the use of SIMD instructions etc.
I think it's better to rely on the compiler writer having a good knowledge of the target architecture than to try and outsmart them.
From time to time you will find through profiling that you need to optimize things by hand. However, these instances will be fairly rare, which will allow you to spend a good deal of energy on things that will actually make a difference.
In the meantime, focus on writing correct and maintainable code.
回答2:
I think it would probably be more useful for you to reconsider the premise of your question, rather than to get a direct answer.
Why do you want to perform these optimizations? Judging by your question, I assume it is to make a concrete program faster. If that is the case, you need to start with the question: How do I make this program faster?
That question has a very different answer. First, you need to consider Amdahl's law. That usually means that it only makes sense to optimize one or two important parts of the program. Everything else pretty much doesn't matter. You should use a profiler to locate these parts of the program. At this point you might argue that you already know that you should use a profiler. However, almost all the programmers I know don't profile their code, even if they know that they should. Knowing about vegetables isn't the same as eating them. ;-)
Once you have located the hot-spots, the solution will probably involve:
- Improving the algorithm, so the code does less work.
- Improving the memory access patterns, to improve cache performance.
Again, you should use the profiler to see if your changes have improved the run-time.
For more details, you can Google code optimization and similar terms.
If you want to get really serious, you should also take a look at Agner Fog's optimization manuals and Computer Architecture: A Quantitative Approach. Make sure to get the newest edition.
You might also might want to read The Sad Tragedy of Micro-Optimization Theater.
回答3:
What can I assume about C/C++ compiler optimisations?
As possible as you can imagine, except the cases that you get issues either functionality or performance with the optimized code, then turn off optimization and debug.
Mordern compilers have various strategies to optimize your code, especially when you are doing concurrent programming, and using libraries like OMP, Boost or TBB.
If you DO care about what your code exactly made into machine code, it would be no more better to decompile it and observe the assemblies.
The most thing for you to do the manual optimization, might be reduce the unpredictable branches, which is some harder be done by the compiler.
If you want to look for the informations about optimization, there's already a question on SO
- What are the c++ compiler optimization techniques in Visual studio
In the optimization options, there are explanations about what each optimize for:
- /O Options (Optimize Code)
And there's something about optimization strategies and techniques
- C++ Optimization Strategies and Techniques, by Pete Isensee
来源:https://stackoverflow.com/questions/15584814/what-can-i-assume-about-c-c-compiler-optimisations