tags:

views:

261

answers:

6

I have the following method to swap two double arrays (double**) in c++. Profiling the code, the method is accounting for 7% of the runtime... I was thinking that this should be a low cost operation, any suggestions? I am new with c++, but i was hoping to just swap the references to the arrays.

 62 void Solver::Swap(double** &v1, double** &v2)
 63 {
 64         double** vswap = NULL;
 65         vswap = v2;
 66         v2 = v1;
 67         v1 = vswap;
 68 }
+3  A: 

The code looks fine. Its is just a pointer assignment. It depends on how many times the method was got called.

aJ
It's being called once every iteration to swap the new and old arrays. The array itself is 2x20000. Could the size of the array be an issue?
ccook
Array size shouldn't matter. Its pointer assignment.
aJ
Could it matter when a profiler is used??
ccook
+1  A: 

I guess your profiler is getting confused here a bit, as this method really only swaps two pointers, which is very cheap. Unless this method is called a lot, it shouldn't show up in a profile. Does your profiler tell you how often this method gets called?

One issue you have to be aware of with swapping is that one array might be in the cache and the other not (especially if they are large), so constantly swapping pointers might trash the cache, but this would show up as a general slow-down.

Anteru
The arrays are both large and swapped a lot. It's being used in an RK4 method I am working on. What is bugging me is that the Swap is costing more than the derivative evaluation. The derivative is being calculated some 24M times, while the swap just 502, however Swap is accounting for 21% and the derivative just 13%. Note the derivative is rather simple atm... (t^3) but all the same.
ccook
It could be also due to your swap getting inlined (your running with optimisation on, aren't you) and this could skew the numbers.
Anteru
A: 

Ok,

Yea, ran into the solution too quickly without thinking about it

Itsik
-1 This function won't actually do anything since the changes to `v1` and `v2` aren't passed on to the caller. (The pointers are being passed by value.)
Martin B
I've only been working in c++ for a few days :) Legacy of my c# work I guess.. Let me try it out, ty
ccook
I'm afraid Martin is correct
ccook
I get the following: Solver.cpp: In member function ‘void Solver::Swap(double***, double***)’:Solver.cpp:64: error: cannot convert ‘double***’ to ‘double**’ in initializationSolver.cpp:66: error: cannot convert ‘double**’ to ‘double***’ in assignment
ccook
No problem :) ty
ccook
+4  A: 

1) Make sure your function is inlined.

2) You can inplace swap, using a XOR for instance

3) Try to force the compiler to pass arguments using register instead of the stack (even though there's lot of register stress on x86, it's worth trying) - you can use the standard register keyword or play with fastcall on MS' compiler.

typedef double** TwoDimArray;

class Solver
{
  inline void Swap( register TwoDimArray& a, register TwoDimArray& b )
  {
    a ^= b ^= a ^= b;
  }
};

4) Don't bother giving default values for temporaries like vswap.

Aurélien Vallée
A member function defined inside its class' definition is implicitly inlined.
sbi
Nice solution, but identifiers in C++ don't start with a number "2DArray".
AraK
My mistake, i wrote it too fast :) it's corrected.Concerning the implicit inlining of inside-class methods, that's a matter of style, i like to emphasis inline and virtual keywords.
Aurélien Vallée
Not sure I follow, where are a and b coming from?
ccook
They are just the identifiers passed as arguments
Matthieu M.
Thank you, using 'register' and 'inline' swap no longer shows up in the profile. Before I call it a done deal, is it possible that inline is preventing the profiler from seeing the method calls all together? Note I have some errors trying the binary operators "invalid operands of types ‘double**’ and ‘double**’ to binary ‘operator^’"
ccook
Something is fishy with your compile settings if this changes make it faster; are you sure you are using a high optimisation level? Typically, inline and register is simply ignored by the compiler, and the XOR swap _shouldn't_ be significantly faster than a register-register copy ;)
Anteru
I suppose the improvement you see comes from `inline`. (I'd be surprised if a modern compiler would actually pay much attention to `register` and on that XORing swap trick I'm with Anteru.)
sbi
I think I've read analysis that the xor-swap should be *slower* than normal swap, in addition to just breaking under certain conditions (swap something with itself), and I don't think it should even work for pointers. May-be just inlining did it?
UncleBens
IMHO it's a common myth nowadays that compilers are sooo smart compared to programmer. And all these specifiers are just ignored. Truly, i don't think so. Optimization is just a matter of finding tricky specifiers, build, and retry until the assembly looks like what you want.There is no way to know if you a XOR will be fast than a copy on specific platform. Even on very close CPUs this may change. You have to test each possibility.
Aurélien Vallée
Also see http://en.wikipedia.org/wiki/XOR_swap_algorithm#Reasons_for_avoidance_in_practice
UncleBens
Thank you for the great feedback, this post with comments definitely helped me out.
ccook
+1  A: 

Are you sure you profiled fully optimized code?

You should inlinethis function.

Other than that the only thing I see is that you first assign NULL to vswap and immediately afterwards some other value - but this should be taken care of by the optimizer.

 inline void Solver::Swap(double** &v1, double** &v2)
 {
   double** vswap = v2;
   v2 = v1;
   v1 = vswap;
 }

However, why don't you use std::swap()?

sbi
I actually didn't know of std::swap... (oops) On the plus, the two perform at the same speed. Ty for pointing me to std::swap
ccook
A: 

Don't assume that the 7% means this operation is slow - it depends on what else is going on.

You can have an operation that only takes 1 nanosecond, and make it take nearly 100% of the time, by doing nothing else.

Mike Dunlavey