Last active
August 19, 2016 13:14
-
-
Save iximiuz/09bdcacab4f7ccb94cf05138833f3fd6 to your computer and use it in GitHub Desktop.
C++ Return value optimization benchmark
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <chrono> | |
#include <iostream> | |
#include <stdlib.h> | |
#include <time.h> | |
#define SIZE_MEDIUM 4096 | |
#define SIZE_LARGE 16*4096 | |
#define ITER_COUNT 100000 | |
using namespace std; | |
using namespace std::chrono; | |
struct MediumStruct { | |
int data[SIZE_MEDIUM]; | |
}; | |
struct LargeStruct { | |
int data[SIZE_LARGE]; | |
}; | |
template<typename T> | |
T by_value(int size) { | |
T rv; | |
memset(rv.data, rand(), size*sizeof(rv.data[0])); | |
return rv; | |
} | |
template<typename T> | |
void by_ref(T &v, int size) { | |
memset(v.data, rand(), size*sizeof(v.data[0])); | |
} | |
template<typename T> | |
void bench_by_value(int size, const string &suite) { | |
high_resolution_clock::time_point t1 = high_resolution_clock::now(); | |
int counter = 0; | |
for (int i = 0; i < ITER_COUNT; i++) { | |
T r = by_value<T>(size); | |
for (int j = 0; j < size; j++) { | |
counter += r.data[j]; | |
} | |
} | |
high_resolution_clock::time_point t2 = high_resolution_clock::now(); | |
auto duration = duration_cast<milliseconds>(t2 - t1).count(); | |
cout << "By value (" << suite << ") " << duration << " ms " | |
<< "[stub " << counter << "]" << endl; | |
} | |
template<typename T> | |
void bench_by_ref(int size, const string &suite) { | |
high_resolution_clock::time_point t1 = high_resolution_clock::now(); | |
int counter = 0; | |
for (int i = 0; i < ITER_COUNT; i++) { | |
T r; | |
by_ref<T>(r, size); | |
for (int j = 0; j < size; j++) { | |
counter += r.data[j]; | |
} | |
} | |
high_resolution_clock::time_point t2 = high_resolution_clock::now(); | |
auto duration = duration_cast<milliseconds>(t2 - t1).count(); | |
cout << "By ref (" << suite << ") " << duration << " ms " | |
<< "[stub " << counter << "]" << endl; | |
} | |
int main() { | |
srand(time(NULL)); | |
bench_by_value<MediumStruct>(SIZE_MEDIUM, "MEDIUM"); | |
bench_by_value<LargeStruct>(SIZE_LARGE, "LARGE"); | |
bench_by_ref<MediumStruct>(SIZE_MEDIUM, "MEDIUM"); | |
bench_by_ref<LargeStruct>(SIZE_LARGE, "LARGE"); | |
} |
After reducing amount of rand()
calls in the benchmark, difference in the execution time became more visible.
$ g++ -std=c++11 main.cpp
$ ./a.out
By value (MEDIUM) 938 ms [stub 132300800]
By value (LARGE) 16048 ms [stub -1764818944]
By ref (MEDIUM) 914 ms [stub -1316978688]
By ref (LARGE) 16133 ms [stub 580321280]
$ ./a.out
By value (MEDIUM) 924 ms [stub -36802560]
By value (LARGE) 16523 ms [stub 1703346176]
By ref (MEDIUM) 930 ms [stub -87310336]
By ref (LARGE) 16630 ms [stub 594935808]
$ g++ -std=c++11 -fno-elide-constructors main.cpp
$ ./a.out
By value (MEDIUM) 1143 ms [stub -406900736]
By value (LARGE) 19949 ms [stub 1393557504]
By ref (MEDIUM) 909 ms [stub -1232310272]
By ref (LARGE) 16726 ms [stub -2084503552]
$ ./a.out
By value (MEDIUM) 1128 ms [stub -1636438016]
By value (LARGE) 18869 ms [stub 109707264]
By ref (MEDIUM) 996 ms [stub -2006835200]
By ref (LARGE) 17156 ms [stub 1202454528]
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
On my MacBook Pro this example works pretty the same with and without RVO optimization.