Skip to content

Commit 83781b6

Browse files
author
Eddie
committed
Comparison of runtime polymorphic with Zoo type erasure
1 parent 9a1e406 commit 83781b6

File tree

1 file changed

+227
-0
lines changed

1 file changed

+227
-0
lines changed

benchmark/cm/main.cpp

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
#include "zoo/Any/DerivedVTablePolicy.h"
2+
#include "zoo/AnyContainer.h"
3+
4+
#include <math.h>
5+
#include <stdint.h>
6+
7+
/* Some definitions necessary, they are not in the listings */
8+
using f32 = float;
9+
constexpr f32 Pi32 = M_PI;
10+
using u32 = uint32_t;
11+
12+
/* ========================================================================
13+
LISTING 22
14+
======================================================================== */
15+
16+
class shape_base
17+
{
18+
public:
19+
shape_base() {}
20+
virtual f32 Area() = 0;
21+
};
22+
23+
class square : public shape_base
24+
{
25+
public:
26+
square(f32 SideInit) : Side(SideInit) {}
27+
f32 AreaNP() {return Side*Side;}
28+
virtual f32 Area() {return Side*Side;}
29+
30+
private:
31+
f32 Side;
32+
};
33+
34+
class rectangle : public shape_base
35+
{
36+
public:
37+
rectangle(f32 WidthInit, f32 HeightInit) : Width(WidthInit), Height(HeightInit) {}
38+
f32 AreaNP() {return Width*Height;}
39+
virtual f32 Area() {return Width*Height;}
40+
41+
private:
42+
f32 Width, Height;
43+
};
44+
45+
class triangle : public shape_base
46+
{
47+
public:
48+
triangle(f32 BaseInit, f32 HeightInit) : Base(BaseInit), Height(HeightInit) {}
49+
f32 AreaNP() {return 0.5f*Base*Height;}
50+
virtual f32 Area() {return 0.5f*Base*Height;}
51+
52+
private:
53+
f32 Base, Height;
54+
};
55+
56+
class circle : public shape_base
57+
{
58+
public:
59+
circle(f32 RadiusInit) : Radius(RadiusInit) {}
60+
f32 AreaNP() {return Pi32*Radius*Radius;}
61+
virtual f32 Area() {return Pi32*Radius*Radius;}
62+
63+
private:
64+
f32 Radius;
65+
};
66+
67+
/* ========================================================================
68+
LISTING 23
69+
======================================================================== */
70+
71+
f32 TotalAreaVTBL(u32 ShapeCount, shape_base **Shapes)
72+
{
73+
f32 Accum = 0.0f;
74+
for(u32 ShapeIndex = 0; ShapeIndex < ShapeCount; ++ShapeIndex)
75+
{
76+
Accum += Shapes[ShapeIndex]->Area();
77+
}
78+
79+
return Accum;
80+
}
81+
82+
#include <chrono>
83+
#include <memory>
84+
#include <vector>
85+
#include <random>
86+
#include <stdexcept>
87+
#include <atomic>
88+
89+
std::atomic_int sideEffect = 0;
90+
91+
template<typename F, typename... Args>
92+
auto benchmark(F &&f, Args &&...args) {
93+
auto start = std::chrono::high_resolution_clock::now();
94+
sideEffect = f(std::forward<Args>(args)...);
95+
auto end = std::chrono::high_resolution_clock::now();
96+
return end - start;
97+
}
98+
99+
template <typename Duration>
100+
auto toNanoseconds(Duration &&duration) {
101+
return std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count();
102+
}
103+
104+
template<typename G, typename D>
105+
shape_base *buildShape(int shapeTypeIndex, G &&g, D &&d) {
106+
switch(shapeTypeIndex) {
107+
case 0: return new square(d(g));
108+
case 1: return new rectangle(d(g), d(g));
109+
case 2: return new triangle(d(g), d(g));
110+
case 3: return new circle(d(g));
111+
default: throw std::runtime_error("Impossible shape allocation");
112+
}
113+
}
114+
115+
struct ShapeCollection {
116+
std::vector<shape_base *> storage_;
117+
static inline int deletions_ = 0;
118+
119+
template<typename G>
120+
ShapeCollection(G &&g, int count) {
121+
std::uniform_int_distribution shape(0, 2);
122+
std::uniform_real_distribution rd(0.00001, 1.2);
123+
for(auto c = count; c--; ) {
124+
std::unique_ptr<shape_base> temporary(buildShape(shape(g), g, rd));
125+
storage_.push_back(temporary.get());
126+
temporary.release();
127+
}
128+
}
129+
130+
~ShapeCollection() {
131+
for(auto ptr: storage_) {
132+
delete ptr;
133+
++deletions_;
134+
}
135+
}
136+
};
137+
138+
139+
#include <iostream>
140+
141+
struct ShapeAffordance {
142+
template<typename> struct Mixin {};
143+
144+
struct VTableEntry { f32 (*area)(void *); };
145+
146+
template<typename>
147+
constexpr static VTableEntry DefaultImplementation =
148+
{ [](void *) { return 0.0f; } };
149+
template<typename VM>
150+
constexpr static VTableEntry Operation = {
151+
[](void *p) {
152+
auto vm = static_cast<VM *>(p);
153+
auto value = reinterpret_cast<typename VM::ManagedType *>(vm->value());
154+
return value->AreaNP();
155+
}
156+
};
157+
158+
template<typename AC>
159+
struct UserAffordance {
160+
f32 area() {
161+
AC *ac = static_cast<AC *>(this);
162+
auto vm = ac->container();
163+
return vm->template vTable<ShapeAffordance>()->area(vm);
164+
}
165+
};
166+
};
167+
168+
using P = zoo::Policy<void *[2], ShapeAffordance, zoo::Destroy, zoo::Move>;
169+
using Shape = zoo::AnyContainer<P>;
170+
171+
static_assert(24 == sizeof(Shape));
172+
173+
auto zooTraverse(std::vector<Shape> &s) {
174+
f32 rv = 0;
175+
for(auto &shape: s) {
176+
rv += shape.area();
177+
}
178+
return rv;
179+
}
180+
181+
int main(int argc, const char *argv[]) {
182+
std::random_device rd;
183+
std::mt19937 mersenne(rd());
184+
constexpr auto Count = 1'048'583;
185+
//constexpr auto Count = 32749;
186+
auto virtualInheritance = [](auto &&mersenne) {
187+
ShapeCollection collection(mersenne, Count);
188+
auto dur = benchmark(
189+
[](auto c, auto ptrs) { return static_cast<int>(TotalAreaVTBL(c, ptrs)); },
190+
collection.storage_.size(),
191+
collection.storage_.data()
192+
);
193+
return dur;
194+
};
195+
auto zooTypeErasure = [](auto &&m) {
196+
std::vector<Shape> shapes;
197+
std::uniform_int_distribution sti(0, 2);
198+
std::uniform_real_distribution rd(0.00001, 1.2);
199+
for(int i = Count; i--; ) {
200+
auto shapeTypeIndex = sti(m);
201+
switch(shapeTypeIndex) {
202+
case 0: shapes.push_back(square(rd(m))); break;
203+
case 1: shapes.push_back(rectangle(rd(m), rd(m))); break;
204+
case 2: shapes.push_back(triangle(rd(m), rd(m))); break;
205+
case 3: shapes.push_back(circle(rd(m))); break;
206+
default: throw std::runtime_error("Impossible shape type index");
207+
}
208+
}
209+
return
210+
benchmark(
211+
zooTraverse,
212+
shapes
213+
);
214+
};
215+
auto report = [](auto duration) {
216+
auto nanos = toNanoseconds(duration);
217+
constexpr auto Cycle = 1/3.6;
218+
std::cout << nanos << ' ' << nanos/double(Count) << ' ' << nanos/Cycle/Count << ' ' << sideEffect << std::endl;
219+
};
220+
auto zte1 = zooTypeErasure(mersenne);
221+
auto durationVI = virtualInheritance(mersenne);
222+
auto zte2 = zooTypeErasure(mersenne);
223+
report(zte1);
224+
report(durationVI);
225+
report(zte2);
226+
return 0;
227+
}

0 commit comments

Comments
 (0)