Skip to content

Instantly share code, notes, and snippets.

@SanderMertens
Last active June 27, 2025 23:23
Show Gist options
  • Save SanderMertens/00cfd8480650d9979109ff465d516f32 to your computer and use it in GitHub Desktop.
Save SanderMertens/00cfd8480650d9979109ff465d516f32 to your computer and use it in GitHub Desktop.
#include <prefab_storage_tests.h>
#include <stdio.h>
ECS_COMPONENT_DECLARE(Position);
ECS_COMPONENT_DECLARE(Rotation);
ECS_COMPONENT_DECLARE(Velocity);
ECS_COMPONENT_DECLARE(Transform);
ECS_COMPONENT_DECLARE(TransformRef);
ECS_COMPONENT_DECLARE(Parent);
ECS_COMPONENT_DECLARE(Children);
typedef struct Position {
float x, y, z;
} Position;
typedef struct Velocity {
float x, y, z;
} Velocity;
typedef struct Rotation {
float x, y, z;
} Rotation;
typedef struct Transform {
mat4 value;
} Transform;
typedef struct TransformRef {
ecs_ref_t value;
} TransformRef;
typedef struct Parent {
ecs_entity_t value;
} Parent;
typedef struct Children {
ecs_entity_t *value;
int32_t count;
int32_t size;
} Children;
void Children_reserve(Children *c, int32_t count) {
assert(c->size == 0);
c->size = count;
c->count = 0;
c->value = ecs_os_malloc_n(ecs_entity_t, count);
}
void Children_append(Children *c) {
if (c->size == c->count) {
if (!c->size) {
c->size = 1;
} else {
c->size *= 2;
}
c->value = ecs_os_realloc_n(c->value, ecs_entity_t, c->size);
}
c->count ++;
}
typedef struct FlattenedSoA {
Position *p;
Rotation *r;
Transform *t;
int32_t count, size;
} FlattenedSoA;
void FlattenedSoA_reserve(FlattenedSoA *f, int32_t count) {
assert(f->size == 0);
f->size = count;
f->count = 0;
f->p = ecs_os_malloc_n(Position, count);
f->r = ecs_os_malloc_n(Rotation, count);
f->t = ecs_os_malloc_n(Transform, count);
}
void FlattenedSoA_append(FlattenedSoA *f) {
if (f->size == f->count) {
if (!f->size) {
f->size = 1;
} else {
f->size *= 2;
}
f->p = ecs_os_realloc_n(f->p, Position, f->size);
f->r = ecs_os_realloc_n(f->r, Rotation, f->size);
f->t = ecs_os_realloc_n(f->t, Transform, f->size);
}
f->count ++;
}
typedef struct FlattenedAoSElem {
Position p;
Rotation r;
Transform t;
} FlattenedAoSElem;
typedef struct FlattenedAoS {
FlattenedAoSElem *v;
int32_t count, size;
} FlattenedAoS;
void FlattenedAoS_reserve(FlattenedAoS *f, int32_t count) {
assert(f->size == 0);
f->size = count;
f->count = 0;
f->v = ecs_os_malloc_n(FlattenedAoSElem, count);
}
void FlattenedAoS_append(FlattenedAoS *f) {
if (f->size == f->count) {
if (!f->size) {
f->size = 1;
} else {
f->size *= 2;
}
f->v = ecs_os_realloc_n(f->v, FlattenedAoSElem, f->size);
}
f->count ++;
}
int InstanceCount = 20000;
int ChildCount = 20;
int ChildFragmentationCount = 4;
int ChildrenWithGrandChildren = 10;
int GrandChildCount = 2;
int QuerySampleCount = 20;
void fragmenting_dfs(ecs_world_t *world, ecs_entity_t parent, Transform *pt) {
ecs_query_t *q = ecs_query(world, {
.terms = {
{ ecs_childof(parent) },
{ ecs_id(Position) },
{ ecs_id(Rotation) },
{ ecs_id(Transform) }
}
});
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 1);
Rotation *r = ecs_field(&it, Rotation, 2);
Transform *t = ecs_field(&it, Transform, 3);
for (int i = 0; i < it.count; i ++) {
glm_translate_to(pt[0].value, *(vec3*)&p[i], t[i].value);
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0});
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0});
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0});
}
if (ecs_table_has_traversable(it.table)) {
for (int i = 0; i < it.count; i ++) {
fragmenting_dfs(world, it.entities[i], &t[i]);
}
}
}
ecs_query_fini(q);
}
void fragmenting() {
ecs_world_t *world = ecs_init();
ECS_COMPONENT_DEFINE(world, Position);
ECS_COMPONENT_DEFINE(world, Rotation);
ECS_COMPONENT_DEFINE(world, Velocity);
ECS_COMPONENT_DEFINE(world, Transform);
ECS_COMPONENT_DEFINE(world, TransformRef);
ECS_COMPONENT_DEFINE(world, Parent);
ECS_COMPONENT_DEFINE(world, Children);
ecs_query_t *q_move = ecs_query(world, {
.expr = "Position, Velocity",
.cache_kind = EcsQueryCacheAuto
});
ecs_query_t *q = ecs_query(world, {
.expr = "Position, Rotation, Transform, ?Transform(cascade)",
.cache_kind = EcsQueryCacheAuto
});
ecs_query_t *q_roots = ecs_query(world, {
.expr = "Position, Rotation, Transform, !(ChildOf, *)",
.cache_kind = EcsQueryCacheAuto
});
int child_fragment_ids[ChildFragmentationCount];
for (int i = 0; i < ChildFragmentationCount; i ++) {
child_fragment_ids[i] = ecs_new(world);
}
ecs_time_t t; ecs_time_measure(&t);
ecs_table_t *table = ecs_table_find(world, (ecs_id_t[]){
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform)
}, 4);
for (int i = 0; i < InstanceCount; i ++) {
ecs_entity_t inst = ecs_new_w_table(world, table);
ecs_set(world, inst, Position, {i, i, i});
ecs_set(world, inst, Rotation, {0, 0, 0});
ecs_set(world, inst, Velocity, {0, 0, 0});
ecs_table_t *child_table =
ecs_table_add_id(world, table, ecs_pair(EcsChildOf, inst));
for (int c = 0; c < ChildCount; c ++) {
ecs_entity_t child = ecs_new_w_table(world, child_table);
ecs_set(world, child, Position, {c, c, c});
ecs_set(world, child, Rotation, {0, 0, 0});
ecs_set(world, child, Velocity, {0, 0, 0});
ecs_add_id(world, child, child_fragment_ids[c % ChildFragmentationCount]);
if (c < ChildrenWithGrandChildren) {
for (int gc = 0; gc < GrandChildCount; gc ++) {
ecs_entity_t grandchild = ecs_new_w_table(world, table);
ecs_add_pair(world, grandchild, EcsChildOf, child);
ecs_set(world, grandchild, Position, {c, c, c});
ecs_set(world, grandchild, Rotation, {0, 0, 0});
ecs_set(world, grandchild, Velocity, {0, 0, 0});
}
}
}
}
printf("create: %.3f\n", ecs_time_measure(&t));
for (int x = 0; x < QuerySampleCount; x ++) {
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 0);
Rotation *r = ecs_field(&it, Rotation, 1);
Transform *t = ecs_field(&it, Transform, 2);
Transform *pt = ecs_field(&it, Transform, 3);
if (!pt) {
for (int i = 0; i < it.count; i ++) {
glm_translate_make(t[i].value, *(vec3*)&p[i]);
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0});
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0});
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0});
}
} else {
for (int i = 0; i < it.count; i ++) {
glm_translate_to(pt[0].value, *(vec3*)&p[i], t[i].value);
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0});
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0});
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0});
}
}
}
}
printf("transform (bfs): %.3f\n", ecs_time_measure(&t));
for (int x = 0; x < QuerySampleCount; x ++) {
ecs_iter_t it = ecs_query_iter(world, q_roots);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 0);
Rotation *r = ecs_field(&it, Rotation, 1);
Transform *t = ecs_field(&it, Transform, 2);
for (int i = 0; i < it.count; i ++) {
glm_translate_make(t[i].value, *(vec3*)&p[i]);
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0});
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0});
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0});
}
for (int i = 0; i < it.count; i ++) {
fragmenting_dfs(world, it.entities[i], &t[i]);
}
}
}
printf("transform (dfs): %.3f\n", ecs_time_measure(&t));
for (int x = 0; x < QuerySampleCount; x ++) {
ecs_iter_t it = ecs_query_iter(world, q_move);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 0);
Velocity *v = ecs_field(&it, Velocity, 1);
for (int i = 0; i < it.count; i ++) {
p[i].x += v[i].x;
p[i].y += v[i].y;
p[i].z += v[i].z;
}
}
}
printf("move: %.3f\n", ecs_time_measure(&t));
ecs_fini(world);
}
void child_tables_dfs(ecs_world_t *world, ecs_entity_t parent, Transform *pt, Children *parent_children) {
for (int i = 0; i < parent_children->count; i ++) {
ecs_entity_t child = parent_children->value[i];
Position *p = ecs_get_mut(world, child, Position);
Rotation *r = ecs_get_mut(world, child, Rotation);
Transform *t = ecs_get_mut(world, child, Transform);
glm_translate_to(pt->value, *(vec3*)p, t->value);
glm_rotate(t->value, r->x, (vec3){1.0, 0.0, 0.0});
glm_rotate(t->value, r->y, (vec3){0.0, 1.0, 0.0});
glm_rotate(t->value, r->z, (vec3){0.0, 0.0, 1.0});
Children *children = ecs_get_mut(world, child, Children);
if (children) {
child_tables_dfs(world, child, t, children);
}
}
}
void child_tables() {
ecs_world_t *world = ecs_init();
ECS_COMPONENT_DEFINE(world, Position);
ECS_COMPONENT_DEFINE(world, Rotation);
ECS_COMPONENT_DEFINE(world, Velocity);
ECS_COMPONENT_DEFINE(world, Transform);
ECS_COMPONENT_DEFINE(world, TransformRef);
ECS_COMPONENT_DEFINE(world, Parent);
ECS_COMPONENT_DEFINE(world, Children);
ECS_ENTITY(world, Depth, Exclusive);
ECS_TAG(world, Depth0);
ECS_TAG(world, Depth1);
ECS_TAG(world, Depth2);
ecs_entity_t child_kinds[ChildCount + GrandChildCount];
for (int i = 0; i < ChildCount + GrandChildCount; i ++) {
child_kinds[i] = ecs_new(world);
}
int child_fragment_ids[ChildFragmentationCount];
for (int i = 0; i < ChildFragmentationCount; i ++) {
child_fragment_ids[i] = ecs_new(world);
}
ecs_query_t *q_move = ecs_query(world, {
.expr = "Position, Velocity",
.cache_kind = EcsQueryCacheAuto
});
ecs_query_t *q = ecs_query(world, {
.expr = "Position, Rotation, Transform, ?Parent",
.group_by = Depth
});
ecs_query_t *q_roots = ecs_query(world, {
.expr = "Position, Rotation, Transform, ?Children, !Parent",
.cache_kind = EcsQueryCacheAuto
});
ecs_time_t t; ecs_time_measure(&t);
ecs_table_t *table = ecs_table_find(world, (ecs_id_t[]){
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Children), ecs_pair(Depth, Depth0)
}, 6);
ecs_table_t *child_table = ecs_table_find(world, (ecs_id_t[]){
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Parent), ecs_pair(Depth, Depth1)
}, 6);
ecs_table_t *grand_child_table = ecs_table_find(world, (ecs_id_t[]){
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Parent), ecs_pair(Depth, Depth2)
}, 6);
for (int i = 0; i < InstanceCount; i ++) {
ecs_entity_t inst = ecs_new_w_table(world, table);
ecs_set(world, inst, Position, {i, i, i});
ecs_set(world, inst, Rotation, {0, 0, 0});
ecs_set(world, inst, Velocity, {0, 0, 0});
Children *children = ecs_get_mut(world, inst, Children);
ecs_os_zeromem(children);
Children_reserve(children, ChildCount);
for (int c = 0; c < ChildCount; c ++) {
ecs_entity_t child = ecs_new_w_table(world, child_table);
ecs_set(world, child, Parent, {inst});
ecs_set(world, child, Position, {c, c, c});
ecs_set(world, child, Rotation, {0, 0, 0});
ecs_set(world, child, Velocity, {0, 0, 0});
ecs_add_id(world, child, child_kinds[c]);
ecs_add_id(world, child, child_fragment_ids[c % ChildFragmentationCount]);
Children_append(children);
children->value[children->count - 1] = child;
if (c < ChildrenWithGrandChildren) {
Children *gchildren = ecs_ensure(world, child, Children);
ecs_os_zeromem(gchildren);
Children_reserve(gchildren, GrandChildCount);
for (int gc = 0; gc < GrandChildCount; gc ++) {
ecs_entity_t grandchild = ecs_new_w_table(world, grand_child_table);
ecs_set(world, grandchild, Parent, {child});
ecs_set(world, grandchild, Position, {c, c, c});
ecs_set(world, grandchild, Rotation, {0, 0, 0});
ecs_set(world, grandchild, Velocity, {0, 0, 0});
ecs_add_id(world, grandchild, child_kinds[ChildCount + gc]);
Children_append(gchildren);
gchildren->value[gchildren->count - 1] = grandchild;
}
}
}
}
printf("create: %.3f\n", ecs_time_measure(&t));
for (int x = 0; x < QuerySampleCount; x ++) {
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 0);
Rotation *r = ecs_field(&it, Rotation, 1);
Transform *t = ecs_field(&it, Transform, 2);
Parent *parent = ecs_field(&it, Parent, 3);
if (!parent) {
for (int i = 0; i < it.count; i ++) {
glm_translate_make(t[i].value, *(vec3*)&p[i]);
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0});
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0});
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0});
}
} else {
for (int i = 0; i < it.count; i ++) {
Transform *pt = ecs_get_mut(world, parent[i].value, Transform);
glm_translate_to(pt[0].value, *(vec3*)&p[i], t[i].value);
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0});
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0});
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0});
}
}
}
}
printf("transform (bfs): %.3f\n", ecs_time_measure(&t));
for (int x = 0; x < QuerySampleCount; x ++) {
ecs_iter_t it = ecs_query_iter(world, q_roots);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 0);
Rotation *r = ecs_field(&it, Rotation, 1);
Transform *t = ecs_field(&it, Transform, 2);
Children *children = ecs_field(&it, Children, 3);
for (int i = 0; i < it.count; i ++) {
glm_translate_make(t[i].value, *(vec3*)&p[i]);
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0});
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0});
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0});
}
if (children) {
for (int i = 0; i < it.count; i ++) {
child_tables_dfs(world, it.entities[i], &t[i], children);
}
}
}
}
printf("transform (dfs): %.3f\n", ecs_time_measure(&t));
for (int x = 0; x < QuerySampleCount; x ++) {
ecs_iter_t it = ecs_query_iter(world, q_move);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 0);
Velocity *v = ecs_field(&it, Velocity, 1);
for (int i = 0; i < it.count; i ++) {
p[i].x += v[i].x;
p[i].y += v[i].y;
p[i].z += v[i].z;
}
}
}
printf("move: %.3f\n", ecs_time_measure(&t));
ecs_fini(world);
}
void child_tables_w_ref() {
ecs_world_t *world = ecs_init();
ECS_COMPONENT_DEFINE(world, Position);
ECS_COMPONENT_DEFINE(world, Rotation);
ECS_COMPONENT_DEFINE(world, Velocity);
ECS_COMPONENT_DEFINE(world, Transform);
ECS_COMPONENT_DEFINE(world, TransformRef);
ECS_COMPONENT_DEFINE(world, Parent);
ECS_COMPONENT_DEFINE(world, Children);
ECS_TAG(world, Depth);
ECS_TAG(world, Depth0);
ECS_TAG(world, Depth1);
ECS_TAG(world, Depth2);
ecs_entity_t child_kinds[ChildCount + GrandChildCount];
for (int i = 0; i < ChildCount + GrandChildCount; i ++) {
child_kinds[i] = ecs_new(world);
}
int child_fragment_ids[ChildFragmentationCount];
for (int i = 0; i < ChildFragmentationCount; i ++) {
child_fragment_ids[i] = ecs_new(world);
}
ecs_query_t *q_move = ecs_query(world, {
.expr = "Position, Velocity",
.cache_kind = EcsQueryCacheAuto
});
ecs_query_t *q = ecs_query(world, {
.expr = "Position, Rotation, Transform, ?TransformRef",
.group_by = Depth
});
ecs_query_t *q_roots = ecs_query(world, {
.expr = "Position, Rotation, Transform, ?Children, !Parent",
.cache_kind = EcsQueryCacheAuto
});
ecs_time_t t; ecs_time_measure(&t);
ecs_table_t *table = ecs_table_find(world, (ecs_id_t[]){
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Children), ecs_pair(Depth, Depth0)
}, 6);
ecs_table_t *child_table = ecs_table_find(world, (ecs_id_t[]){
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(TransformRef), ecs_id(Parent), ecs_pair(Depth, Depth1)
}, 7);
ecs_table_t *grand_child_table = ecs_table_find(world, (ecs_id_t[]){
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(TransformRef), ecs_id(Parent), ecs_pair(Depth, Depth2)
}, 7);
for (int i = 0; i < InstanceCount; i ++) {
ecs_entity_t inst = ecs_new_w_table(world, table);
ecs_set(world, inst, Position, {i, i, i});
ecs_set(world, inst, Rotation, {0, 0, 0});
ecs_set(world, inst, Velocity, {0, 0, 0});
Children *children = ecs_get_mut(world, inst, Children);
ecs_os_zeromem(children);
Children_reserve(children, ChildCount);
ecs_ref_t tr = ecs_ref_init(world, inst, Transform);
for (int c = 0; c < ChildCount; c ++) {
ecs_entity_t child = ecs_new_w_table(world, child_table);
ecs_set(world, child, Parent, {inst});
ecs_set(world, child, Position, {c, c, c});
ecs_set(world, child, Rotation, {0, 0, 0});
ecs_set(world, child, Velocity, {0, 0, 0});
ecs_set(world, child, TransformRef, {tr});
ecs_add_id(world, child, child_kinds[c]);
ecs_add_id(world, child, child_fragment_ids[c % ChildFragmentationCount]);
ecs_ref_t tr_child = ecs_ref_init(world, inst, Transform);
Children_append(children);
children->value[children->count - 1] = child;
if (c < ChildrenWithGrandChildren) {
Children *gchildren = ecs_ensure(world, child, Children);
ecs_os_zeromem(gchildren);
Children_reserve(gchildren, GrandChildCount);
for (int gc = 0; gc < GrandChildCount; gc ++) {
ecs_entity_t grandchild = ecs_new_w_table(world, grand_child_table);
ecs_set(world, grandchild, Parent, {child});
ecs_set(world, grandchild, Position, {c, c, c});
ecs_set(world, grandchild, Rotation, {0, 0, 0});
ecs_set(world, grandchild, Velocity, {0, 0, 0});
ecs_set(world, grandchild, TransformRef, {tr_child});
ecs_add_id(world, grandchild, child_kinds[ChildCount + gc]);
Children_append(gchildren);
gchildren->value[gchildren->count - 1] = grandchild;
}
}
}
}
printf("create: %.3f\n", ecs_time_measure(&t));
for (int x = 0; x < QuerySampleCount; x ++) {
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 0);
Rotation *r = ecs_field(&it, Rotation, 1);
Transform *t = ecs_field(&it, Transform, 2);
TransformRef *pt_ref = ecs_field(&it, TransformRef, 3);
if (!pt_ref) {
for (int i = 0; i < it.count; i ++) {
glm_translate_make(t[i].value, *(vec3*)&p[i]);
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0});
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0});
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0});
}
} else {
for (int i = 0; i < it.count; i ++) {
Transform *pt = ecs_ref_get(world, &pt_ref->value, Transform);
glm_translate_to(pt[0].value, *(vec3*)&p[i], t[i].value);
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0});
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0});
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0});
}
}
}
}
printf("transform (bfs): %.3f\n", ecs_time_measure(&t));
for (int x = 0; x < QuerySampleCount; x ++) {
ecs_iter_t it = ecs_query_iter(world, q_roots);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 0);
Rotation *r = ecs_field(&it, Rotation, 1);
Transform *t = ecs_field(&it, Transform, 2);
Children *children = ecs_field(&it, Children, 3);
for (int i = 0; i < it.count; i ++) {
glm_translate_make(t[i].value, *(vec3*)&p[i]);
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0});
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0});
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0});
}
if (children) {
for (int i = 0; i < it.count; i ++) {
child_tables_dfs(world, it.entities[i], &t[i], children);
}
}
}
}
printf("transform (dfs): %.3f\n", ecs_time_measure(&t));
for (int x = 0; x < QuerySampleCount; x ++) {
ecs_iter_t it = ecs_query_iter(world, q_move);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 0);
Velocity *v = ecs_field(&it, Velocity, 1);
for (int i = 0; i < it.count; i ++) {
p[i].x += v[i].x;
p[i].y += v[i].y;
p[i].z += v[i].z;
}
}
}
printf("move: %.3f\n", ecs_time_measure(&t));
ecs_fini(world);
}
void child_tables_flattened_soa() {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Rotation);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Transform);
ECS_COMPONENT(world, Parent);
ECS_COMPONENT(world, Children);
ECS_COMPONENT(world, FlattenedSoA);
ECS_TAG(world, Depth);
ECS_TAG(world, Depth0);
ECS_TAG(world, Depth1);
ECS_TAG(world, Depth2);
ecs_entity_t child_kinds[ChildCount + GrandChildCount];
for (int i = 0; i < ChildCount + GrandChildCount; i ++) {
child_kinds[i] = ecs_new(world);
}
int child_fragment_ids[ChildFragmentationCount];
for (int i = 0; i < ChildFragmentationCount; i ++) {
child_fragment_ids[i] = ecs_new(world);
}
ecs_query_t *q_move = ecs_query(world, {
.expr = "Position, Velocity",
.cache_kind = EcsQueryCacheAuto
});
ecs_query_t *q = ecs_query(world, {
.expr = "Position, Rotation, Transform, FlattenedSoA",
.group_by = Depth
});
ecs_time_t t; ecs_time_measure(&t);
ecs_table_t *table = ecs_table_find(world, (ecs_id_t[]){
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Children), ecs_id(FlattenedSoA), ecs_pair(Depth, Depth0)
}, 6);
ecs_table_t *child_table = ecs_table_find(world, (ecs_id_t[]){
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Parent), ecs_pair(Depth, Depth1)
}, 6);
ecs_table_t *grand_child_table = ecs_table_find(world, (ecs_id_t[]){
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Parent), ecs_pair(Depth, Depth2)
}, 6);
for (int i = 0; i < InstanceCount; i ++) {
ecs_entity_t inst = ecs_new_w_table(world, table);
ecs_set(world, inst, Position, {i, i, i});
ecs_set(world, inst, Rotation, {0, 0, 0});
ecs_set(world, inst, Velocity, {0, 0, 0});
Children *children = ecs_get_mut(world, inst, Children);
ecs_os_zeromem(children);
Children_reserve(children, ChildCount);
FlattenedSoA *f = ecs_get_mut(world, inst, FlattenedSoA);
ecs_os_zeromem(f);
FlattenedSoA_reserve(f, ChildCount);
for (int c = 0; c < ChildCount; c ++) {
ecs_entity_t child = ecs_new_w_table(world, child_table);
ecs_set(world, child, Parent, {inst});
ecs_set(world, child, Position, {c, c, c});
ecs_set(world, child, Rotation, {0, 0, 0});
ecs_set(world, child, Velocity, {0, 0, 0});
ecs_add_id(world, child, child_kinds[c]);
ecs_add_id(world, child, child_fragment_ids[c % ChildFragmentationCount]);
Children_append(children);
children->value[children->count - 1] = child;
FlattenedSoA_append(f);
f->p[f->count - 1] = (Position){i, i, i};
f->r[f->count - 1] = (Rotation){0, 0, 0};
if (c < ChildrenWithGrandChildren) {
Children *gchildren = ecs_ensure(world, child, Children);
ecs_os_zeromem(gchildren);
Children_reserve(gchildren, GrandChildCount);
for (int gc = 0; gc < GrandChildCount; gc ++) {
ecs_entity_t grandchild = ecs_new_w_table(world, grand_child_table);
ecs_set(world, child, Parent, {child});
ecs_set(world, grandchild, Position, {c, c, c});
ecs_set(world, grandchild, Rotation, {0, 0, 0});
ecs_set(world, grandchild, Velocity, {0, 0, 0});
ecs_add_id(world, grandchild, child_kinds[ChildCount + gc]);
Children_append(gchildren);
gchildren->value[gchildren->count - 1] = grandchild;
FlattenedSoA_append(f);
f->p[f->count - 1] = (Position){i, i, i};
f->r[f->count - 1] = (Rotation){0, 0, 0};
}
}
}
}
printf("create: %.3f\n", ecs_time_measure(&t));
for (int x = 0; x < QuerySampleCount; x ++) {
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 0);
Rotation *r = ecs_field(&it, Rotation, 1);
Transform *t = ecs_field(&it, Transform, 2);
FlattenedSoA *f = ecs_field(&it, FlattenedSoA, 3);
for (int i = 0; i < it.count; i ++) {
glm_translate_make(t[i].value, *(vec3*)&p[i]);
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0});
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0});
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0});
}
for (int i = 0; i < it.count; i ++) {
for (int c = 0; c < f->count; c ++) {
glm_translate_to(t[i].value, *(vec3*)&f[i].p[c], f[i].t[c].value);
glm_rotate(f[i].t[c].value, f[i].r[c].x, (vec3){1.0, 0.0, 0.0});
glm_rotate(f[i].t[c].value, f[i].r[c].y, (vec3){0.0, 1.0, 0.0});
glm_rotate(f[i].t[c].value, f[i].r[c].z, (vec3){0.0, 0.0, 1.0});
}
}
}
}
printf("transform: %.3f\n", ecs_time_measure(&t));
for (int x = 0; x < QuerySampleCount; x ++) {
ecs_iter_t it = ecs_query_iter(world, q_move);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 0);
Velocity *v = ecs_field(&it, Velocity, 1);
for (int i = 0; i < it.count; i ++) {
p[i].x += v[i].x;
p[i].y += v[i].y;
p[i].z += v[i].z;
}
}
}
printf("move: %.3f\n", ecs_time_measure(&t));
ecs_fini(world);
}
void child_tables_flattened_aos() {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Rotation);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Transform);
ECS_COMPONENT(world, Parent);
ECS_COMPONENT(world, Children);
ECS_COMPONENT(world, FlattenedAoS);
ECS_TAG(world, Depth);
ECS_TAG(world, Depth0);
ECS_TAG(world, Depth1);
ECS_TAG(world, Depth2);
ecs_entity_t child_kinds[ChildCount + GrandChildCount];
for (int i = 0; i < ChildCount + GrandChildCount; i ++) {
child_kinds[i] = ecs_new(world);
}
int child_fragment_ids[ChildFragmentationCount];
for (int i = 0; i < ChildFragmentationCount; i ++) {
child_fragment_ids[i] = ecs_new(world);
}
ecs_query_t *q_move = ecs_query(world, {
.expr = "Position, Velocity",
.cache_kind = EcsQueryCacheAuto
});
ecs_query_t *q = ecs_query(world, {
.expr = "Position, Rotation, Transform, FlattenedAoS",
.group_by = Depth
});
ecs_time_t t; ecs_time_measure(&t);
ecs_table_t *table = ecs_table_find(world, (ecs_id_t[]){
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Children), ecs_id(FlattenedAoS), ecs_pair(Depth, Depth0)
}, 6);
ecs_table_t *child_table = ecs_table_find(world, (ecs_id_t[]){
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Parent), ecs_id(Children), ecs_pair(Depth, Depth1)
}, 6);
ecs_table_t *grand_child_table = ecs_table_find(world, (ecs_id_t[]){
ecs_id(Position), ecs_id(Rotation), ecs_id(Velocity), ecs_id(Transform), ecs_id(Parent), ecs_pair(Depth, Depth2)
}, 6);
for (int i = 0; i < InstanceCount; i ++) {
ecs_entity_t inst = ecs_new_w_table(world, table);
ecs_set(world, inst, Position, {i, i, i});
ecs_set(world, inst, Rotation, {0, 0, 0});
ecs_set(world, inst, Velocity, {0, 0, 0});
ecs_add_pair(world, inst, Depth, Depth0);
Children *children = ecs_get_mut(world, inst, Children);
ecs_os_zeromem(children);
Children_reserve(children, ChildCount);
FlattenedAoS *f = ecs_get_mut(world, inst, FlattenedAoS);
ecs_os_zeromem(f);
FlattenedAoS_reserve(f, ChildCount);
for (int c = 0; c < ChildCount; c ++) {
ecs_entity_t child = ecs_new_w_table(world, child_table);
ecs_set(world, child, Parent, {inst});
ecs_set(world, child, Position, {c, c, c});
ecs_set(world, child, Rotation, {0, 0, 0});
ecs_set(world, child, Velocity, {0, 0, 0});
ecs_add_id(world, child, child_kinds[c]);
ecs_add_pair(world, child, Depth, Depth1);
ecs_add_id(world, child, child_fragment_ids[c % ChildFragmentationCount]);
Children_append(children);
children->value[children->count - 1] = child;
FlattenedAoS_append(f);
f->v[f->count - 1].p = (Position){i, i, i};
f->v[f->count - 1].r = (Rotation){0, 0, 0};
if (c < ChildrenWithGrandChildren) {
Children *gchildren = ecs_ensure(world, child, Children);
ecs_os_zeromem(gchildren);
Children_reserve(gchildren, GrandChildCount);
for (int gc = 0; gc < GrandChildCount; gc ++) {
ecs_entity_t grandchild = ecs_new_w_table(world, grand_child_table);
ecs_set(world, child, Parent, {child});
ecs_set(world, grandchild, Position, {c, c, c});
ecs_set(world, grandchild, Rotation, {0, 0, 0});
ecs_set(world, grandchild, Velocity, {0, 0, 0});
ecs_add_id(world, grandchild, child_kinds[ChildCount + gc]);
Children_append(gchildren);
gchildren->value[gchildren->count - 1] = grandchild;
FlattenedAoS_append(f);
f->v[f->count - 1].p = (Position){i, i, i};
f->v[f->count - 1].r = (Rotation){0, 0, 0};
}
}
}
}
printf("create: %.3f\n", ecs_time_measure(&t));
for (int x = 0; x < QuerySampleCount; x ++) {
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 0);
Rotation *r = ecs_field(&it, Rotation, 1);
Transform *t = ecs_field(&it, Transform, 2);
FlattenedAoS *f = ecs_field(&it, FlattenedAoS, 3);
for (int i = 0; i < it.count; i ++) {
glm_translate_make(t[i].value, *(vec3*)&p[i]);
glm_rotate(t[i].value, r[i].x, (vec3){1.0, 0.0, 0.0});
glm_rotate(t[i].value, r[i].y, (vec3){0.0, 1.0, 0.0});
glm_rotate(t[i].value, r[i].z, (vec3){0.0, 0.0, 1.0});
}
for (int i = 0; i < it.count; i ++) {
for (int c = 0; c < f->count; c ++) {
glm_translate_to(t[i].value, *(vec3*)&f[i].v[c].p, f[i].v[c].t.value);
glm_rotate(f[i].v[c].t.value, f[i].v[c].r.x, (vec3){1.0, 0.0, 0.0});
glm_rotate(f[i].v[c].t.value, f[i].v[c].r.y, (vec3){0.0, 1.0, 0.0});
glm_rotate(f[i].v[c].t.value, f[i].v[c].r.z, (vec3){0.0, 0.0, 1.0});
}
}
}
}
printf("transform: %.3f\n", ecs_time_measure(&t));
for (int x = 0; x < QuerySampleCount; x ++) {
ecs_iter_t it = ecs_query_iter(world, q_move);
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 0);
Velocity *v = ecs_field(&it, Velocity, 1);
for (int i = 0; i < it.count; i ++) {
p[i].x += v[i].x;
p[i].y += v[i].y;
p[i].z += v[i].z;
}
}
}
printf("move: %.3f\n", ecs_time_measure(&t));
ecs_fini(world);
}
int main(int argc, char *argv[]) {
printf("Instances: %d, Children: %d, ChildrenWithGrandChildren: %d, GrandChildren: %d, ChildTables: %d\n",
InstanceCount, ChildCount, ChildrenWithGrandChildren, GrandChildCount, ChildFragmentationCount);
printf("\nFragmenting:\n===\n");
fragmenting();
printf("\nChild tables (get_mut<Transform>()):\n===\n");
child_tables();
printf("\nChild tables (ref_get<Transform>()):\n===\n");
child_tables_w_ref();
printf("\nChild tables (flattened SoA transform):\n===\n");
child_tables_flattened_soa();
printf("\nChild tables (flattened AoS transform):\n===\n");
child_tables_flattened_aos();
}
// Instances: 20000, Children: 20, ChildrenWithGrandChildren: 10, GrandChildren: 2, ChildTables: 4
// Fragmenting:
// ===
// create: 0.586
// transform (bfs): 0.474
// transform (dfs): 2.914
// move: 0.157
// Child tables (get_mut<Transform>()):
// ===
// create: 0.102
// transform (bfs): 0.172
// transform (dfs): 0.316
// move: 0.004
// Child tables (ref_get<Transform>()):
// ===
// create: 0.119
// transform (bfs): 0.129
// transform (dfs): 0.359
// move: 0.004
// Child tables (flattened SoA transform):
// ===
// create: 0.115
// transform: 0.122
// move: 0.004
// Child tables (flattened AoS transform):
// ===
// create: 0.119
// transform: 0.110
// move: 0.004
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment