Files
PixelDefense/engine/libs/flecs/test/addons/src/MultiTaskThread.c

1385 lines
33 KiB
C

#include <addons.h>
static ECS_COMPONENT_DECLARE(Position);
static ECS_DECLARE(Tag);
void MultiTaskThread_setup(void) {
ecs_log_set_level(-3);
}
void MultiTaskThread_Progress(ecs_iter_t *it) {
Position *pos = ecs_field(it, Position, 1);
int row;
for (row = 0; row < it->count; row ++) {
Position *p = &pos[row];
p->x ++;
}
}
static
ecs_world_t* init_world(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT_DEFINE(world, Position);
ECS_SYSTEM(world, MultiTaskThread_Progress, EcsOnUpdate, Position);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = MultiTaskThread_Progress,
.multi_threaded = true
});
return world;
}
void MultiTaskThread_2_thread_10_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 10, THREADS = 2;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_2_thread_1_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 1, THREADS = 2;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_2_thread_2_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 2, THREADS = 2;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_2_thread_5_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 5, THREADS = 2;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_3_thread_10_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 10, THREADS = 3;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_3_thread_1_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 1, THREADS = 3;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_3_thread_2_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 2, THREADS = 3;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_3_thread_5_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 5, THREADS = 3;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_4_thread_10_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 10, THREADS = 4;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_4_thread_1_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 1, THREADS = 4;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_4_thread_2_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 2, THREADS = 4;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_4_thread_5_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 5, THREADS = 4;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_5_thread_10_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 10, THREADS = 5;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_5_thread_1_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 1, THREADS = 5;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_5_thread_2_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 2, THREADS = 5;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_5_thread_5_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 5, THREADS = 5;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_6_thread_10_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 10, THREADS = 6;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_6_thread_1_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 1, THREADS = 6;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_6_thread_2_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 2, THREADS = 6;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_6_thread_5_entity(void) {
ecs_world_t *world = init_world();
int i, ENTITIES = 5, THREADS = 6;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_2_thread_1_entity_instanced(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT_DEFINE(world, Position);
ecs_entity_t s = ecs_system_init(world, &(ecs_system_desc_t){
.entity = ecs_entity(world, {.add = {ecs_dependson(EcsOnUpdate)}}),
.callback = MultiTaskThread_Progress,
.query.filter = {
.expr = "Position",
.instanced = true
},
.multi_threaded = true
});
test_assert(s != 0);
int i, ENTITIES = 1, THREADS = 2;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_2_thread_5_entity_instanced(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT_DEFINE(world, Position);
ecs_entity_t s = ecs_system_init(world, &(ecs_system_desc_t){
.entity = ecs_entity(world, {.add = {ecs_dependson(EcsOnUpdate)}}),
.callback = MultiTaskThread_Progress,
.query.filter = {
.expr = "Position",
.instanced = true
},
.multi_threaded = true
});
test_assert(s != 0);
int i, ENTITIES = 5, THREADS = 2;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
void MultiTaskThread_2_thread_10_entity_instanced(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT_DEFINE(world, Position);
ecs_entity_t s = ecs_system_init(world, &(ecs_system_desc_t){
.entity = ecs_entity(world, {.add = {ecs_dependson(EcsOnUpdate)}}),
.callback = MultiTaskThread_Progress,
.query.filter = {
.expr = "Position",
.instanced = true
},
.multi_threaded = true
});
test_assert(s != 0);
int i, ENTITIES = 10, THREADS = 2;
ecs_entity_t *handles = ecs_os_alloca(sizeof(ecs_entity_t) * ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
handles[i] = ecs_new(world, Position);
ecs_set(world, handles[i], Position, {0});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 1);
}
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
test_int(ecs_get(world, handles[i], Position)->x, 2);
}
ecs_fini(world);
}
typedef struct Param {
ecs_entity_t entity;
int count;
} Param;
static
void TestSubset(ecs_iter_t *it) {
Param *param = it->param;
int i;
for (i = 0; i < it->count; i ++) {
test_assert(param->entity != it->entities[i]);
param->count ++;
}
}
static
void TestAll(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 1);
ecs_entity_t TestSubset = ecs_field_id(it, 2);
int i;
for (i = 0; i < it->count; i ++) {
Param param = {.entity = it->entities[i], 0};
ecs_run_w_filter(it->world, TestSubset, 1, it->frame_offset + i + 1, 0, &param);
p[i].x += param.count;
}
}
static
void test_combs_100_entity(int THREADS) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT_DEFINE(world, Position);
ECS_SYSTEM(world, TestSubset, 0, Position);
ECS_SYSTEM(world, TestAll, EcsOnUpdate, Position, TestSubset());
ecs_system_init(world, &(ecs_system_desc_t){
.entity = TestAll,
.multi_threaded = true
});
int i, ENTITIES = 100;
const ecs_entity_t *ids = ecs_bulk_new(world, Position, ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
ecs_set(world, ids[i], Position, {1, 2});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES; i ++) {
const Position *p = ecs_get(world, ids[i], Position);
test_int(p->x, ENTITIES - i);
}
ecs_fini(world);
}
void MultiTaskThread_2_thread_test_combs_100_entity_w_next_worker(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT_DEFINE(world, Position);
ECS_SYSTEM(world, TestSubset, 0, Position);
ecs_query_t *q = ecs_query_new(world, "Position, TestSubset()");
int i, ENTITIES = 100;
const ecs_entity_t *ids = ecs_bulk_new(world, Position, ENTITIES);
for (i = 0; i < ENTITIES; i ++) {
ecs_set(world, ids[i], Position, {1, 2});
}
ecs_iter_t it = ecs_query_iter(world, q);
ecs_iter_t wit = ecs_worker_iter(&it, 0, 2);
while (ecs_worker_next(&wit)) {
TestAll(&wit);
}
it = ecs_query_iter(world, q);
wit = ecs_worker_iter(&it, 1, 2);
while (ecs_worker_next(&wit)) {
TestAll(&wit);
}
for (i = 0; i < ENTITIES; i ++) {
const Position *p = ecs_get(world, ids[i], Position);
test_int(p->x, ENTITIES - i);
}
ecs_fini(world);
}
void MultiTaskThread_2_thread_test_combs_100_entity(void) {
test_combs_100_entity(2);
}
void MultiTaskThread_3_thread_test_combs_100_entity(void) {
test_combs_100_entity(3);
}
void MultiTaskThread_4_thread_test_combs_100_entity(void) {
test_combs_100_entity(4);
}
void MultiTaskThread_5_thread_test_combs_100_entity(void) {
test_combs_100_entity(5);
}
void MultiTaskThread_6_thread_test_combs_100_entity(void) {
test_combs_100_entity(6);
}
static
void test_combs_100_entity_2_types(int THREADS) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT_DEFINE(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_PREFAB(world, Type, Position, Velocity);
ECS_SYSTEM(world, TestSubset, 0, Position);
ECS_SYSTEM(world, TestAll, EcsOnUpdate, Position, TestSubset());
ecs_system_init(world, &(ecs_system_desc_t){
.entity = TestAll,
.multi_threaded = true
});
int i, ENTITIES = 100;
const ecs_entity_t *temp_ids_1 = ecs_bulk_new(world, Position, ENTITIES / 2);
ecs_entity_t ids_1[50];
memcpy(ids_1, temp_ids_1, sizeof(ecs_entity_t) * ENTITIES / 2);
const ecs_entity_t *ids_2 = bulk_new_w_type(world, Type, ENTITIES / 2);
for (i = 0; i < ENTITIES / 2; i ++) {
ecs_set(world, ids_1[i], Position, {1, 2});
ecs_set(world, ids_2[i], Position, {1, 2});
}
ecs_set_task_threads(world, THREADS);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES / 2; i ++) {
const Position *p = ecs_get(world, ids_1[i], Position);
test_int(p->x, ENTITIES - i);
p = ecs_get(world, ids_2[i], Position);
test_int(p->x, ENTITIES - (i + ENTITIES / 2));
}
ecs_fini(world);
}
void MultiTaskThread_2_thread_test_combs_100_entity_2_types(void) {
test_combs_100_entity_2_types(2);
}
void MultiTaskThread_3_thread_test_combs_100_entity_2_types(void) {
test_combs_100_entity_2_types(3);
}
void MultiTaskThread_4_thread_test_combs_100_entity_2_types(void) {
test_combs_100_entity_2_types(4);
}
void MultiTaskThread_5_thread_test_combs_100_entity_2_types(void) {
test_combs_100_entity_2_types(5);
}
void MultiTaskThread_6_thread_test_combs_100_entity_2_types(void) {
test_combs_100_entity_2_types(6);
}
void MultiTaskThread_change_thread_count(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT_DEFINE(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_PREFAB(world, Type, Position, Velocity);
ECS_SYSTEM(world, TestSubset, 0, Position);
ECS_SYSTEM(world, TestAll, EcsOnUpdate, Position, TestSubset());
ecs_system_init(world, &(ecs_system_desc_t){
.entity = TestAll,
.multi_threaded = true
});
int i, ENTITIES = 100;
const ecs_entity_t *temp_ids_1 = ecs_bulk_new(world, Position, ENTITIES / 2);
ecs_entity_t ids_1[50];
memcpy(ids_1, temp_ids_1, sizeof(ecs_entity_t) * ENTITIES / 2);
const ecs_entity_t *ids_2 = bulk_new_w_type(world, Type, ENTITIES / 2);
for (i = 0; i < ENTITIES / 2; i ++) {
ecs_set(world, ids_1[i], Position, {1, 2});
ecs_set(world, ids_2[i], Position, {1, 2});
}
ecs_set_task_threads(world, 2);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES / 2; i ++) {
Position *p = ecs_get_mut(world, ids_1[i], Position);
test_int(p->x, ENTITIES - i);
p->x = 1;
p = ecs_get_mut(world, ids_2[i], Position);
test_int(p->x, ENTITIES - (i + ENTITIES / 2));
p->x = 1;
}
ecs_set_task_threads(world, 3);
ecs_progress(world, 0);
for (i = 0; i < ENTITIES / 2; i ++) {
const Position *p = ecs_get(world, ids_1[i], Position);
test_int(p->x, ENTITIES - i);
p = ecs_get(world, ids_2[i], Position);
test_int(p->x, ENTITIES - (i + ENTITIES / 2));
}
ecs_fini(world);
}
static
void QuitSystem(ecs_iter_t *it) {
ecs_quit(it->world);
}
void MultiTaskThread_multithread_quit(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT_DEFINE(world, Position);
ECS_SYSTEM(world, QuitSystem, EcsOnUpdate, Position);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = QuitSystem,
.multi_threaded = true
});
ecs_bulk_new(world, Position, 100);
ecs_set_task_threads(world, 2);
test_assert( ecs_progress(world, 0) == 0);
ecs_fini(world);
}
static bool has_ran = false;
static
void MtTask(ecs_iter_t *it) {
has_ran = true;
}
void MultiTaskThread_schedule_w_tasks(void) {
ecs_world_t *world = ecs_init();
ECS_SYSTEM(world, MtTask, EcsOnUpdate, 0);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = MtTask,
.multi_threaded = true
});
ecs_set_task_threads(world, 2);
test_assert( ecs_progress(world, 0) != 0);
test_assert( has_ran == true);
ecs_fini(world);
}
static
void ReactiveDummySystem(ecs_iter_t * it) {
has_ran = true;
}
static
void PeriodicDummySystem(ecs_iter_t * it) {
ecs_id_t ecs_id(Position) = ecs_field_id(it, 1);
int i;
for (i = 0; i < it->count; i++ ) {
ecs_set(it->world, it->entities[i], Position, {0});
}
}
void MultiTaskThread_reactive_system(void) {
ecs_world_t * world = ecs_init();
ECS_COMPONENT_DEFINE(world, Position);
ECS_SYSTEM(world, PeriodicDummySystem, EcsOnUpdate, Position);
ECS_OBSERVER(world, ReactiveDummySystem, EcsOnSet, Position);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = PeriodicDummySystem,
.multi_threaded = true
});
ecs_bulk_new(world, Position, 2);
ecs_set_task_threads(world, 2);
test_assert(has_ran == false);
ecs_progress(world, 0);
test_assert(has_ran == true);
ecs_fini(world);
}
void MultiTaskThread_fini_after_set_threads(void) {
ecs_world_t * world = ecs_init();
ecs_set_task_threads(world, 2);
ecs_fini(world);
// Make sure code doesn't crash
test_assert(true);
}
static
void SingleThreadedSystem(ecs_iter_t * it) {
Position *p = ecs_field(it, Position, 1);
int i;
for (i = 0; i < it->count; i++ ) {
p[i].x ++;
p[i].y ++;
}
}
void MultiTaskThread_2_threads_single_threaded_system(void) {
ecs_world_t * world = ecs_init();
ECS_COMPONENT_DEFINE(world, Position);
ECS_SYSTEM(world, SingleThreadedSystem, EcsOnUpdate, Position);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = SingleThreadedSystem,
.multi_threaded = false
});
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(world, 0, Position, {20, 30});
ecs_set_task_threads(world, 2);
ecs_progress(world, 0);
const Position *p = ecs_get(world, e1, Position);
test_assert(p != NULL);
test_int(p->x, 11);
test_int(p->y, 21);
p = ecs_get(world, e2, Position);
test_assert(p != NULL);
test_int(p->x, 21);
test_int(p->y, 31);
ecs_fini(world);
}
static int create_query_invoked = 0;
static
void CreateQuery(ecs_iter_t *it) {
ecs_query_new(it->world, "0");
create_query_invoked ++;
}
void MultiTaskThread_no_staging_w_multithread(void) {
for (int i = 0; i < 10; i ++) {
ecs_world_t *world = ecs_init();
ecs_set_task_threads(world, 32);
ecs_system_init(world, &(ecs_system_desc_t){
.callback = CreateQuery,
.no_readonly = true,
.entity = ecs_entity(world, {.add = {ecs_dependson(EcsOnUpdate)}})
});
create_query_invoked = 0;
ecs_progress(world, 0);
test_int(create_query_invoked, 1);
ecs_fini(world);
}
test_assert(true);
}
void MultiTaskThread_multithread_w_monitor_addon(void) {
ecs_world_t *world = ecs_init();
ECS_IMPORT(world, FlecsMonitor);
ecs_set_task_threads(world, 4);
ecs_progress(world, 0);
ecs_fini(world);
/* Make sure monitor could be run in multithreaded mode */
test_assert(true);
}
static int system_ctx = 0;
static
void System_w_ctx(ecs_iter_t *it) {
test_assert(it->ctx == &system_ctx);
test_assert(it->system != 0);
test_assert(it->delta_time != 0);
system_ctx ++;
}
static
void System_run_w_ctx(ecs_iter_t *it) {
System_w_ctx(it);
ecs_iter_fini(it);
}
static
void System_w_binding_ctx(ecs_iter_t *it) {
test_assert(it->binding_ctx == &system_ctx);
test_assert(it->system != 0);
test_assert(it->delta_time != 0);
system_ctx ++;
}
static
void System_run_w_binding_ctx(ecs_iter_t *it) {
System_w_binding_ctx(it);
ecs_iter_fini(it);
}
void MultiTaskThread_get_ctx(void) {
ecs_world_t *world = ecs_init();
ecs_set_task_threads(world, 2);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = ecs_entity(world, { .add = { ecs_dependson(EcsOnUpdate) } }),
.callback = System_w_ctx,
.multi_threaded = true,
.ctx = &system_ctx
});
ecs_progress(world, 0);
test_assert(system_ctx != 0);
ecs_fini(world);
}
void MultiTaskThread_get_binding_ctx(void) {
ecs_world_t *world = ecs_init();
ecs_set_task_threads(world, 2);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = ecs_entity(world, { .add = { ecs_dependson(EcsOnUpdate) } }),
.callback = System_w_binding_ctx,
.multi_threaded = true,
.binding_ctx = &system_ctx
});
ecs_progress(world, 0);
test_assert(system_ctx != 0);
ecs_fini(world);
}
void MultiTaskThread_get_ctx_w_run(void) {
ecs_world_t *world = ecs_init();
ecs_set_task_threads(world, 2);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = ecs_entity(world, { .add = { ecs_dependson(EcsOnUpdate) } }),
.run = System_run_w_ctx,
.multi_threaded = true,
.ctx = &system_ctx
});
ecs_progress(world, 0);
test_assert(system_ctx != 0);
ecs_fini(world);
}
void MultiTaskThread_get_binding_ctx_w_run(void) {
ecs_world_t *world = ecs_init();
ecs_set_task_threads(world, 2);
ecs_system_init(world, &(ecs_system_desc_t){
.entity = ecs_entity(world, { .add = { ecs_dependson(EcsOnUpdate) } }),
.run = System_run_w_binding_ctx,
.multi_threaded = true,
.binding_ctx = &system_ctx
});
ecs_progress(world, 0);
test_assert(system_ctx != 0);
ecs_fini(world);
}
void MultiTaskThread_sys(ecs_iter_t *it) { }
void MultiTaskThread_sys_bulk_init(ecs_iter_t *it) {
ecs_bulk_init(it->world, &(ecs_bulk_desc_t){
.count = 10,
.ids = {Tag}
});
}
void MultiTaskThread_bulk_new_in_no_readonly_w_multithread(void) {
ecs_world_t *world = ecs_init();
ECS_TAG_DEFINE(world, Tag);
ecs_system(world, {
.entity = ecs_entity(world, { .add = { ecs_dependson(EcsOnUpdate) }}),
.no_readonly = true,
.callback = MultiTaskThread_sys_bulk_init
});
ecs_system(world, {
.entity = ecs_entity(world, { .add = { ecs_dependson(EcsOnUpdate) }}),
.multi_threaded = true,
.callback = MultiTaskThread_sys
});
ecs_set_task_threads(world, 80);
for (int i = 0; i < 100; i ++) {
ecs_progress(world, 0);
}
test_int(ecs_count(world, Tag), 100 * 10);
ecs_fini(world);
}
void MultiTaskThread_sys_bulk_init_2(ecs_iter_t *it) {
ecs_bulk_init(it->world, &(ecs_bulk_desc_t){
.count = 1,
.ids = {ecs_id(Position)}
});
ecs_iter_t qit = ecs_query_iter(it->world, it->ctx);
ecs_iter_fini(&qit);
}
void MultiTaskThread_bulk_new_in_no_readonly_w_multithread_2(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT_DEFINE(world, Position);
ecs_set_task_threads(world, 64);
ecs_system(world, {
.entity = ecs_entity(world, {
.add = { ecs_dependson(EcsOnUpdate) }
}),
.query.filter.terms = {{ ecs_id(Position) }},
.callback = MultiTaskThread_sys
});
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{ ecs_id(Position) }}
});
ecs_system(world, {
.entity = ecs_entity(world, {
.add = { ecs_dependson(EcsOnUpdate) }
}),
.callback = MultiTaskThread_sys_bulk_init_2,
.no_readonly = true,
.ctx = q
});
ecs_system(world, {
.entity = ecs_entity(world, {
.add = { ecs_dependson(EcsOnUpdate) }
}),
.callback = MultiTaskThread_sys
});
ecs_progress(world, 0);
test_int(ecs_count(world, Position), 1);
ecs_fini(world);
}
static ecs_os_thread_id_t main_thread;
static int invoked_count = 0;
static int invoked_main_count = 0;
static void dummy(ecs_iter_t *it) {
int stage_id = ecs_get_stage_id(it->world);
if (stage_id == 0) {
test_assert(main_thread == ecs_os_thread_self());
ecs_os_ainc(&invoked_main_count);
} else {
test_assert(main_thread != ecs_os_thread_self());
}
ecs_os_ainc(&invoked_count);
}
void MultiTaskThread_run_first_worker_on_main(void) {
ecs_world_t *world = ecs_init();
ecs_system(world, {
.entity = ecs_entity(world, { .add = { ecs_dependson(EcsOnUpdate) }}),
.multi_threaded = true,
.callback = dummy
});
ecs_set_task_threads(world, 3);
main_thread = ecs_os_thread_self();
ecs_progress(world, 0);
test_int(invoked_count, 3);
test_int(invoked_main_count, 1);
ecs_fini(world);
}
void MultiTaskThread_run_single_thread_on_main(void) {
ecs_world_t *world = ecs_init();
ecs_system(world, {
.entity = ecs_entity(world, { .add = { ecs_dependson(EcsOnUpdate) }}),
.multi_threaded = false,
.callback = dummy
});
ecs_set_task_threads(world, 3);
main_thread = ecs_os_thread_self();
ecs_progress(world, 0);
test_int(invoked_count, 1);
test_int(invoked_main_count, 1);
ecs_fini(world);
}