Sign in to follow this  
Migi0027

C++ Optimization week!

Recommended Posts

Hi guys! smile.png

 

So after a while of programming, I realised that my code is becomming more messy and with slower compilation time.

 

So I ask you, what things do you commonly optimize, tricks n. stuff. (Speed Wise and Compilation Time Wise)

 

What I know so far:

  • You should love constants
  • Use class prototyping a lot

Please share!

 

Thank You

-MIGI0027

Share this post


Link to post
Share on other sites

A few things I keep in mind:

- use const where possible, both in member functions as parameters

- pass objects as const reference when their size is 'relatively' big

- don't let 'outsiders' get to crucial class members (make things private, make const 'Get...' functions public) 

- use VLD Always in debug mode, detect memory leaks a.s.a.p.

- use &auto when possible to make code more readable

- where possible always use std::vector instead of dynamic arrays (new/delete)

(helps in following 'the rule of 3')

Share this post


Link to post
Share on other sites

A few things I keep in mind:

- use const where possible, both in member functions as parameters

- pass objects as const reference when their size is 'relatively' big

- don't let 'outsiders' get to crucial class members (make things private, make const 'Get...' functions public) 

- use VLD Always in debug mode, detect memory leaks a.s.a.p.

- use &auto when possible to make code more readable

- where possible always use std::vector instead of dynamic arrays (new/delete)

(helps in following 'the rule of 3')

You should reserve the space of vectors as well this will at least in the avarage case help the vector not resize as much.

 

Check your template usage if you have loads of this it will upset compile times and may even make a compiler cry once in a while.

 

Batch compiling will also help, look for unity builds for that subject but keep in mind that you should always have a single file compile path in the solution as well.

Edited by NightCreature83

Share this post


Link to post
Share on other sites

So, while all the suggestions are fine, they don't usually solve the larger issues.  Don't get me wrong, I've seen trivial missing references cause massive performance degradation, in fact, for fun:

class ThingGrid
{
public:
  typedef uint32_t                     Thing;
  typedef std::vector< Thing >  ThingArray_t;
 
  const ThingArray_t    operator[]( size_t y ) const    {return mThings[ y ];}
  const Thing               GetThing( size_t x, size_t y ) const   {return mThings[ y ][ x ];}
 
private:
  std::vector< ThingArray_t >  mThings;
};

It is a silly piece of code and obviously just an example, but it works as intended and if we were not talking about optimizations (and this were in say a JavaDoc commented header) it would not jump out as to why the above is really bad.  If you didn't catch it immediately, yes returning the uint32_t "Thing" by value is intended but the return of the array is bad since it is also by value, so GetThing is massively slower than it should be thanks to a hidden temporary being made.  Of course, fix the reference and things are all better, or are they?  Take the following:

for( int x=0; x<things.Width(); ++x )
  for( int y=0; y<things.Height(); ++y )
    {ThingGrid::Thing thing = things.GetThing( x, y ); ... do something ...}

That piece of code is going to perform horribly on multiple levels even with the fix for the reference.  Why?  Think about it, there are 2 primary problems with that loop as applied to the given class.

 

[spoiler]

1.  First problem is the inner loop iterates on Y while the data is laid out in an sub arrays of x indexed data.  So, you are touching new chunks of memory each loop.  Fix:

for( int y=0; y<things.Height(); ++y )
  for( int x=0; x<things.Width(); ++x )
    {ThingGrid::Thing thing = things.GetThing( x, y ); ... do something ...}

2.  Even with that fix, you still get bit by the fact that as individual std::vectors each one points to different chunks of memory, so each time you complete an x loop you are likely blowing the cache and looking at a completely new chunk of memory.  Fixing this means removing the inner vectors and using a single vector with manual y offset to indexing.  Of course at that point, you could just use "for( const Thing& : mThings ) {}" and not have two indexes being maintained.

[/spoiler]

 

So, all said and done, while the simple rules of thumb items are important, I believe knowing your libraries and memory access patterns are much more important to prevent simple things like the above from being constantly adding up performance drains.

Edited by AllEightUp

Share this post


Link to post
Share on other sites
  1. Preprocessing macros will significantly slow your compilation.
  2. Do not include unnecessary header files.
  3. Create a build target for speed emphasized compiler settings and work with that as you develop instead of what you usually use (probably a debug build). You can always make use of a debug build when you need to debug.

Share this post


Link to post
Share on other sites

Compile time tip:

 

In a header file that doesn't use pointer as members, don't include the header file of the member object, instead do this:

B.h

#ifndef B_H
#define B_H

class A;

class B
{

public:

B();

private:

A* m_a;

}; 

#endif 
B.cpp

#include "A.h"

B::B
{
a = new A();
a->Initialize();
}
Edited by irlanrobson

Share this post


Link to post
Share on other sites

Make sure you're using all cores, ie. in VS check the project settings. C/C++ |General | Multi-processor compilation should be enabled. When using make, be sure to use -j <x> to run up to x jobs in parallel.

 

I noticed that Clang is a lot faster when using precompiled headers compared to GCC (almost as fast as VC++).

 

And as mentioned before, always be aware of your includes, avoid includes in header files as much as possible, consider using the forward declaration headers for some standard libraries, forward declare your own classes if possible, etc. etc. Once that doesn't help anymore, look into precompiled headers (especially if you use the standard library and/boost almost everywhere).

 

With a few tricks I could get a verification build from over 4min down to a little over 10s (with VC++). Disable compiler optimization, disable debug info, use precompiled headers and forward declarations, etc.  Interestingly the difference with GCC was about a zero and that already took twice as long before. Clang on the other hand would go down to around 20s.

Share this post


Link to post
Share on other sites

It was a 'why', not a 'how'.

Pass by const-reference has the same semantics as pass-by-const-value, but the object isn't actually copied/cloned. As a rule of thumb, large objects are likely expensive to copy, so if you don't need to make copies, you should avoid it.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this