Skip to content

Instantly share code, notes, and snippets.

@esprehn
Created October 16, 2015 02:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save esprehn/e63070367e183ad2dc43 to your computer and use it in GitHub Desktop.
Save esprehn/e63070367e183ad2dc43 to your computer and use it in GitHub Desktop.
// Sample virtual vs switch.
// clang++ -std=c++11 -O3 benchmark3.cpp && ./a.out
//
// Tested on a MBP:
//
// switch loop(10712 ticks, 0.010712 seconds)
// shuffled switch loop(10587 ticks, 0.010587 seconds)
// virtual loop(10583 ticks, 0.010583 seconds)
// shuffled virtual loop(14292 ticks, 0.014292 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 rand() + 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 rand() + s.size() + value + id; \
} \
#include "classes.h"
#undef CLASS
#define CLASS(id) Type##id,
enum TypeId {
#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 = 100000;
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 (toTypeId(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 (toTypeId(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;
}
}
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