E
E. Robert Tisdale
Peteris said:E. Robert Tisdale said:That's a good start.
First,
convince us that your compiler did *not* simply inline
f(const DISK_REGISTER&) and/or g(DISK_REGISTER).
Show us the compiler version and options that you used.
pkrumins$ g++ test.cpp -o test -W -Wall
pkrumins$ g++ -v
gcc version 3.3.4
Since I am [not] optimizing, no functions were inlined.
Second,
convince us that your results are *significant*.
Run each case several times
and calculate the average time and standard deviation.
The difference in average times must be at least as large
as the standard deviation(s).
I changed the number of iterations for each test to 200 million, so
the tests took less time.
I did 10 observations.
Here are the results (sorted by time):
1. f(const DISK_REGISTER&)
N time (s) delta time (s) (delta time)^2 (s^2)
1 6,324 0,0195 0,00038025
2 6,326 0,0175 0,00030625
3 6,327 0,0165 0,00027225
4 6,334 0,0095 0,00009025
5 6,336 0,0075 0,00005625
6 6,350 0,0065 0,00004225
7 6,353 0,0095 0,00009025
8 6,354 0,0105 0,00011025
9 6,363 0,0195 0,00038025
10 6,368 0,0245 0,00060025
----- ----------
avg: 6,3435 sum: 0,00232850
standard deviation:
sqrt(sum/(n - 1)) = 0,016084844 (s)
2. g(DISK_REGISTER)
N time (s) delta time (s) (delta time)^2 (s^2)
1 5,596 0,0048 0,00002304
2 5,597 0,0038 0,00001444
3 5,599 0,0018 0,00000324
4 5,599 0,0018 0,00000324
5 5,600 0,0008 0,00000064
6 5,600 0,0008 0,00000064
7 5,601 0,0002 0,00000004
8 5,603 0,0022 0,00000484
9 5,604 0,0032 0,00001024
10 5,609 0,0082 0,00006724
----- ----------
avg: 5,601 sum: 0,00012760
standard deviation: 0,003765339 (s)
Now the results are significant and we see that pass by value is
((6.3435 - 5.601)/6.3435)*100% = 11.7%
faster than pass by const reference.
#include <iostream>cat main.cc
#include <string>
struct DISK_REGISTER {
unsigned ready:1;
unsigned error_occured:1;
unsigned disk_spinning:1;
unsigned write_protect:1;
unsigned head_loaded:1;
unsigned error_code:8;
unsigned track:9;
unsigned sector:5;
unsigned command:5;
};
void f(const DISK_REGISTER &r) {
(void) r;
}
void g(DISK_REGISTER r) {
(void) r;
}
int
main(int argc, char* argv[]) {
int result = EXIT_SUCCESS;
if (1 < argc) {
const std::string arg = argv[1];
DISK_REGISTER r;
if ("g" == arg)
for (unsigned int i = 0; i < 1000000000; ++i)
g(r);
else
if ("f" == arg)
for (unsigned i = 0; i < 1000000000; i++)
f(r);
else {
std::cerr << argv[0] << ": <f|g>" << std::endl;
result = EXIT_FAILURE;
}
}
return result;
}
16.945u 0.007s 0:16.95 99.9% 0+0k 0+0io 0pf+0wg++ -Wall -ansi -pedantic -o main main.cc
g++ --version g++ (GCC) 3.4.1
time ./main f
16.907u 0.005s 0:17.44 96.9% 0+0k 0+0io 0pf+0wtime ./main f
+0k 0+0io 0pf+0w
16.893u 0.006s 0:16.90 99.9% 0+0k 0+0io 0pf+0wtime ./main f
16.912u 0.005s 0:16.92 99.9% 0+0k 0+0io 0pf+0wtime ./main f
16.924u 0.003s 0:16.93 99.9% 0+0k 0+0io 0pf+0wtime ./main g
16.921u 0.005s 0:16.92 100.0% 0+0k 0+0io 0pf+0wtime ./main g
17.035u 0.006s 0:17.06 99.8% 0+0k 0+0io 0pf+0wtime ./main g
17.041u 0.005s 0:17.05 99.9% 0+0k 0+0io 0pf+0wtime ./main g
My compiler emits exactly the same code
for both f(const DISK_REGISTER&) and g(DISK_REGISTER).
The only difference in the calling program
in the arguments that get puhed onto the stack: