Created
October 16, 2015 01:39
-
-
Save esprehn/c6fa65eac153028ab1a3 to your computer and use it in GitHub Desktop.
Virtual vs Switch
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, compiled with | |
// clang++ -std=c++11 -O3 benchmark.cpp | |
// | |
// Tested on a MBP: | |
// | |
// Computed 33332 | |
// virtual loop(474 ticks, 0.000474 seconds) | |
// Computed 33332 | |
// switch loop(173 ticks, 0.000173 seconds) | |
#include <iostream> | |
#include <ctime> | |
#include <vector> | |
class Base { | |
public: | |
virtual int test(int value) = 0; | |
}; | |
class SubA : public Base { | |
int test(int value) override; | |
}; | |
__attribute__((noinline)) | |
int SubA::test(int value) { return value + 1; } | |
__attribute__((noinline)) | |
int applyA(int value) { return value + 1; } | |
class SubB : public Base { | |
int test(int value) override; | |
}; | |
__attribute__((noinline)) | |
int SubB::test(int value) { return value - 1; } | |
__attribute__((noinline)) | |
int applyB(int value) { return value - 1; } | |
class SubC : public Base { | |
int test(int value) override; | |
}; | |
__attribute__((noinline)) | |
int SubC::test(int value) { return value + 2; } | |
__attribute__((noinline)) | |
int applyC(int value) { return value + 2; } | |
enum TypeId { | |
TypeA, | |
TypeB, | |
TypeC, | |
MaxTypeId, | |
}; | |
TypeId toTypeId(int i) | |
{ | |
return static_cast<TypeId>(i % MaxTypeId); | |
} | |
Base* createObject(int i) | |
{ | |
switch (toTypeId(i)) { | |
case TypeA: | |
return new SubA(); | |
case TypeB: | |
return new SubB(); | |
case TypeC: | |
return new SubC(); | |
default: | |
std::cout << "ERROR!" << std::endl; | |
return nullptr; | |
} | |
} | |
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; | |
}; | |
int main() | |
{ | |
{ | |
std::vector<Base*> items; | |
for (int i = 0; i < 50000; ++i) { | |
items.push_back(createObject(i)); | |
} | |
Benchmark bm("virtual loop"); | |
int value = 0; | |
for (int i = 0; i < 50000; ++i) { | |
value = items[i]->test(value); | |
} | |
std::cout << "Computed " << value << std::endl; | |
} | |
{ | |
std::vector<TypeId> items; | |
for (int i = 0; i < 50000; ++i) { | |
items.push_back(toTypeId(i)); | |
} | |
Benchmark bm("switch loop"); | |
int value = 0; | |
for (int i = 0; i < 50000; ++i) { | |
switch (toTypeId(i)) { | |
case TypeA: | |
value = applyA(value); | |
break; | |
case TypeB: | |
value = applyB(value); | |
break; | |
case TypeC: | |
value = applyC(value); | |
break; | |
default: | |
std::cout << "ERROR!" << std::endl; | |
} | |
} | |
std::cout << "Computed " << value << std::endl; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment