Title: Optimization
Description: Some Things to think about
myork - March 4, 2004 05:27 PM (GMT)
Normally I am against early optimization, I think you should profile your code with the appropriate tools to find the real bottlenecks before hand (otherwise you waste time optimising code that is not important).
But these are some tricks to keep in mind when using C++.
The for loop:
A generic for loop:
| CODE |
for(;loop != end;loop++) { /* CODE */} |
Seems pretty imposable to optimise. But you look at the standard way of implementing the ++ operator on C++ classes.
| CODE |
MyClass MyClass:operator ++(int) // Postfix increment requires an int to distinguish it from prefix increment { MyClass copy(*this); this->increment();
return(copy); } |
Because the postfix increment should happen after the expression has been completed, you need to create a copy of the 'this' object in its current state and return that for use within the expression. You can then increment the 'this' value now so it is correctly defined for later use. I know this feature is not used in the above loop, but the post increment will normally be implemented to behave just like it does with builtin types. See example below.
What is also hidden is that this actually takes 2 extra calls to the copy constructor. The first call creates the copy. The second is a call to copy the value out of the operator into a temporary for use by the expression (this is because you can not return by reference).
| CODE |
MyClass y = x++; // Y is assigned the value of x and then x is incremented
|
So how do you get around this problem? Well the solution is as simple as the problem. You use a prefix increment operator.
| CODE |
for(;loop != end;++loop) { /* CODE */} |
| CODE |
MyClass& MyClass:operator ++() // Prefix increment { this->increment(); return(*this); } |
Here the implementation is very nice and clean. No calls to the copy constructor required.
KTC - March 4, 2004 07:11 PM (GMT)
A nice read with topics like this and others:
http://www.tantalon.com/pete/cppopt/main.htmp.s. : Is there any free profiler for C++ on windows that anyone know of ? (Without me needing to use mingw or cygwin coz I don't have enough space for it atm)
Sam Fisher vs Solid Snake - March 5, 2004 03:57 PM (GMT)
i think the using namespace cmd saves space because ur not writing all the std::cout<<std::endls
KTC - March 5, 2004 04:54 PM (GMT)
Is it really that difficult to type std:: ? Or at least use using declareation in local scope. Dumping everything to global is just BAD.....
Sam Fisher vs Solid Snake - March 5, 2004 10:16 PM (GMT)
ehh.. well everybody here awhile back when there were about 100-200 people told me to use namespace rather than typing std::, however i can go any way
KTC - March 5, 2004 11:59 PM (GMT)
| CODE |
| using namespace std; |
is just convenient to recommand to beginners so that they can learn C++ without having to know the exact details of namespace. However, when one start to progress on one's knowledge of C++ and write anything that's beyond a toy program, the using directive dumping everything into globals is just evil...
aftli - April 6, 2004 02:09 PM (GMT)
um, using namespace std; instead of std:: certainly does NOT reduce the size of a compiled program.
And using pre-increment instead of post-increment wherever possible is always a good idea.
brett
ih8censorship - April 6, 2004 03:03 PM (GMT)
another thing that can make stuff a little smaller in win32 when windows.h is included is typing #define WIN32_LEAN_AND_MEAN and that will strip down the header a bit but you may get undefined errors so you have to include the specific headers then. so i guess that means dont include every header file you have just the ones you need ^_^
inline_skater20032001 - April 7, 2004 01:46 AM (GMT)
Some compilers automatically optimize your code. Example: Borland Command-Line Compiler
ih8censorship - April 7, 2004 01:54 AM (GMT)
yes they do, however if its optimizing good code it will still be a lot better than it trying to optimize mediocre code.
FrozenKnight - April 7, 2004 08:50 AM (GMT)
Another thing that you can do is search for a better algrothim to use. EG: using quick sort rather than bubble sort. (Compilers can't optimize bad math choices)
dr voodoo - April 9, 2004 10:55 PM (GMT)
When using nested loops always ask yourself if the nested loop can't use information from the top loop so that it doesn't need so many loops. Example:
| CODE |
for(int a=0;a<size;++a) for(int b=0;b<size;++b) col(a,b);//a with b |
Can be optimized to:
| CODE |
for(int a=0;a<size;++a) for(int b=a;b<size;++b) { col(a,b);//a with b col(b,a);//b with a } |
The effect is exactly the same but the sencond needs only half as many loops as the first.
Consider inline ASM always as the last option. Once you use it your code is not as easy to read anymore and algrothim amelorations are much harder to implement.
myork - April 12, 2004 02:54 PM (GMT)
Hi Dr V.
You need to indent your second for statment to make it easier to read :P
Your first code has a complexity of O(N^2)
While your second has a complexity of O(N.log(N))
A definite improvement in complexity terms. But do you really gain anything.
You are makeing the algorithm more complicated to understand but doing exactly the same amount of work. (ie you are still calling the function 'col()' on every single element in both arrays.
FrozenKnight - April 12, 2004 09:53 PM (GMT)
I wouldnt consider inline asm as a last option it may break the standards but if youy get used to using it then at least you will know that you can do and how to do it alos you will have a much better understanding of how your computer works and will have an easier time optmizing (once you inderstand how C++ does what it does). and i usualy place (basic usualy not working or not working correctly or not fast enough) C++ code comments with my inineasm code in my C++. saves a lot of time when debugging :)
Incubator - April 12, 2004 10:23 PM (GMT)
huge tip for optimization:
compiler arguments:
-Os (for small binaries)
-O3 for largeer binaries with faster lstartup
-O2 all around balanced imo
-fomit-frame-pointer
-funroll-loops
-pipe
-march=athlon-xp
-mcpu=athlon-xp
the latter can be done manually in the code too, but will make it les readable and unrolling loops always increases file size (and speed too :) )
Prelink: prelink your binaries for increased speed
try to use more const references when passing objects instead of passing them each time by value
| CODE |
const QString& MyClass::getMember() const { return mString; } void MyClass::setString(const QString& s) { ... }
|
will require less copies in the stack (a lot less) thus reducing the amount of times a constructor/destructor is passed through.
can be usefull for large applications with many objects
oh, one very nice hint:
use linux. Linux binaries aere a lor smaller than windows binaries.
(KDevelop, a IDE like VC++6, its executale is only 256K on my build)
a small app, in Qt written, linux: 100K (pics in xpm included) windows: 1.05MB (also pics in xpm included)
dr voodoo - April 13, 2004 12:32 PM (GMT)
| QUOTE |
| You need to indent your second for statment to make it easier to read |
I only indent when I use {}s.
| QUOTE |
| But do you really gain anything. |
You only need to compare b half as often against size then without it. Also you safe lots of jumps.
Often when you come to such a situtation you often put a condition before col. And often if this condition is true for a with b then it's also true b with a. So you safe half of the comparisons. For example:
| CODE |
for(int a=0;a<size;++a) for(int b=a;b<size;++b) if(is_col(a,b)) { col(a,b);//a with b col(b,a);//b with a } |
In some situation the gain will be little but nearly always it is worth the little effort needed for the optimization.