-
-
Save aG0aep6G/a1b87df1ac5930870ffe to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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