Experiments in using Lua with sol2 and how best to structure the data. Contains a shoot out of SOA, vs AOS vs. MOA. SOA = Struct of Arrays AOS = Array of Structs MOA = Many Array of Structs (kind of a hybrid)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sol2_test/tests/perf_tests.cpp

431 lines
12 KiB

#include <fmt/core.h>
#include <string>
#include <fuc2/testing.hpp>
#include "stats.hpp"
using namespace fuc2;
namespace perf_tests {
struct LargeSOA {
std::vector<int> a01;
std::vector<int> a02;
std::vector<int> a03;
std::vector<int> a04;
std::vector<int> a05;
std::vector<int> a06;
std::vector<int> a07;
std::vector<int> a08;
std::vector<int> a09;
std::vector<int> a10;
std::vector<int> a11;
std::vector<int> a12;
std::vector<int> a13;
std::vector<int> a14;
std::vector<int> a15;
std::vector<int> a16;
std::vector<int> a17;
std::vector<int> a18;
std::vector<int> a19;
std::vector<int> a20;
void push_back(int x) {
a01.push_back(x);
a02.push_back(x);
a03.push_back(x);
a04.push_back(x);
a05.push_back(x);
a06.push_back(x);
a07.push_back(x);
a08.push_back(x);
a09.push_back(x);
a10.push_back(x);
a11.push_back(x);
a12.push_back(x);
a13.push_back(x);
a14.push_back(x);
a15.push_back(x);
a16.push_back(x);
a17.push_back(x);
a18.push_back(x);
a19.push_back(x);
a20.push_back(x);
}
};
struct LargeStruct {
int a01;
int a02;
int a03;
int a04;
int a05;
int a06;
int a07;
int a08;
int a09;
int a10;
int a11;
int a12;
int a13;
int a14;
int a15;
int a16;
int a17;
int a18;
int a19;
int a20;
LargeStruct(int x) :
a01(x),
a02(x),
a03(x),
a04(x),
a05(x),
a06(x),
a07(x),
a08(x),
a09(x),
a10(x),
a11(x),
a12(x),
a13(x),
a14(x),
a15(x),
a16(x),
a17(x),
a18(x),
a19(x),
a20(x) {}
};
struct S1 {
int a01;
int a02;
int a03;
int a04;
S1(int x) : a01(x), a02(x), a03(x), a04(x) { }
};
struct S2 {
int a05;
int a06;
int a07;
int a08;
S2(int x) : a05(x), a06(x), a07(x), a08(x) { }
};
struct S3 {
int a09;
int a10;
int a11;
int a12;
S3(int x) : a09(x), a10(x), a11(x), a12(x) { }
};
struct S4 {
int a13;
int a14;
int a15;
int a16;
S4(int x) : a13(x), a14(x), a15(x), a16(x) { }
};
struct S5 {
int a17;
int a18;
int a19;
int a20;
S5(int x) : a17(x), a18(x), a19(x), a20(x) { }
};
struct MultipleSOA {
std::vector<S1> s1;
std::vector<S2> s2;
std::vector<S3> s3;
std::vector<S4> s4;
std::vector<S5> s5;
void push_back(int x) {
s1.push_back({x});
s2.push_back({x});
s3.push_back({x});
s4.push_back({x});
s5.push_back({x});
}
};
struct Samples {
std::vector<Stats> soa_big_for;
std::vector<Stats> soa_many_for;
std::vector<Stats> ls_big_for;
std::vector<Stats> ls_many_for;
std::vector<Stats> moa_big_for;
std::vector<Stats> moa_many_for;
};
void test_large_soa(Samples& samples, int sample_size, int sample_number) {
auto soa = new LargeSOA();
for(int i = 0; i < sample_size; i++) {
soa->push_back(i);
}
Stats big_for;
for(int i = 0; i < sample_number; i++) {
auto start = big_for.time_start();
for(int i = 0; i < sample_size; i++) {
soa->a01[i] += soa->a02[i] + i;
soa->a02[i] += soa->a03[i] + i;
soa->a03[i] += soa->a04[i] + i;
soa->a04[i] += soa->a05[i] + i;
soa->a05[i] += soa->a06[i] + i;
soa->a06[i] += soa->a07[i] + i;
soa->a07[i] += soa->a08[i] + i;
soa->a08[i] += soa->a09[i] + i;
soa->a09[i] += soa->a10[i] + i;
soa->a10[i] += soa->a11[i] + i;
soa->a11[i] += soa->a12[i] + i;
soa->a12[i] += soa->a13[i] + i;
soa->a13[i] += soa->a14[i] + i;
soa->a14[i] += soa->a15[i] + i;
soa->a15[i] += soa->a16[i] + i;
soa->a16[i] += soa->a17[i] + i;
soa->a17[i] += soa->a18[i] + i;
soa->a18[i] += soa->a19[i] + i;
soa->a19[i] += soa->a20[i] + i;
}
big_for.sample_time(start);
}
samples.soa_big_for.push_back(big_for);
Stats many_for;
for(int i = 0; i < sample_number; i++) {
auto start = many_for.time_start();
for(int i = 0; i < sample_size; i++) soa->a01[i] += soa->a02[i] + i;
for(int i = 0; i < sample_size; i++) soa->a02[i] += soa->a03[i] + i;
for(int i = 0; i < sample_size; i++) soa->a03[i] += soa->a04[i] + i;
for(int i = 0; i < sample_size; i++) soa->a04[i] += soa->a05[i] + i;
for(int i = 0; i < sample_size; i++) soa->a05[i] += soa->a06[i] + i;
for(int i = 0; i < sample_size; i++) soa->a06[i] += soa->a07[i] + i;
for(int i = 0; i < sample_size; i++) soa->a07[i] += soa->a08[i] + i;
for(int i = 0; i < sample_size; i++) soa->a08[i] += soa->a09[i] + i;
for(int i = 0; i < sample_size; i++) soa->a09[i] += soa->a10[i] + i;
for(int i = 0; i < sample_size; i++) soa->a10[i] += soa->a11[i] + i;
for(int i = 0; i < sample_size; i++) soa->a11[i] += soa->a12[i] + i;
for(int i = 0; i < sample_size; i++) soa->a12[i] += soa->a13[i] + i;
for(int i = 0; i < sample_size; i++) soa->a13[i] += soa->a14[i] + i;
for(int i = 0; i < sample_size; i++) soa->a14[i] += soa->a15[i] + i;
for(int i = 0; i < sample_size; i++) soa->a15[i] += soa->a16[i] + i;
for(int i = 0; i < sample_size; i++) soa->a16[i] += soa->a17[i] + i;
for(int i = 0; i < sample_size; i++) soa->a17[i] += soa->a18[i] + i;
for(int i = 0; i < sample_size; i++) soa->a18[i] += soa->a19[i] + i;
for(int i = 0; i < sample_size; i++) soa->a19[i] += soa->a20[i] + i;
many_for.sample_time(start);
}
samples.soa_many_for.push_back(many_for);
}
void test_large_struct(Samples& samples, int sample_size, int sample_number) {
auto ls = new std::vector<LargeStruct>;
for(int i = 0; i < sample_size; i++) {
ls->push_back({i});
}
Stats ls_big_for;
for(int i = 0; i < sample_number; i++) {
auto start = ls_big_for.time_start();
for(auto& el : *ls) {
el.a01 += el.a02 + i;
el.a02 += el.a03 + i;
el.a03 += el.a04 + i;
el.a04 += el.a05 + i;
el.a05 += el.a06 + i;
el.a06 += el.a07 + i;
el.a07 += el.a08 + i;
el.a08 += el.a09 + i;
el.a09 += el.a10 + i;
el.a10 += el.a11 + i;
el.a11 += el.a12 + i;
el.a12 += el.a13 + i;
el.a13 += el.a14 + i;
el.a14 += el.a15 + i;
el.a15 += el.a16 + i;
el.a16 += el.a17 + i;
el.a17 += el.a18 + i;
el.a18 += el.a19 + i;
el.a19 += el.a20 + i;
}
ls_big_for.sample_time(start);
}
samples.ls_big_for.push_back(ls_big_for);
Stats ls_many_for;
for(int i = 0; i < sample_number; i++) {
auto start = ls_many_for.time_start();
for(auto& el : *ls) el.a01 += el.a02 + i;
for(auto& el : *ls) el.a02 += el.a03 + i;
for(auto& el : *ls) el.a03 += el.a04 + i;
for(auto& el : *ls) el.a04 += el.a05 + i;
for(auto& el : *ls) el.a05 += el.a06 + i;
for(auto& el : *ls) el.a06 += el.a07 + i;
for(auto& el : *ls) el.a07 += el.a08 + i;
for(auto& el : *ls) el.a08 += el.a09 + i;
for(auto& el : *ls) el.a09 += el.a10 + i;
for(auto& el : *ls) el.a10 += el.a11 + i;
for(auto& el : *ls) el.a11 += el.a12 + i;
for(auto& el : *ls) el.a12 += el.a13 + i;
for(auto& el : *ls) el.a13 += el.a14 + i;
for(auto& el : *ls) el.a14 += el.a15 + i;
for(auto& el : *ls) el.a15 += el.a16 + i;
for(auto& el : *ls) el.a16 += el.a17 + i;
for(auto& el : *ls) el.a17 += el.a18 + i;
for(auto& el : *ls) el.a18 += el.a19 + i;
for(auto& el : *ls) el.a19 += el.a20 + i;
ls_many_for.sample_time(start);
}
samples.ls_many_for.push_back(ls_many_for);
}
void test_moa_style(Samples& samples, int sample_size, int sample_number) {
auto moa = new MultipleSOA();
for(int i = 0; i < sample_size; i++) {
moa->push_back(i);
}
Stats moa_big_for;
for(int i = 0; i < sample_number; i++) {
auto start = moa_big_for.time_start();
for(int i = 0; i < sample_size; i++) {
moa->s1[i].a01 += moa->s1[i].a02 + i;
moa->s1[i].a02 += moa->s1[i].a03 + i;
moa->s1[i].a03 += moa->s1[i].a04 + i;
moa->s1[i].a04 += moa->s2[i].a05 + i;
moa->s2[i].a05 += moa->s2[i].a06 + i;
moa->s2[i].a06 += moa->s2[i].a07 + i;
moa->s2[i].a07 += moa->s2[i].a08 + i;
moa->s2[i].a08 += moa->s3[i].a09 + i;
moa->s3[i].a09 += moa->s3[i].a10 + i;
moa->s3[i].a10 += moa->s3[i].a11 + i;
moa->s3[i].a11 += moa->s3[i].a12 + i;
moa->s3[i].a12 += moa->s4[i].a13 + i;
moa->s4[i].a13 += moa->s4[i].a14 + i;
moa->s4[i].a14 += moa->s4[i].a15 + i;
moa->s4[i].a15 += moa->s4[i].a16 + i;
moa->s4[i].a16 += moa->s5[i].a17 + i;
moa->s5[i].a17 += moa->s5[i].a18 + i;
moa->s5[i].a18 += moa->s5[i].a19 + i;
moa->s5[i].a19 += moa->s5[i].a20 + i;
}
moa_big_for.sample_time(start);
}
samples.moa_big_for.push_back(moa_big_for);
Stats moa_many_for;
for(int i = 0; i < sample_number; i++) {
auto start = moa_many_for.time_start();
for(auto& el : moa->s1) {
el.a01 += el.a02 + i;
el.a02 += el.a03 + i;
el.a03 += el.a04 + i;
}
for(int i = 0; i < sample_size; i++) {
moa->s1[i].a04 += moa->s2[i].a05 + i;
}
for(auto& el : moa->s2) {
el.a05 += el.a06 + i;
el.a06 += el.a07 + i;
el.a07 += el.a08 + i;
}
for(int i = 0; i < sample_size; i++) {
moa->s2[i].a08 += moa->s3[i].a09 + i;
}
for(auto& el : moa->s3) {
el.a09 += el.a10 + i;
el.a10 += el.a11 + i;
el.a11 += el.a12 + i;
}
for(int i = 0; i < sample_size; i++) {
moa->s3[i].a12 += moa->s4[i].a13 + i;
}
for(auto& el : moa->s4) {
el.a13 += el.a14 + i;
el.a14 += el.a15 + i;
el.a15 += el.a16 + i;
}
for(int i = 0; i < sample_size; i++) {
moa->s4[i].a16 += moa->s5[i].a17 + i;
}
for(auto& el : moa->s5) {
el.a17 += el.a18 + i;
el.a18 += el.a19 + i;
el.a19 += el.a20 + i;
}
moa_many_for.sample_time(start);
}
samples.moa_many_for.push_back(moa_many_for);
}
void test_soa_performance() {
Samples samples;
int sample_size = 1000;
int sample_count = 1000;
for(int i = 0; i < 100; i++) {
// quick and dirty "randomness"
if(i % 2 == 0) {
test_large_soa(samples, sample_size, sample_count);
test_large_struct(samples, sample_size, sample_count);
test_moa_style(samples, sample_count, sample_count);
} else if(i % 3 == 0) {
test_large_struct(samples, sample_size, sample_count);
test_large_soa(samples, sample_size, sample_count);
test_moa_style(samples, sample_count, sample_count);
} else {
test_moa_style(samples, sample_count, sample_count);
test_large_struct(samples, sample_size, sample_count);
test_large_soa(samples, sample_size, sample_count);
}
}
fmt::println("soa_bf soa_mf ls_bf ls_mf moa_bf moa_mf");
for(size_t i = 0; i < samples.soa_big_for.size(); i++) {
fmt::println("{:.2f} {:.2f} {:.2f} {:.2f} {:.2f} {:.2f}",
samples.soa_big_for[i].mean(),
samples.soa_many_for[i].mean(),
samples.ls_big_for[i].mean(),
samples.ls_many_for[i].mean(),
samples.moa_big_for[i].mean(),
samples.moa_many_for[i].mean());
}
}
fuc2::Set TESTS{
.name="perf",
.tests={
TEST(test_soa_performance),
}
};
}