Skip to content

Instantly share code, notes, and snippets.

@esprehn
Created October 16, 2015 03:27
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/717efcb989f60a5f5f71 to your computer and use it in GitHub Desktop.
Save esprehn/717efcb989f60a5f5f71 to your computer and use it in GitHub Desktop.
// 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;
}
}
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