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 +++
THIS CODE IS FREE - LICENSED UNDER THE MIT LICENSE
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;
Uint32 updates_to_death;
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;
updates_to_death = 1000000;
}
void update(float dt)
{
if(updates_to_death > 0) // alive
{
--updates_to_death;
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<Uint32> updates_to_death_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),
updates_to_death_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;
updates_to_death_vec[i] = 1000000;
}
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];
Uint32 &updates_to_death = updates_to_death_vec[i];
if(updates_to_death > 0) // alive
{
--updates_to_death;
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;
}