I noticed this accidentally one day, and now decided to test it extensively.
So, when I call a function:
#define Type int
#define Prm const Type &
Type testfunc1(Prm v1, Prm v2, Prm v3, Prm v4, Prm v5, Prm v6, Prm v7, Prm v8, Prm v9, Prm v10){
return (v1|v2|v3|v4|v5|v6|v7|v8|v9|v10);
}
100 million times:
for(Type y = 0; y < 10000; y++){
for(Type x = 0; x < 10000; x++){
out |= testfunc1(x,y,x,x,y,y,x,y,x,y);
}
}
With types int
, const int
and const int &
, i notice that const int
is faster than const int &
. (Note: im using the return value to ensure the function wont get optimized off).
Why is it so? I always thought adding &
would actually make it faster, but the tests say the opposite. I know for bigger datatypes it would probably be different outcome, I didnt test those though since I'm quite sure about the results.
My tests:
const int: 7.95s
const int &: 10.2s
Edit: I think it is indeed because of my architecture; I tested with Sint64
type and the results were:
const Sint64: 17.5s
const Sint64 &: 16.2s
Edit2: Or is it? Tested with double
type (which is 64bit?), and results make me puzzled:
const double: 11.28s
const double &: 12.34s
Edit3: updated the loop code to match my newest tests with 64bit types.
By putting a &
into the argument, you are adding more code to the program. Without the &
, the sequence is:
push values
call Function
pop values <- usually an update to stack pointer
and in Function:
return sp[arg1] | sp[arg2] | etc <- value read direct from stack.
Adding the '&' does this:
push address of value1
push address of value2
etc
call Function
pop values <- usually an update to stack pointer
and in Function:
return_value = 0;
address = sp[arg1]
or return_value, [address]
address = sp[arg2]
or return_value, [address]
etc
return return_value
So, as you can see, the &
adds a lot. So why use it? If you have a very large object, passing a pointer is more optimal than copying the object to the stack.
This result is heavily system-dependent. It indicates that on your particular system copying a value of a reference (which is most likely implemented as a pointer) has higher cost than copying a value of an integer. The most probable reason for that difference is that your integer requires 32-bits to represent, and your pointer/reference representation requires 64-bits. EDIT This is not to mention the cost of accessing your integers: getting their values would require an additional indirection. Since you are passing only two items, use of caching hides that additional cost to a large extent, but the cost is there.
You are absolutely right about larger types, though: passing a reference to, say, a large struct
or a vector<...>
still requires only 64 bit (or whatever that size is on your system), regardless of how many items your structure has, or how many items your vector<...>
holds. The larger the structure, the higher the costs to pass it by value, and therefore the savings that you realize by making it a reference.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With