From bcffade9af06c60dff856fe3197d1dcc8a42be6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Sun, 10 Aug 2025 00:06:47 -0400 Subject: [PATCH] util/hash_table: don't allocate the smallest table, declare it in the struct When compiling Heaven shaders with radeonsi+ACO, this reduces the total number of ralloc calls by 10.8% (same number as the sets, which also reduced it by 10.8%). Apparently we like to create a lot of hash tables. Reviewed-by: Gert Wollny Acked-by: Pierre-Eric Pelloux-Prayer Part-of: --- src/util/hash_table.c | 46 +++++++++++++++++++++++++++++++------------ src/util/hash_table.h | 10 ++++++++++ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/util/hash_table.c b/src/util/hash_table.c index 5545190f514..ea049e3c5b2 100644 --- a/src/util/hash_table.c +++ b/src/util/hash_table.c @@ -167,6 +167,7 @@ _mesa_hash_table_init(struct hash_table *ht, bool (*key_equals_function)(const void *a, const void *b)) { + ht->mem_ctx = mem_ctx; ht->size_index = 0; ht->size = hash_sizes[ht->size_index].size; ht->rehash = hash_sizes[ht->size_index].rehash; @@ -175,12 +176,14 @@ _mesa_hash_table_init(struct hash_table *ht, ht->max_entries = hash_sizes[ht->size_index].max_entries; ht->key_hash_function = key_hash_function; ht->key_equals_function = key_equals_function; - ht->table = rzalloc_array(mem_ctx, struct hash_entry, ht->size); + assert(ht->size == ARRAY_SIZE(ht->_initial_storage)); + ht->table = ht->_initial_storage; + memset(ht->table, 0, sizeof(ht->_initial_storage)); ht->entries = 0; ht->deleted_entries = 0; ht->deleted_key = &deleted_key_value; - return ht->table != NULL; + return true; } /* It's preferred to use _mesa_hash_table_init instead of this to skip ralloc. */ @@ -243,16 +246,23 @@ _mesa_hash_table_clone(struct hash_table *src, void *dst_mem_ctx) if (ht == NULL) return NULL; - memcpy(ht, src, sizeof(struct hash_table)); + /* Copy the whole structure except the initial storage. */ + memcpy(ht, src, offsetof(struct hash_table, _initial_storage)); + ht->mem_ctx = dst_mem_ctx; - ht->table = ralloc_array(ht, struct hash_entry, ht->size); - if (ht->table == NULL) { - ralloc_free(ht); - return NULL; + if (src->table != src->_initial_storage) { + ht->table = ralloc_array(dst_mem_ctx, struct hash_entry, ht->size); + if (ht->table == NULL) { + ralloc_free(ht); + return NULL; + } + + memcpy(ht->table, src->table, ht->size * sizeof(struct hash_entry)); + } else { + ht->table = ht->_initial_storage; + memcpy(ht->table, src->_initial_storage, sizeof(src->_initial_storage)); } - memcpy(ht->table, src->table, ht->size * sizeof(struct hash_entry)); - return ht; } @@ -272,7 +282,9 @@ _mesa_hash_table_fini(struct hash_table *ht, delete_function(entry); } } - ralloc_free(ht->table); + if (ht->table != ht->_initial_storage) + ralloc_free(ht->table); + ht->table = NULL; } @@ -439,12 +451,19 @@ _mesa_hash_table_rehash(struct hash_table *ht, unsigned new_size_index) if (new_size_index >= ARRAY_SIZE(hash_sizes)) return; - table = rzalloc_array(ralloc_parent(ht->table), struct hash_entry, + table = rzalloc_array(ht->mem_ctx, struct hash_entry, hash_sizes[new_size_index].size); if (table == NULL) return; - old_ht = *ht; + if (ht->table == ht->_initial_storage) { + /* Copy the whole structure including the initial storage. */ + old_ht = *ht; + old_ht.table = old_ht._initial_storage; + } else { + /* Copy everything except the initial storage. */ + memcpy(&old_ht, ht, offsetof(struct hash_table, _initial_storage)); + } ht->table = table; ht->size_index = new_size_index; @@ -462,7 +481,8 @@ _mesa_hash_table_rehash(struct hash_table *ht, unsigned new_size_index) ht->entries = old_ht.entries; - ralloc_free(old_ht.table); + if (old_ht.table != old_ht._initial_storage) + ralloc_free(old_ht.table); } static struct hash_entry * diff --git a/src/util/hash_table.h b/src/util/hash_table.h index f4bbc526c7b..f31e0de4485 100644 --- a/src/util/hash_table.h +++ b/src/util/hash_table.h @@ -44,6 +44,7 @@ struct hash_entry { }; struct hash_table { + void *mem_ctx; struct hash_entry *table; uint32_t (*key_hash_function)(const void *key); bool (*key_equals_function)(const void *a, const void *b); @@ -56,6 +57,15 @@ struct hash_table { uint32_t size_index; uint32_t entries; uint32_t deleted_entries; + + /* "table" points to here at first. A bigger storage is allocated separately + * when a bigger size is needed. + */ + struct hash_entry _initial_storage[19]; /* hash_sizes[0].size */ + + /* Don't insert any new fields here. All other fields must be before + * _initial_storage. + */ }; struct hash_table *