Skip to content

Instantly share code, notes, and snippets.

@aG0aep6G
Created March 26, 2016 16:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save aG0aep6G/a1b87df1ac5930870ffe to your computer and use it in GitHub Desktop.
Save aG0aep6G/a1b87df1ac5930870ffe to your computer and use it in GitHub Desktop.
struct SOA(T){
import std.experimental.allocator;
import std.experimental.allocator.mallocator;
import std.meta: staticMap;
import std.typecons: Tuple;
import std.traits: FieldNameTuple;
alias toArray(T) = T[];
alias toType(string s) = typeof(__traits(getMember, T, s));
alias MemberNames = FieldNameTuple!T;
alias Types = staticMap!(toType, MemberNames);
alias ArrayTypes = staticMap!(toArray, Types);
this(size_t _size, IAllocator _alloc = allocatorObject(Mallocator.instance)){
alloc = _alloc;
size = _size;
allocate(size);
}
ref auto opDispatch(string name)() inout{
import std.meta: staticIndexOf;
alias index = staticIndexOf!(name, MemberNames);
static assert(index >= 0);
return containers[index];
}
void insertBack(Types types){
if(length == size) grow;
foreach(index, ref container; containers){
container[length] = types[index];
}
length = length + 1;
}
void insertBack(T t){
if(length == size) grow;
foreach(index, _; Types){
containers[index][length] = __traits(getMember, t, MemberNames[index]);
}
length = length + 1;
}
size_t length() const @property{
return _length;
}
~this(){
if(alloc is null) return;
foreach(ref container; containers){
alloc.dispose(container);
}
}
private:
void length(size_t len)@property{
_length = len;
}
Tuple!ArrayTypes containers;
IAllocator alloc;
size_t _length = 0;
size_t size = 0;
short growFactor = 2;
void allocate(size_t size){
if(alloc is null){
alloc = allocatorObject(Mallocator.instance);
}
foreach(index, ref container; containers){
container = alloc.makeArray!(Types[index])(size);
}
length = size;
}
void grow(){
import std.algorithm: max;
size_t newSize = max(1,size * growFactor);
size_t expandSize = newSize - size;
if(size is 0){
allocate(newSize);
}
else{
foreach(ref container; containers){
alloc.expandArray(container, expandSize);
}
}
size = newSize;
}
}
//struct with junk data
struct Foo{
float[30] xy;
float t;
float f = 42;
string name = "test";
float s;
float [50] z;
float* ptr;
}
float testSoa2(S)(ref S soa){
float sum = 0;
foreach(index; 0 .. soa.length){
sum += soa.f[index];
}
return sum * sum;
}
float testAos2(A)(ref A aos){
float sum = 0;
foreach(index; 0 .. aos.length){
sum += aos[index].f;
}
return sum * sum;
}
struct Vector3{
float x=1, y=2, z=3;
}
Vector3 testAos(A)(ref A aos){
float x=0;
float y=0;
float z=0;
foreach(index; 0 .. aos.length){
x += aos[index].x;
y += aos[index].y;
z += aos[index].z;
}
return Vector3(x, y, z);
}
Vector3 testSoa(S)(ref S soa){
float x=0;
float y=0;
float z=0;
foreach(index; 0 .. soa.length){
x += soa.x[index];
y += soa.y[index];
z += soa.z[index];
}
return Vector3(x, y, z);
}
void main(string[] args){
import std.stdio;
import std.container: Array;
import std.datetime;
import std.conv : to;
import std.exception: enforce;
auto size = args[1].to!size_t;
enum length = 1000;
writeln("benchmarking complete access");
auto aosVec = Array!Vector3();
foreach(_; 0 .. size){
aosVec.insertBack(Vector3());
}
Vector3 v;
float f;
auto d1 = benchmark!({v = testAos(aosVec);})(length)[0].to!Duration;
enforce(v == Vector3(100000, 200000, 300000));
writeln("AoS: ", d1);
auto soaVec = SOA!Vector3(size);
foreach(i; 0 .. size){
soaVec.x[i] = Vector3.init.x;
soaVec.y[i] = Vector3.init.y;
soaVec.z[i] = Vector3.init.z;
}
auto d2 = benchmark!({v = testSoa(soaVec);})(length)[0].to!Duration;
enforce(v == Vector3(100000, 200000, 300000));
writeln("SoA: ", d2);
writeln("benchmarking partial access");
auto aos = Array!(Foo)();
foreach(_; 0 .. size){
aos.insertBack(Foo());
}
auto d3 = benchmark!({f = testAos2(aos);})(length)[0].to!Duration;
enforce(f > 1e13);
writeln("AoS: ", d3);
auto soa2 = SOA!(Foo)(size);
foreach(i; 0 .. size){
soa2.f[i] = 42;
}
auto d4 = benchmark!({f = testSoa2(soa2);})(length)[0].to!Duration;
enforce(f > 1e13);
writeln("SoA: ", d4);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment