# 4FipS.com Forums

Forums dedicated to the projects hosted at 4FipS.com

## Data-oriented design & programming - A simple benchmark

> About coding, hacking, photography, and such...

### Data-oriented design & programming - A simple benchmark

Since I've been recently very interested in Data Oriented Design (DOD) and wanted to have some real numbers at hand, I've decided to write a simple benchmark that compares the Object and Data Oriented approaches in a fictive particle system. Basically, I'm trying to measure the processing speed (system throughput) at various particle counts.

The graph below shows the dependency:

Here's my configuration:
Windows Vista 64-bit
Visual Studio 2010
Intel Core 2 Quad Q8400 (4 MB Cache, 2.66 GHz, 1333 MHz FSB)
4GB RAM (at 416 MHz)

And here's the code that drives the benchmark:
Code: Select all
/*
(c) 2012 +++ Filip Stoklas, aka FipS, http://www.4FipS.com +++
ARTICLE URL: http://forums.4fips.com/viewtopic.php?f=3&t=588
*/

#include <fs/system.h>
#include <fs/math.h>

using namespace fs;
using namespace fs::system;
using namespace fs::math;

struct Cold_data
{
char dummy[32];
};

struct Particle_oop
{
Vector3_f pos;
Vector3_f vel;
Vector4_f color;
float size;
Cold_data cold_data;

void reset()
{
pos = Vector3_f(0.f, 0.f, 0.f);
vel = Vector3_f(1.f, 1.f, 1.f);
color = Vector4_f(0.f, 0.f, 0.f, 0.f);
size = 1.f;
}

void update(float dt)
{
{
pos += vel * dt;
color = Vector4_f(0.f, pos.y, 0.f, dt);
size += pos.x;
}
}
};

struct Particle_system_oop // AoS
{
std::vector<Particle_oop> particles;

explicit Particle_system_oop(size_t num_particles):
particles(num_particles)
{
for(size_t i = 0, n = particles.size(); i < n; ++i)
particles[i].reset();
}

void update(float dt)
{
for(size_t i = 0, n = particles.size(); i < n; ++i)
particles[i].update(dt);
}
};

struct Particle_system_dop // SoA
{
std::vector<Vector3_f> pos_vec;
std::vector<Vector3_f> vel_vec;
std::vector<Vector4_f> color_vec;
std::vector<float> size_vec;
std::vector<Cold_data> cold_data_vec;

explicit Particle_system_dop(size_t num_particles):
pos_vec(num_particles),
vel_vec(num_particles),
color_vec(num_particles),
size_vec(num_particles),
cold_data_vec(num_particles)
{
for(size_t i = 0, n = pos_vec.size(); i < n; ++i)
reset_particle(i);
}

void update(float dt)
{
for(size_t i = 0, n = pos_vec.size(); i < n; ++i)
update_particle(i, dt);
}

void reset_particle(size_t i)
{
pos_vec[i] = Vector3_f(0.f, 0.f, 0.f);
vel_vec[i] = Vector3_f(1.f, 1.f, 1.f);
color_vec[i] = Vector4_f(0.f, 0.f, 0.f, 0.f);
size_vec[i] = 1.f;
}

void update_particle(size_t i, float dt)
{
Vector3_f &pos = pos_vec[i];
Vector3_f &vel = vel_vec[i];
Vector4_f &color = color_vec[i];
float &size = size_vec[i];

{
pos += vel * dt;
color = Vector4_f(0.f, pos.y, 0.f, dt);
size += pos.x;
}
}
};

struct Particle_system_nop // AoS / no pool
{
typedef std::unique_ptr<Particle_oop> Particle_oop_ptr;
std::vector<Particle_oop_ptr> particles;

explicit Particle_system_nop(size_t num_particles):
particles(num_particles)
{
for(size_t i = 0, n = particles.size(); i < n; ++i)
{
particles[i] = std::move(Particle_oop_ptr(new Particle_oop));
particles[i]->reset();
}
}

void update(float dt)
{
for(size_t i = 0, n = particles.size(); i < n; ++i)
particles[i]->update(dt);
}
};

double run_particle_system_oop(size_t num_particles, size_t num_iterations)
{
Particle_system_oop particle_sys_oop(num_particles);
const double t = time_sec();
for(size_t j = 0; j < num_iterations; ++j)
particle_sys_oop.update(.1f);
const double dur = time_sec() - t;
printf("run_particle_system_oop(%u, %u) -> %f s\n",
unsigned(num_particles), unsigned(num_iterations), dur);
return dur;
}

double run_particle_system_dop(size_t num_particles, size_t num_iterations)
{
Particle_system_dop particle_sys_dop(num_particles);
const double t = time_sec();
for(size_t j = 0; j < num_iterations; ++j)
particle_sys_dop.update(.1f);
const double dur = time_sec() - t;
printf("run_particle_system_dop(%u, %u) -> %f s\n",
unsigned(num_particles), unsigned(num_iterations), dur);
return dur;
}

double run_particle_system_nop(size_t num_particles, size_t num_iterations)
{
Particle_system_nop particle_sys_nop(num_particles);
const double t = time_sec();
for(size_t j = 0; j < num_iterations; ++j)
particle_sys_nop.update(.1f);
const double dur = time_sec() - t;
printf("run_particle_system_nop(%u, %u) -> %f s\n",
unsigned(num_particles), unsigned(num_iterations), dur);
return dur;
}

int main()
{
double total_oop = 0.0;
double total_dop = 0.0;
double total_nop = 0.0;

for(size_t j = 1; j <= 100; ++j)
{
const size_t num_particles = 1000 * j;
printf("num_particles = %u\n", (unsigned)num_particles);

double dur_oop = 0.0;
double dur_dop = 0.0;
double dur_nop = 0.0;
size_t sum_particles = 0;

for(int i = 1; i <= 5; ++i)
{
const size_t num_iterations = 1000 * i;
dur_oop += run_particle_system_oop(num_particles, num_iterations);
dur_dop += run_particle_system_dop(num_particles, num_iterations);
dur_nop += run_particle_system_nop(num_particles, num_iterations);
sum_particles += num_particles * num_iterations;
}

printf("oop -> %f s, dop -> %f s , nop -> %f s\n",
dur_oop, dur_dop, dur_nop);
printf("oop -> %f M/s, dop -> %f M/s, nop -> %f M/s\n\n",
.000001 * sum_particles / dur_oop,
.000001 * sum_particles / dur_dop,
.000001 * sum_particles / dur_nop);

total_oop += dur_oop;
total_dop += dur_dop;
total_nop += dur_nop;
}

printf("total: oop -> %f s, dop -> %f s, nop -> %f s\n\n",
total_oop, total_dop, total_nop);

return 0;
}

FipS

Posts: 156
Joined: Wed Nov 12, 2008 9:49 pm
Location: Prague