From d99efe2249471f046783a431e27459f3f7052019 Mon Sep 17 00:00:00 2001 From: Sander Mertens Date: Tue, 14 Nov 2023 09:54:34 -0800 Subject: [PATCH] Reduce branching in command batching code --- flecs.c | 193 ++++++++++++++++-------------------------- src/entity.c | 1 + src/stage.c | 194 ++++++++++++++++--------------------------- test/api/src/Event.c | 6 +- 4 files changed, 150 insertions(+), 244 deletions(-) diff --git a/flecs.c b/flecs.c index 59d213e858..08c909b1bc 100644 --- a/flecs.c +++ b/flecs.c @@ -8154,6 +8154,7 @@ bool flecs_defer_end( ecs_stage_t *dst_stage = flecs_stage_from_world(&world); ecs_commands_t *commands = stage->cmd; ecs_vec_t *queue = &commands->queue; + if (ecs_vec_count(queue)) { ecs_cmd_t *cmds = ecs_vec_first(queue); int32_t i, count = ecs_vec_count(queue); @@ -20479,72 +20480,54 @@ int32_t flecs_relation_depth( static -ecs_cmd_t* flecs_cmd_alloc( +ecs_cmd_t* flecs_cmd_new( ecs_stage_t *stage) { ecs_cmd_t *cmd = ecs_vec_append_t(&stage->allocator, &stage->cmd->queue, ecs_cmd_t); - ecs_os_zeromem(cmd); + cmd->is._1.value = NULL; + cmd->next_for_entity = 0; + cmd->entry = NULL; return cmd; } static -ecs_cmd_t* flecs_cmd_new( +ecs_cmd_t* flecs_cmd_new_batched( ecs_stage_t *stage, - ecs_entity_t e, - bool is_delete, - bool can_batch) + ecs_entity_t e) { - if (e) { - ecs_vec_t *cmds = &stage->cmd->queue; - ecs_cmd_entry_t *first_entry = NULL; - ecs_cmd_entry_t *entry = flecs_sparse_try_t( - &stage->cmd->entries, ecs_cmd_entry_t, e); + ecs_vec_t *cmds = &stage->cmd->queue; + ecs_cmd_entry_t *entry = flecs_sparse_get_any_t( + &stage->cmd->entries, ecs_cmd_entry_t, e); - int32_t cur = ecs_vec_count(cmds); - if (entry) { - if (entry->first == -1) { - /* Existing but invalidated entry */ - entry->first = cur; - first_entry = entry; - } else { - int32_t last = entry->last; - if (entry->last == -1) { - /* Entity was deleted, don't insert command */ - return NULL; - } - - if (can_batch) { - ecs_cmd_t *arr = ecs_vec_first_t(cmds, ecs_cmd_t); - ecs_assert(arr[last].entity == e, ECS_INTERNAL_ERROR, NULL); - ecs_cmd_t *last_op = &arr[last]; - last_op->next_for_entity = cur; - if (last == entry->first) { - /* Flip sign bit so flush logic can tell which command - * is the first for an entity */ - last_op->next_for_entity *= -1; - } - } - } - } else if (can_batch || is_delete) { - first_entry = entry = flecs_sparse_ensure_fast_t( - &stage->cmd->entries, ecs_cmd_entry_t, e); + int32_t cur = ecs_vec_count(cmds); + ecs_cmd_t *cmd = flecs_cmd_new(stage); + if (entry) { + if (entry->first == -1) { + /* Existing but invalidated entry */ entry->first = cur; + cmd->entry = entry; + } else { + int32_t last = entry->last; + ecs_cmd_t *arr = ecs_vec_first_t(cmds, ecs_cmd_t); + ecs_assert(arr[last].entity == e, ECS_INTERNAL_ERROR, NULL); + ecs_cmd_t *last_op = &arr[last]; + last_op->next_for_entity = cur; + if (last == entry->first) { + /* Flip sign bit so flush logic can tell which command + * is the first for an entity */ + last_op->next_for_entity *= -1; + } } - if (can_batch) { - entry->last = cur; - } - if (is_delete) { - /* Prevent insertion of more commands for entity */ - entry->last = -1; - } - - ecs_cmd_t *cmd = flecs_cmd_alloc(stage); - cmd->entry = first_entry; - return cmd; + } else { + cmd->entry = entry = flecs_sparse_ensure_fast_t( + &stage->cmd->entries, ecs_cmd_entry_t, e); + entry->first = cur; } - return flecs_cmd_alloc(stage); + entry->last = cur; + + return cmd; } static @@ -20646,7 +20629,7 @@ bool flecs_defer_modified( ecs_id_t id) { if (flecs_defer_cmd(stage)) { - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, false, true); + ecs_cmd_t *cmd = flecs_cmd_new_batched(stage, entity); if (cmd) { cmd->kind = EcsCmdModified; cmd->id = id; @@ -20664,13 +20647,11 @@ bool flecs_defer_clone( bool clone_value) { if (flecs_defer_cmd(stage)) { - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, false, false); - if (cmd) { - cmd->kind = EcsCmdClone; - cmd->id = src; - cmd->entity = entity; - cmd->is._1.clone_value = clone_value; - } + ecs_cmd_t *cmd = flecs_cmd_new(stage); + cmd->kind = EcsCmdClone; + cmd->id = src; + cmd->entity = entity; + cmd->is._1.clone_value = clone_value; return true; } return false; @@ -20683,13 +20664,11 @@ bool flecs_defer_path( const char *name) { if (stage->defer > 0) { - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, false, false); - if (cmd) { - cmd->kind = EcsCmdPath; - cmd->entity = entity; - cmd->id = parent; - cmd->is._1.value = ecs_os_strdup(name); - } + ecs_cmd_t *cmd = flecs_cmd_new(stage); + cmd->kind = EcsCmdPath; + cmd->entity = entity; + cmd->id = parent; + cmd->is._1.value = ecs_os_strdup(name); return true; } return false; @@ -20700,11 +20679,9 @@ bool flecs_defer_delete( ecs_entity_t entity) { if (flecs_defer_cmd(stage)) { - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, true, false); - if (cmd) { - cmd->kind = EcsCmdDelete; - cmd->entity = entity; - } + ecs_cmd_t *cmd = flecs_cmd_new(stage); + cmd->kind = EcsCmdDelete; + cmd->entity = entity; return true; } return false; @@ -20715,11 +20692,9 @@ bool flecs_defer_clear( ecs_entity_t entity) { if (flecs_defer_cmd(stage)) { - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, false, true); - if (cmd) { - cmd->kind = EcsCmdClear; - cmd->entity = entity; - } + ecs_cmd_t *cmd = flecs_cmd_new_batched(stage, entity); + cmd->kind = EcsCmdClear; + cmd->entity = entity; return true; } return false; @@ -20731,7 +20706,7 @@ bool flecs_defer_on_delete_action( ecs_entity_t action) { if (flecs_defer_cmd(stage)) { - ecs_cmd_t *cmd = flecs_cmd_alloc(stage); + ecs_cmd_t *cmd = flecs_cmd_new(stage); cmd->kind = EcsCmdOnDeleteAction; cmd->id = id; cmd->entity = action; @@ -20747,12 +20722,10 @@ bool flecs_defer_enable( bool enable) { if (flecs_defer_cmd(stage)) { - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, false, false); - if (cmd) { - cmd->kind = enable ? EcsCmdEnable : EcsCmdDisable; - cmd->entity = entity; - cmd->id = id; - } + ecs_cmd_t *cmd = flecs_cmd_new(stage); + cmd->kind = enable ? EcsCmdEnable : EcsCmdDisable; + cmd->entity = entity; + cmd->id = id; return true; } return false; @@ -20777,14 +20750,12 @@ bool flecs_defer_bulk_new( *ids_out = ids; /* Store data in op */ - ecs_cmd_t *cmd = flecs_cmd_alloc(stage); - if (cmd) { - cmd->kind = EcsCmdBulkNew; - cmd->id = id; - cmd->is._n.entities = ids; - cmd->is._n.count = count; - } - + ecs_cmd_t *cmd = flecs_cmd_new(stage); + cmd->kind = EcsCmdBulkNew; + cmd->id = id; + cmd->is._n.entities = ids; + cmd->is._n.count = count; + cmd->entity = 0; return true; } return false; @@ -20797,12 +20768,10 @@ bool flecs_defer_add( { if (flecs_defer_cmd(stage)) { ecs_assert(id != 0, ECS_INTERNAL_ERROR, NULL); - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, false, true); - if (cmd) { - cmd->kind = EcsCmdAdd; - cmd->id = id; - cmd->entity = entity; - } + ecs_cmd_t *cmd = flecs_cmd_new_batched(stage, entity); + cmd->kind = EcsCmdAdd; + cmd->id = id; + cmd->entity = entity; return true; } return false; @@ -20815,12 +20784,10 @@ bool flecs_defer_remove( { if (flecs_defer_cmd(stage)) { ecs_assert(id != 0, ECS_INTERNAL_ERROR, NULL); - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, false, true); - if (cmd) { - cmd->kind = EcsCmdRemove; - cmd->id = id; - cmd->entity = entity; - } + ecs_cmd_t *cmd = flecs_cmd_new_batched(stage, entity); + cmd->kind = EcsCmdRemove; + cmd->id = id; + cmd->entity = entity; return true; } return false; @@ -20836,17 +20803,7 @@ void* flecs_defer_set( void *value, bool need_value) { - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, false, true); - if (!cmd) { - if (need_value) { - /* Entity is deleted by a previous command, but we still need to - * return a temporary storage to the application. */ - cmd_kind = EcsCmdSkip; - } else { - /* No value needs to be returned, we can drop the command */ - return NULL; - } - } + ecs_cmd_t *cmd = flecs_cmd_new_batched(stage, entity); /* Find type info for id */ const ecs_type_info_t *ti = NULL; @@ -20977,7 +20934,7 @@ void* flecs_defer_set( * already deleted. */ return cmd_value; } - cmd = flecs_cmd_alloc(stage); + cmd = flecs_cmd_new(stage); } if (!existing) { @@ -21011,11 +20968,7 @@ void flecs_enqueue( ecs_stage_t *stage, ecs_event_desc_t *desc) { - ecs_cmd_t *cmd = flecs_cmd_new(stage, desc->entity, false, false); - if (!cmd) { - return; /* Entity was deleted */ - } - + ecs_cmd_t *cmd = flecs_cmd_new(stage); cmd->kind = EcsCmdEvent; cmd->entity = desc->entity; diff --git a/src/entity.c b/src/entity.c index bdf4abbca1..5a9c9de460 100644 --- a/src/entity.c +++ b/src/entity.c @@ -4768,6 +4768,7 @@ bool flecs_defer_end( ecs_stage_t *dst_stage = flecs_stage_from_world(&world); ecs_commands_t *commands = stage->cmd; ecs_vec_t *queue = &commands->queue; + if (ecs_vec_count(queue)) { ecs_cmd_t *cmds = ecs_vec_first(queue); int32_t i, count = ecs_vec_count(queue); diff --git a/src/stage.c b/src/stage.c index c418f09eda..b6efff6b57 100644 --- a/src/stage.c +++ b/src/stage.c @@ -18,72 +18,54 @@ #include "private_api.h" static -ecs_cmd_t* flecs_cmd_alloc( +ecs_cmd_t* flecs_cmd_new( ecs_stage_t *stage) { ecs_cmd_t *cmd = ecs_vec_append_t(&stage->allocator, &stage->cmd->queue, ecs_cmd_t); - ecs_os_zeromem(cmd); + cmd->is._1.value = NULL; + cmd->next_for_entity = 0; + cmd->entry = NULL; return cmd; } static -ecs_cmd_t* flecs_cmd_new( +ecs_cmd_t* flecs_cmd_new_batched( ecs_stage_t *stage, - ecs_entity_t e, - bool is_delete, - bool can_batch) -{ - if (e) { - ecs_vec_t *cmds = &stage->cmd->queue; - ecs_cmd_entry_t *first_entry = NULL; - ecs_cmd_entry_t *entry = flecs_sparse_try_t( - &stage->cmd->entries, ecs_cmd_entry_t, e); - - int32_t cur = ecs_vec_count(cmds); - if (entry) { - if (entry->first == -1) { - /* Existing but invalidated entry */ - entry->first = cur; - first_entry = entry; - } else { - int32_t last = entry->last; - if (entry->last == -1) { - /* Entity was deleted, don't insert command */ - return NULL; - } + ecs_entity_t e) +{ + ecs_vec_t *cmds = &stage->cmd->queue; + ecs_cmd_entry_t *entry = flecs_sparse_get_any_t( + &stage->cmd->entries, ecs_cmd_entry_t, e); - if (can_batch) { - ecs_cmd_t *arr = ecs_vec_first_t(cmds, ecs_cmd_t); - ecs_assert(arr[last].entity == e, ECS_INTERNAL_ERROR, NULL); - ecs_cmd_t *last_op = &arr[last]; - last_op->next_for_entity = cur; - if (last == entry->first) { - /* Flip sign bit so flush logic can tell which command - * is the first for an entity */ - last_op->next_for_entity *= -1; - } - } - } - } else if (can_batch || is_delete) { - first_entry = entry = flecs_sparse_ensure_fast_t( - &stage->cmd->entries, ecs_cmd_entry_t, e); + int32_t cur = ecs_vec_count(cmds); + ecs_cmd_t *cmd = flecs_cmd_new(stage); + if (entry) { + if (entry->first == -1) { + /* Existing but invalidated entry */ entry->first = cur; + cmd->entry = entry; + } else { + int32_t last = entry->last; + ecs_cmd_t *arr = ecs_vec_first_t(cmds, ecs_cmd_t); + ecs_assert(arr[last].entity == e, ECS_INTERNAL_ERROR, NULL); + ecs_cmd_t *last_op = &arr[last]; + last_op->next_for_entity = cur; + if (last == entry->first) { + /* Flip sign bit so flush logic can tell which command + * is the first for an entity */ + last_op->next_for_entity *= -1; + } } - if (can_batch) { - entry->last = cur; - } - if (is_delete) { - /* Prevent insertion of more commands for entity */ - entry->last = -1; - } - - ecs_cmd_t *cmd = flecs_cmd_alloc(stage); - cmd->entry = first_entry; - return cmd; + } else { + cmd->entry = entry = flecs_sparse_ensure_fast_t( + &stage->cmd->entries, ecs_cmd_entry_t, e); + entry->first = cur; } - return flecs_cmd_alloc(stage); + entry->last = cur; + + return cmd; } static @@ -185,7 +167,7 @@ bool flecs_defer_modified( ecs_id_t id) { if (flecs_defer_cmd(stage)) { - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, false, true); + ecs_cmd_t *cmd = flecs_cmd_new_batched(stage, entity); if (cmd) { cmd->kind = EcsCmdModified; cmd->id = id; @@ -203,13 +185,11 @@ bool flecs_defer_clone( bool clone_value) { if (flecs_defer_cmd(stage)) { - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, false, false); - if (cmd) { - cmd->kind = EcsCmdClone; - cmd->id = src; - cmd->entity = entity; - cmd->is._1.clone_value = clone_value; - } + ecs_cmd_t *cmd = flecs_cmd_new(stage); + cmd->kind = EcsCmdClone; + cmd->id = src; + cmd->entity = entity; + cmd->is._1.clone_value = clone_value; return true; } return false; @@ -222,13 +202,11 @@ bool flecs_defer_path( const char *name) { if (stage->defer > 0) { - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, false, false); - if (cmd) { - cmd->kind = EcsCmdPath; - cmd->entity = entity; - cmd->id = parent; - cmd->is._1.value = ecs_os_strdup(name); - } + ecs_cmd_t *cmd = flecs_cmd_new(stage); + cmd->kind = EcsCmdPath; + cmd->entity = entity; + cmd->id = parent; + cmd->is._1.value = ecs_os_strdup(name); return true; } return false; @@ -239,11 +217,9 @@ bool flecs_defer_delete( ecs_entity_t entity) { if (flecs_defer_cmd(stage)) { - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, true, false); - if (cmd) { - cmd->kind = EcsCmdDelete; - cmd->entity = entity; - } + ecs_cmd_t *cmd = flecs_cmd_new(stage); + cmd->kind = EcsCmdDelete; + cmd->entity = entity; return true; } return false; @@ -254,11 +230,9 @@ bool flecs_defer_clear( ecs_entity_t entity) { if (flecs_defer_cmd(stage)) { - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, false, true); - if (cmd) { - cmd->kind = EcsCmdClear; - cmd->entity = entity; - } + ecs_cmd_t *cmd = flecs_cmd_new_batched(stage, entity); + cmd->kind = EcsCmdClear; + cmd->entity = entity; return true; } return false; @@ -270,7 +244,7 @@ bool flecs_defer_on_delete_action( ecs_entity_t action) { if (flecs_defer_cmd(stage)) { - ecs_cmd_t *cmd = flecs_cmd_alloc(stage); + ecs_cmd_t *cmd = flecs_cmd_new(stage); cmd->kind = EcsCmdOnDeleteAction; cmd->id = id; cmd->entity = action; @@ -286,12 +260,10 @@ bool flecs_defer_enable( bool enable) { if (flecs_defer_cmd(stage)) { - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, false, false); - if (cmd) { - cmd->kind = enable ? EcsCmdEnable : EcsCmdDisable; - cmd->entity = entity; - cmd->id = id; - } + ecs_cmd_t *cmd = flecs_cmd_new(stage); + cmd->kind = enable ? EcsCmdEnable : EcsCmdDisable; + cmd->entity = entity; + cmd->id = id; return true; } return false; @@ -316,14 +288,12 @@ bool flecs_defer_bulk_new( *ids_out = ids; /* Store data in op */ - ecs_cmd_t *cmd = flecs_cmd_alloc(stage); - if (cmd) { - cmd->kind = EcsCmdBulkNew; - cmd->id = id; - cmd->is._n.entities = ids; - cmd->is._n.count = count; - } - + ecs_cmd_t *cmd = flecs_cmd_new(stage); + cmd->kind = EcsCmdBulkNew; + cmd->id = id; + cmd->is._n.entities = ids; + cmd->is._n.count = count; + cmd->entity = 0; return true; } return false; @@ -336,12 +306,10 @@ bool flecs_defer_add( { if (flecs_defer_cmd(stage)) { ecs_assert(id != 0, ECS_INTERNAL_ERROR, NULL); - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, false, true); - if (cmd) { - cmd->kind = EcsCmdAdd; - cmd->id = id; - cmd->entity = entity; - } + ecs_cmd_t *cmd = flecs_cmd_new_batched(stage, entity); + cmd->kind = EcsCmdAdd; + cmd->id = id; + cmd->entity = entity; return true; } return false; @@ -354,12 +322,10 @@ bool flecs_defer_remove( { if (flecs_defer_cmd(stage)) { ecs_assert(id != 0, ECS_INTERNAL_ERROR, NULL); - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, false, true); - if (cmd) { - cmd->kind = EcsCmdRemove; - cmd->id = id; - cmd->entity = entity; - } + ecs_cmd_t *cmd = flecs_cmd_new_batched(stage, entity); + cmd->kind = EcsCmdRemove; + cmd->id = id; + cmd->entity = entity; return true; } return false; @@ -375,17 +341,7 @@ void* flecs_defer_set( void *value, bool need_value) { - ecs_cmd_t *cmd = flecs_cmd_new(stage, entity, false, true); - if (!cmd) { - if (need_value) { - /* Entity is deleted by a previous command, but we still need to - * return a temporary storage to the application. */ - cmd_kind = EcsCmdSkip; - } else { - /* No value needs to be returned, we can drop the command */ - return NULL; - } - } + ecs_cmd_t *cmd = flecs_cmd_new_batched(stage, entity); /* Find type info for id */ const ecs_type_info_t *ti = NULL; @@ -516,7 +472,7 @@ void* flecs_defer_set( * already deleted. */ return cmd_value; } - cmd = flecs_cmd_alloc(stage); + cmd = flecs_cmd_new(stage); } if (!existing) { @@ -550,11 +506,7 @@ void flecs_enqueue( ecs_stage_t *stage, ecs_event_desc_t *desc) { - ecs_cmd_t *cmd = flecs_cmd_new(stage, desc->entity, false, false); - if (!cmd) { - return; /* Entity was deleted */ - } - + ecs_cmd_t *cmd = flecs_cmd_new(stage); cmd->kind = EcsCmdEvent; cmd->entity = desc->entity; diff --git a/test/api/src/Event.c b/test/api/src/Event.c index da36c9f6f8..661d098bc0 100644 --- a/test/api/src/Event.c +++ b/test/api/src/Event.c @@ -1052,7 +1052,7 @@ void Event_enqueue_event_not_alive_w_data_move(void) { ecs_defer_end(world); test_int(ctx.invoked, 0); - test_int(dtor_position, 0); /* event wasn't enqueued */ + test_int(dtor_position, 1); ecs_fini(world); } @@ -1096,8 +1096,8 @@ void Event_enqueue_event_not_alive_w_data_copy(void) { ecs_defer_end(world); test_int(ctx.invoked, 0); - test_int(copy_position, 0); /* event wasn't enqueued */ - test_int(dtor_position, 0); /* event wasn't enqueued */ + test_int(copy_position, 1); + test_int(dtor_position, 1); ecs_fini(world); }