Created
October 16, 2015 03:27
-
-
Save esprehn/717efcb989f60a5f5f71 to your computer and use it in GitHub Desktop.
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
// Sample virtual vs switch. | |
// | |
// Tested on a MBP: | |
// | |
// switch loop(965945 ticks, 0.965945 seconds) | |
// shuffled switch loop(915787 ticks, 0.915787 seconds) | |
// switch loop ptrs(993597 ticks, 0.993597 seconds) | |
// shuffled switch loop ptrs(1957770 ticks, 1.95777 seconds) | |
// virtual loop(931314 ticks, 0.931314 seconds) | |
// shuffled virtual loop(1905250 ticks, 1.90525 seconds) | |
#include <algorithm> | |
#include <ctime> | |
#include <iostream> | |
#include <random> | |
#include <string> | |
#include <vector> | |
class Base { | |
public: | |
virtual int test(int value) = 0; | |
}; | |
#define CLASS(id) \ | |
class Sub##id : public Base { \ | |
__attribute__((noinline)) \ | |
int test(int value); \ | |
}; \ | |
__attribute__((noinline)) \ | |
int apply##id (int value); | |
#include "classes.h" | |
#undef CLASS | |
#define CLASS(id) \ | |
__attribute__((noinline)) \ | |
int Sub##id ::test(int value) { \ | |
std::string s("test"); \ | |
std::transform(s.begin(), s.end(), s.begin(), toupper); \ | |
return s.size() + value + id; \ | |
} \ | |
__attribute__((noinline)) \ | |
int apply##id (int value) { \ | |
std::string s("test"); \ | |
std::transform(s.begin(), s.end(), s.begin(), toupper); \ | |
return s.size() + value + id; \ | |
} \ | |
#include "classes.h" | |
#undef CLASS | |
#define CLASS(id) Type##id, | |
enum TypeId : long { | |
#include "classes.h" | |
MaxTypeId, | |
}; | |
#undef CLASS | |
TypeId toTypeId(int i) | |
{ | |
return static_cast<TypeId>(i % MaxTypeId); | |
} | |
Base* createObject(int i) | |
{ | |
switch (toTypeId(i)) { | |
#define CLASS(id) \ | |
case id: \ | |
return new Sub##id(); | |
#include "classes.h" | |
#undef CLASS | |
default: | |
std::cout << "ERROR!" << std::endl; | |
return 0; | |
} | |
} | |
class Benchmark { | |
public: | |
Benchmark(const std::string& name) | |
: m_time(clock()) | |
, m_name(name) | |
{ } | |
~Benchmark() | |
{ | |
time_t delta = clock() - m_time; | |
std::cout | |
<< m_name | |
<< "(" | |
<< delta | |
<< " ticks, " | |
<< ((float)delta)/CLOCKS_PER_SEC | |
<< " seconds)" | |
<< std::endl; | |
} | |
private: | |
clock_t m_time; | |
std::string m_name; | |
}; | |
static int kMaxIterations = 9900000; | |
int main() | |
{ | |
{ | |
std::vector<TypeId> items; | |
for (int i = 0; i < kMaxIterations; ++i) { | |
items.push_back(toTypeId(i)); | |
} | |
Benchmark bm("switch loop"); | |
int value = 0; | |
for (int i = 0; i < kMaxIterations; ++i) { | |
switch (items[i]) { | |
#define CLASS(id) \ | |
case Type##id: \ | |
value = apply##id (value); \ | |
break; | |
#include "classes.h" | |
#undef CLASS | |
default: | |
std::cout << "ERROR!" << std::endl; | |
} | |
} | |
// std::cout << "Computed " << value << std::endl; | |
} | |
{ | |
std::vector<TypeId> items; | |
for (int i = 0; i < kMaxIterations; ++i) { | |
items.push_back(toTypeId(i)); | |
} | |
std::random_shuffle(items.begin(), items.end()); | |
Benchmark bm("shuffled switch loop"); | |
int value = 0; | |
for (int i = 0; i < kMaxIterations; ++i) { | |
switch (items[i]) { | |
#define CLASS(id) \ | |
case Type##id: \ | |
value = apply##id (value); \ | |
break; | |
#include "classes.h" | |
#undef CLASS | |
default: | |
std::cout << "ERROR!" << std::endl; | |
} | |
} | |
// std::cout << "Computed " << value << std::endl; | |
} | |
{ | |
std::vector<TypeId*> items; | |
for (int i = 0; i < kMaxIterations; ++i) { | |
TypeId* ptr = new TypeId[1]; | |
*ptr = toTypeId(i); | |
items.push_back(ptr); | |
} | |
Benchmark bm("switch loop ptrs"); | |
int value = 0; | |
for (int i = 0; i < kMaxIterations; ++i) { | |
switch (*items[i]) { | |
#define CLASS(id) \ | |
case Type##id: \ | |
value = apply##id (value); \ | |
break; | |
#include "classes.h" | |
#undef CLASS | |
default: | |
std::cout << "ERROR!" << std::endl; | |
} | |
} | |
// std::cout << "Computed " << value << std::endl; | |
} | |
{ | |
std::vector<TypeId*> items; | |
for (int i = 0; i < kMaxIterations; ++i) { | |
TypeId* ptr = new TypeId[1]; | |
*ptr = toTypeId(i); | |
items.push_back(ptr); | |
} | |
std::random_shuffle(items.begin(), items.end()); | |
Benchmark bm("shuffled switch loop ptrs"); | |
int value = 0; | |
for (int i = 0; i < kMaxIterations; ++i) { | |
switch (*items[i]) { | |
#define CLASS(id) \ | |
case Type##id: \ | |
value = apply##id (value); \ | |
break; | |
#include "classes.h" | |
#undef CLASS | |
default: | |
std::cout << "ERROR!" << std::endl; | |
} | |
} | |
// std::cout << "Computed " << value << std::endl; | |
} | |
{ | |
std::vector<Base*> items; | |
for (int i = 0; i < kMaxIterations; ++i) { | |
items.push_back(createObject(i)); | |
} | |
Benchmark bm("virtual loop"); | |
int value = 0; | |
for (int i = 0; i < kMaxIterations; ++i) { | |
value = items[i]->test(value); | |
} | |
// std::cout << "Computed " << value << std::endl; | |
} | |
{ | |
std::vector<Base*> items; | |
for (int i = 0; i < kMaxIterations; ++i) { | |
items.push_back(createObject(i)); | |
} | |
std::random_shuffle(items.begin(), items.end()); | |
Benchmark bm("shuffled virtual loop"); | |
int value = 0; | |
for (int i = 0; i < kMaxIterations; ++i) { | |
value = items[i]->test(value); | |
} | |
// std::cout << "Computed " << value << std::endl; | |
} | |
} |
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
CLASS(0) | |
CLASS(1) | |
CLASS(2) | |
CLASS(3) | |
// ... as many as you like, I tried with 500. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment