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 <gert.wollny@collabora.com>
Acked-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36728>
This commit is contained in:
Marek Olšák 2025-08-10 00:06:47 -04:00 committed by Marge Bot
parent 2028caad28
commit bcffade9af
2 changed files with 43 additions and 13 deletions

View file

@ -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 *

View file

@ -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 *