From 27976629bc19a9b5f7492c84905c2846303ee5ef Mon Sep 17 00:00:00 2001 From: Sander Mertens Date: Fri, 18 Mar 2022 16:17:51 -0700 Subject: [PATCH] #680 remove type info lookups from table creation --- flecs.c | 143 ++++++++++++++++------------ flecs.h | 1 + include/flecs/private/api_defines.h | 1 + src/private_api.h | 6 ++ src/private_types.h | 3 + src/table.c | 71 +++++--------- src/table_graph.c | 41 ++++---- src/world.c | 22 ++++- 8 files changed, 162 insertions(+), 126 deletions(-) diff --git a/flecs.c b/flecs.c index 576bd6ead..070c5d469 100644 --- a/flecs.c +++ b/flecs.c @@ -778,6 +778,9 @@ struct ecs_id_record_t { /* Name lookup index (currently only used for ChildOf pairs) */ ecs_hashmap_t *name_index; + + /* Cached pointer to type info for id */ + const ecs_type_info_t *type_info; }; typedef struct ecs_store_t { @@ -1394,6 +1397,12 @@ ecs_id_record_t* flecs_ensure_id_record( ecs_world_t *world, ecs_id_t id); +void flecs_register_for_id_record( + ecs_world_t *world, + ecs_id_t id, + const ecs_table_t *table, + ecs_table_record_t *tr); + ecs_id_record_t* flecs_get_id_record( const ecs_world_t *world, ecs_id_t id); @@ -2306,29 +2315,27 @@ void init_storage_table( if (table->storage_table) { return; } - + int32_t i, count = ecs_vector_count(table->type); ecs_id_t *ids = ecs_vector_first(table->type, ecs_id_t); + ecs_table_record_t *records = table->records; ecs_ids_t storage_ids = { .array = ecs_os_alloca_n(ecs_id_t, count) }; for (i = 0; i < count; i ++) { - ecs_id_t id = ids[i]; - - if ((id == ecs_id(EcsComponent)) || - (ECS_PAIR_FIRST(id) == ecs_id(EcsIdentifier))) - { - storage_ids.array[storage_ids.count ++] = id; - continue; - } + ecs_table_record_t *tr = &records[i]; + ecs_id_record_t *idr = (ecs_id_record_t*)tr->hdr.cache; + ecs_assert(idr->flags & ECS_TYPE_INFO_INITIALIZED, + ECS_INTERNAL_ERROR, NULL); - const EcsComponent *comp = flecs_component_from_id(world, id); - if (!comp || !comp->size) { - continue; + if (idr->type_info == NULL) { + ecs_assert(ecs_get_typeid(world, ids[i]) == 0, + ECS_INTERNAL_ERROR, NULL); + continue; /* not a component */ } - storage_ids.array[storage_ids.count ++] = id; + storage_ids.array[storage_ids.count ++] = ids[i]; } if (storage_ids.count && storage_ids.count != count) { @@ -2374,7 +2381,6 @@ ecs_flags32_t type_info_flags( static void init_type_info( - ecs_world_t *world, ecs_table_t *table) { ecs_table_t *storage_table = table->storage_table; @@ -2390,20 +2396,18 @@ void init_type_info( return; } - ecs_type_t type = table->storage_type; - ecs_assert(type != NULL, ECS_INTERNAL_ERROR, NULL); - - ecs_id_t *ids = ecs_vector_first(type, ecs_id_t); - int32_t i, count = ecs_vector_count(type); - + ecs_table_record_t *records = table->records; + int32_t i, count = ecs_vector_count(table->type); table->type_info = ecs_os_calloc_n(ecs_type_info_t, count); for (i = 0; i < count; i ++) { - ecs_id_t id = ids[i]; - ecs_entity_t t = ecs_get_typeid(world, id); - - /* Component type info must have been registered before using it */ - const ecs_type_info_t *ti = flecs_get_type_info(world, t); + ecs_table_record_t *tr = &records[i]; + ecs_id_record_t *idr = (ecs_id_record_t*)tr->hdr.cache; + ecs_assert(idr->flags & ECS_TYPE_INFO_INITIALIZED, + ECS_INTERNAL_ERROR, NULL); + + /* All ids in the storage table must be components with type info */ + const ecs_type_info_t *ti = idr->type_info; ecs_assert(ti != NULL, ECS_INTERNAL_ERROR, NULL); table->flags |= type_info_flags(ti); table->type_info[i] = *ti; @@ -2415,7 +2419,7 @@ void flecs_table_init_data( ecs_table_t *table) { init_storage_table(world, table); - init_type_info(world, table); + init_type_info(table); int32_t sw_count = table->sw_column_count = switch_column_count(table); int32_t bs_count = table->bs_column_count = bitset_column_count(table); @@ -2431,29 +2435,13 @@ void flecs_table_init_data( } if (count) { - ecs_entity_t *ids = ecs_vector_first(type, ecs_entity_t); storage->columns = ecs_os_calloc_n(ecs_column_t, count); + ecs_type_info_t *type_info = table->type_info; + ecs_column_t *columns = storage->columns; for (i = 0; i < count; i ++) { - ecs_entity_t id = ids[i]; - - /* Bootstrap components */ - if (id == ecs_id(EcsComponent)) { - storage->columns[i].size = ECS_SIZEOF(EcsComponent); - storage->columns[i].alignment = ECS_ALIGNOF(EcsComponent); - continue; - } else if (ECS_PAIR_FIRST(id) == ecs_id(EcsIdentifier)) { - storage->columns[i].size = ECS_SIZEOF(EcsIdentifier); - storage->columns[i].alignment = ECS_ALIGNOF(EcsIdentifier); - continue; - } - - const EcsComponent *component = flecs_component_from_id(world, id); - ecs_assert(component != NULL, ECS_INTERNAL_ERROR, NULL); - ecs_assert(component->size != 0, ECS_INTERNAL_ERROR, NULL); - - storage->columns[i].size = flecs_itoi16(component->size); - storage->columns[i].alignment = flecs_itoi16(component->alignment); + columns[i].size = flecs_itoi16(type_info[i].size); + columns[i].alignment = flecs_itoi16(type_info[i].alignment); } } @@ -35198,7 +35186,7 @@ ecs_id_record_t* new_id_record( ecs_id_record_t *idr_r = flecs_get_id_record( world, ECS_PAIR_FIRST(id)); if (idr_r) { - idr->flags = idr_r->flags; + idr->flags = (idr_r->flags & ~ECS_TYPE_INFO_INITIALIZED); } } else { rel = id & ECS_COMPONENT_MASK; @@ -35910,6 +35898,26 @@ ecs_id_record_t* flecs_ensure_id_record( return idr; } +void flecs_register_for_id_record( + ecs_world_t *world, + ecs_id_t id, + const ecs_table_t *table, + ecs_table_record_t *tr) +{ + ecs_id_record_t *idr = flecs_ensure_id_record(world, id); + ecs_table_cache_insert(&idr->cache, table, &tr->hdr); + + /* When id record is used by table, make sure type info is initialized */ + if (!(idr->flags & ECS_TYPE_INFO_INITIALIZED)) { + ecs_entity_t type = ecs_get_typeid(world, id); + if (type) { + idr->type_info = flecs_get_type_info(world, type); + ecs_assert(idr->type_info != NULL, ECS_INTERNAL_ERROR, NULL); + } + idr->flags |= ECS_TYPE_INFO_INITIALIZED; + } +} + ecs_id_record_t* flecs_get_id_record( const ecs_world_t *world, ecs_id_t id) @@ -43312,10 +43320,7 @@ void register_table_for_id( int32_t count, ecs_table_record_t *tr) { - id = ecs_strip_generation(id); - - ecs_id_record_t *idr = flecs_ensure_id_record(world, id); - ecs_table_cache_insert(&idr->cache, table, &tr->hdr); + flecs_register_for_id_record(world, id, table, tr); tr->column = column; tr->count = count; tr->id = id; @@ -43390,7 +43395,6 @@ void flecs_table_records_register( int32_t record_count = count + type_flag_count + (id_count != 0) + (pair_count != 0) + ecs_map_count(&relations) + ecs_map_count(&objects) + 1 /* for any */; - int32_t r = 0; if (!has_childof) { record_count ++; @@ -43399,18 +43403,31 @@ void flecs_table_records_register( table->records = ecs_os_calloc_n(ecs_table_record_t, record_count); table->record_count = record_count; - /* First initialize records for regular (non-wildcard) ids */ + /* First initialize records for regular (non-wildcard) ids. Make sure that + * these table records line up with ids in table type. */ + int32_t first_role_id = -1; for (i = 0; i < count; i ++) { - ecs_id_t id = ids[i]; - register_table_for_id(world, table, id, i, 1, &table->records[r]); - r ++; - - ecs_entity_t role = id & ECS_ROLE_MASK; - if (role && role != ECS_PAIR) { - id &= ECS_COMPONENT_MASK; - id = ecs_pair(id, EcsWildcard); - register_table_for_id(world, table, id, i, 1, &table->records[r]); - r ++; + register_table_for_id(world, table, ids[i], i, 1, &table->records[i]); + if (first_role_id == -1) { + ecs_entity_t role = ids[i] & ECS_ROLE_MASK; + if (role && role != ECS_PAIR) { + first_role_id = i; + } + } + } + + /* Initialize records for ids with roles */ + int32_t r = i; + if (first_role_id != -1) { + for (i = first_role_id; i < count; i ++) { + ecs_id_t id = ids[i]; + ecs_entity_t role = id & ECS_ROLE_MASK; + if (role && role != ECS_PAIR) { + id &= ECS_COMPONENT_MASK; + id = ecs_pair(id, EcsWildcard); + register_table_for_id(world, table, id, i, 1, &table->records[r]); + r ++; + } } } diff --git a/flecs.h b/flecs.h index d0df84285..0cb9f6cfd 100644 --- a/flecs.h +++ b/flecs.h @@ -354,6 +354,7 @@ typedef int32_t ecs_size_t; #define ECS_ID_EXCLUSIVE (1u << 6) #define ECS_ID_DONT_INHERIT (1u << 7) +#define ECS_TYPE_INFO_INITIALIZED (1u << 8) /* Utilities for converting from flags to delete policies and vice versa */ #define ECS_ID_ON_DELETE(flags) \ diff --git a/include/flecs/private/api_defines.h b/include/flecs/private/api_defines.h index 3fdbc7df3..88dbbe8e1 100644 --- a/include/flecs/private/api_defines.h +++ b/include/flecs/private/api_defines.h @@ -197,6 +197,7 @@ typedef int32_t ecs_size_t; #define ECS_ID_EXCLUSIVE (1u << 6) #define ECS_ID_DONT_INHERIT (1u << 7) +#define ECS_TYPE_INFO_INITIALIZED (1u << 8) /* Utilities for converting from flags to delete policies and vice versa */ #define ECS_ID_ON_DELETE(flags) \ diff --git a/src/private_api.h b/src/private_api.h index 46c5ce47d..553453ec7 100644 --- a/src/private_api.h +++ b/src/private_api.h @@ -139,6 +139,12 @@ ecs_id_record_t* flecs_ensure_id_record( ecs_world_t *world, ecs_id_t id); +void flecs_register_for_id_record( + ecs_world_t *world, + ecs_id_t id, + const ecs_table_t *table, + ecs_table_record_t *tr); + ecs_id_record_t* flecs_get_id_record( const ecs_world_t *world, ecs_id_t id); diff --git a/src/private_types.h b/src/private_types.h index 7470ead2b..423959bb6 100644 --- a/src/private_types.h +++ b/src/private_types.h @@ -506,6 +506,9 @@ struct ecs_id_record_t { /* Name lookup index (currently only used for ChildOf pairs) */ ecs_hashmap_t *name_index; + + /* Cached pointer to type info for id */ + const ecs_type_info_t *type_info; }; typedef struct ecs_store_t { diff --git a/src/table.c b/src/table.c index 9066ca4f8..ee5e0c29e 100644 --- a/src/table.c +++ b/src/table.c @@ -196,29 +196,27 @@ void init_storage_table( if (table->storage_table) { return; } - + int32_t i, count = ecs_vector_count(table->type); ecs_id_t *ids = ecs_vector_first(table->type, ecs_id_t); + ecs_table_record_t *records = table->records; ecs_ids_t storage_ids = { .array = ecs_os_alloca_n(ecs_id_t, count) }; for (i = 0; i < count; i ++) { - ecs_id_t id = ids[i]; - - if ((id == ecs_id(EcsComponent)) || - (ECS_PAIR_FIRST(id) == ecs_id(EcsIdentifier))) - { - storage_ids.array[storage_ids.count ++] = id; - continue; - } + ecs_table_record_t *tr = &records[i]; + ecs_id_record_t *idr = (ecs_id_record_t*)tr->hdr.cache; + ecs_assert(idr->flags & ECS_TYPE_INFO_INITIALIZED, + ECS_INTERNAL_ERROR, NULL); - const EcsComponent *comp = flecs_component_from_id(world, id); - if (!comp || !comp->size) { - continue; + if (idr->type_info == NULL) { + ecs_assert(ecs_get_typeid(world, ids[i]) == 0, + ECS_INTERNAL_ERROR, NULL); + continue; /* not a component */ } - storage_ids.array[storage_ids.count ++] = id; + storage_ids.array[storage_ids.count ++] = ids[i]; } if (storage_ids.count && storage_ids.count != count) { @@ -264,7 +262,6 @@ ecs_flags32_t type_info_flags( static void init_type_info( - ecs_world_t *world, ecs_table_t *table) { ecs_table_t *storage_table = table->storage_table; @@ -280,20 +277,18 @@ void init_type_info( return; } - ecs_type_t type = table->storage_type; - ecs_assert(type != NULL, ECS_INTERNAL_ERROR, NULL); - - ecs_id_t *ids = ecs_vector_first(type, ecs_id_t); - int32_t i, count = ecs_vector_count(type); - + ecs_table_record_t *records = table->records; + int32_t i, count = ecs_vector_count(table->type); table->type_info = ecs_os_calloc_n(ecs_type_info_t, count); for (i = 0; i < count; i ++) { - ecs_id_t id = ids[i]; - ecs_entity_t t = ecs_get_typeid(world, id); - - /* Component type info must have been registered before using it */ - const ecs_type_info_t *ti = flecs_get_type_info(world, t); + ecs_table_record_t *tr = &records[i]; + ecs_id_record_t *idr = (ecs_id_record_t*)tr->hdr.cache; + ecs_assert(idr->flags & ECS_TYPE_INFO_INITIALIZED, + ECS_INTERNAL_ERROR, NULL); + + /* All ids in the storage table must be components with type info */ + const ecs_type_info_t *ti = idr->type_info; ecs_assert(ti != NULL, ECS_INTERNAL_ERROR, NULL); table->flags |= type_info_flags(ti); table->type_info[i] = *ti; @@ -305,7 +300,7 @@ void flecs_table_init_data( ecs_table_t *table) { init_storage_table(world, table); - init_type_info(world, table); + init_type_info(table); int32_t sw_count = table->sw_column_count = switch_column_count(table); int32_t bs_count = table->bs_column_count = bitset_column_count(table); @@ -321,29 +316,13 @@ void flecs_table_init_data( } if (count) { - ecs_entity_t *ids = ecs_vector_first(type, ecs_entity_t); storage->columns = ecs_os_calloc_n(ecs_column_t, count); + ecs_type_info_t *type_info = table->type_info; + ecs_column_t *columns = storage->columns; for (i = 0; i < count; i ++) { - ecs_entity_t id = ids[i]; - - /* Bootstrap components */ - if (id == ecs_id(EcsComponent)) { - storage->columns[i].size = ECS_SIZEOF(EcsComponent); - storage->columns[i].alignment = ECS_ALIGNOF(EcsComponent); - continue; - } else if (ECS_PAIR_FIRST(id) == ecs_id(EcsIdentifier)) { - storage->columns[i].size = ECS_SIZEOF(EcsIdentifier); - storage->columns[i].alignment = ECS_ALIGNOF(EcsIdentifier); - continue; - } - - const EcsComponent *component = flecs_component_from_id(world, id); - ecs_assert(component != NULL, ECS_INTERNAL_ERROR, NULL); - ecs_assert(component->size != 0, ECS_INTERNAL_ERROR, NULL); - - storage->columns[i].size = flecs_itoi16(component->size); - storage->columns[i].alignment = flecs_itoi16(component->alignment); + columns[i].size = flecs_itoi16(type_info[i].size); + columns[i].alignment = flecs_itoi16(type_info[i].alignment); } } diff --git a/src/table_graph.c b/src/table_graph.c index 73c82ab5d..9c448b8cc 100644 --- a/src/table_graph.c +++ b/src/table_graph.c @@ -301,10 +301,7 @@ void register_table_for_id( int32_t count, ecs_table_record_t *tr) { - id = ecs_strip_generation(id); - - ecs_id_record_t *idr = flecs_ensure_id_record(world, id); - ecs_table_cache_insert(&idr->cache, table, &tr->hdr); + flecs_register_for_id_record(world, id, table, tr); tr->column = column; tr->count = count; tr->id = id; @@ -379,7 +376,6 @@ void flecs_table_records_register( int32_t record_count = count + type_flag_count + (id_count != 0) + (pair_count != 0) + ecs_map_count(&relations) + ecs_map_count(&objects) + 1 /* for any */; - int32_t r = 0; if (!has_childof) { record_count ++; @@ -388,18 +384,31 @@ void flecs_table_records_register( table->records = ecs_os_calloc_n(ecs_table_record_t, record_count); table->record_count = record_count; - /* First initialize records for regular (non-wildcard) ids */ + /* First initialize records for regular (non-wildcard) ids. Make sure that + * these table records line up with ids in table type. */ + int32_t first_role_id = -1; for (i = 0; i < count; i ++) { - ecs_id_t id = ids[i]; - register_table_for_id(world, table, id, i, 1, &table->records[r]); - r ++; - - ecs_entity_t role = id & ECS_ROLE_MASK; - if (role && role != ECS_PAIR) { - id &= ECS_COMPONENT_MASK; - id = ecs_pair(id, EcsWildcard); - register_table_for_id(world, table, id, i, 1, &table->records[r]); - r ++; + register_table_for_id(world, table, ids[i], i, 1, &table->records[i]); + if (first_role_id == -1) { + ecs_entity_t role = ids[i] & ECS_ROLE_MASK; + if (role && role != ECS_PAIR) { + first_role_id = i; + } + } + } + + /* Initialize records for ids with roles */ + int32_t r = i; + if (first_role_id != -1) { + for (i = first_role_id; i < count; i ++) { + ecs_id_t id = ids[i]; + ecs_entity_t role = id & ECS_ROLE_MASK; + if (role && role != ECS_PAIR) { + id &= ECS_COMPONENT_MASK; + id = ecs_pair(id, EcsWildcard); + register_table_for_id(world, table, id, i, 1, &table->records[r]); + r ++; + } } } diff --git a/src/world.c b/src/world.c index 50b599174..24bb571af 100644 --- a/src/world.c +++ b/src/world.c @@ -1194,7 +1194,7 @@ ecs_id_record_t* new_id_record( ecs_id_record_t *idr_r = flecs_get_id_record( world, ECS_PAIR_FIRST(id)); if (idr_r) { - idr->flags = idr_r->flags; + idr->flags = (idr_r->flags & ~ECS_TYPE_INFO_INITIALIZED); } } else { rel = id & ECS_COMPONENT_MASK; @@ -1906,6 +1906,26 @@ ecs_id_record_t* flecs_ensure_id_record( return idr; } +void flecs_register_for_id_record( + ecs_world_t *world, + ecs_id_t id, + const ecs_table_t *table, + ecs_table_record_t *tr) +{ + ecs_id_record_t *idr = flecs_ensure_id_record(world, id); + ecs_table_cache_insert(&idr->cache, table, &tr->hdr); + + /* When id record is used by table, make sure type info is initialized */ + if (!(idr->flags & ECS_TYPE_INFO_INITIALIZED)) { + ecs_entity_t type = ecs_get_typeid(world, id); + if (type) { + idr->type_info = flecs_get_type_info(world, type); + ecs_assert(idr->type_info != NULL, ECS_INTERNAL_ERROR, NULL); + } + idr->flags |= ECS_TYPE_INFO_INITIALIZED; + } +} + ecs_id_record_t* flecs_get_id_record( const ecs_world_t *world, ecs_id_t id)