All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Zbigniew Kempczyński" <zbigniew.kempczynski@intel.com>
To: igt-dev@lists.freedesktop.org
Subject: [igt-dev] [PATCH i-g-t v28 03/36] lib/igt_map: Adopt Mesa hash table
Date: Mon, 22 Mar 2021 13:37:17 +0100	[thread overview]
Message-ID: <20210322123750.94772-4-zbigniew.kempczynski@intel.com> (raw)
In-Reply-To: <20210322123750.94772-1-zbigniew.kempczynski@intel.com>

From: Dominik Grzegorzek <dominik.grzegorzek@intel.com>

The _search function has been changed to return a pointer to
the stored data instead of the entry struct. The _search_entry function,
which acts as the original search has been added. Additionally _remove function
has an optional delete_function param, to make it more usable.

For more information, see:
http://cgit.freedesktop.org/~anholt/hash_table/tree/README

Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Zbigniew Kempczyński <zbigniew.kempczynski@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Jason Ekstrand <jason@jlekstrand.net>
---
 .../igt-gpu-tools/igt-gpu-tools-docs.xml      |   1 +
 lib/Makefile.sources                          |   2 +
 lib/igt_map.c                                 | 502 ++++++++++++++++++
 lib/igt_map.h                                 | 174 ++++++
 lib/meson.build                               |   1 +
 5 files changed, 680 insertions(+)
 create mode 100644 lib/igt_map.c
 create mode 100644 lib/igt_map.h

diff --git a/docs/reference/igt-gpu-tools/igt-gpu-tools-docs.xml b/docs/reference/igt-gpu-tools/igt-gpu-tools-docs.xml
index 9c9aa8f1d..bf5ac5428 100644
--- a/docs/reference/igt-gpu-tools/igt-gpu-tools-docs.xml
+++ b/docs/reference/igt-gpu-tools/igt-gpu-tools-docs.xml
@@ -33,6 +33,7 @@
     <xi:include href="xml/igt_kmod.xml"/>
     <xi:include href="xml/igt_kms.xml"/>
     <xi:include href="xml/igt_list.xml"/>
+    <xi:include href="xml/igt_map.xml"/>
     <xi:include href="xml/igt_pm.xml"/>
     <xi:include href="xml/igt_primes.xml"/>
     <xi:include href="xml/igt_rand.xml"/>
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index 4f6389f8a..84fd7b49c 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -48,6 +48,8 @@ lib_source_list =	 	\
 	igt_infoframe.h		\
 	igt_list.c		\
 	igt_list.h		\
+	igt_map.c		\
+	igt_map.h		\
 	igt_matrix.c		\
 	igt_matrix.h		\
 	igt_params.c		\
diff --git a/lib/igt_map.c b/lib/igt_map.c
new file mode 100644
index 000000000..da8713a18
--- /dev/null
+++ b/lib/igt_map.c
@@ -0,0 +1,502 @@
+/*
+ * Copyright © 2009, 2021 Intel Corporation
+ * Copyright © 1988-2004 Keith Packard and Bart Massey.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the authors
+ * or their institutions shall not be used in advertising or
+ * otherwise to promote the sale, use or other dealings in this
+ * Software without prior written authorization from the
+ * authors.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *    Keith Packard <keithp@keithp.com>
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "igt_map.h"
+
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
+
+/*
+ * From Knuth -- a good choice for hash/rehash values is p, p-2 where
+ * p and p-2 are both prime.  These tables are sized to have an extra 10%
+ * free to avoid exponential performance degradation as the hash table fills
+ */
+
+static const uint32_t deleted_key_value;
+static const void *deleted_key = &deleted_key_value;
+
+static const struct {
+	uint32_t max_entries, size, rehash;
+} hash_sizes[] = {
+	{ 2,		5,		3	  },
+	{ 4,		7,		5	  },
+	{ 8,		13,		11	  },
+	{ 16,		19,		17	  },
+	{ 32,		43,		41        },
+	{ 64,		73,		71        },
+	{ 128,		151,		149       },
+	{ 256,		283,		281       },
+	{ 512,		571,		569       },
+	{ 1024,		1153,		1151      },
+	{ 2048,		2269,		2267      },
+	{ 4096,		4519,		4517      },
+	{ 8192,		9013,		9011      },
+	{ 16384,	18043,		18041     },
+	{ 32768,	36109,		36107     },
+	{ 65536,	72091,		72089     },
+	{ 131072,	144409,		144407    },
+	{ 262144,	288361,		288359    },
+	{ 524288,	576883,		576881    },
+	{ 1048576,	1153459,	1153457   },
+	{ 2097152,	2307163,	2307161   },
+	{ 4194304,	4613893,	4613891   },
+	{ 8388608,	9227641,	9227639   },
+	{ 16777216,	18455029,	18455027  },
+	{ 33554432,	36911011,	36911009  },
+	{ 67108864,	73819861,	73819859  },
+	{ 134217728,	147639589,	147639587 },
+	{ 268435456,	295279081,	295279079 },
+	{ 536870912,	590559793,	590559791 },
+	{ 1073741824,	1181116273,	1181116271},
+	{ 2147483648ul,	2362232233ul,	2362232231ul}
+};
+
+static int
+entry_is_free(const struct igt_map_entry *entry)
+{
+	return entry->key == NULL;
+}
+
+static int
+entry_is_deleted(const struct igt_map_entry *entry)
+{
+	return entry->key == deleted_key;
+}
+
+static int
+entry_is_present(const struct igt_map_entry *entry)
+{
+	return entry->key != NULL && entry->key != deleted_key;
+}
+
+/**
+ * igt_map_create:
+ * @hash_function: function that maps key to 32b hash
+ * @key_equals_function: function that compares given hashes
+ *
+ * Function creates a map and initializes it with given @hash_function and
+ * @key_equals_function.
+ *
+ * Returns: pointer to just created map
+ */
+struct igt_map *
+igt_map_create(uint32_t (*hash_function)(const void *key),
+	       int (*key_equals_function)(const void *a, const void *b))
+{
+	struct igt_map *map;
+
+	map = malloc(sizeof(*map));
+	if (map == NULL)
+		return NULL;
+
+	map->size_index = 0;
+	map->size = hash_sizes[map->size_index].size;
+	map->rehash = hash_sizes[map->size_index].rehash;
+	map->max_entries = hash_sizes[map->size_index].max_entries;
+	map->hash_function = hash_function;
+	map->key_equals_function = key_equals_function;
+	map->table = calloc(map->size, sizeof(*map->table));
+	map->entries = 0;
+	map->deleted_entries = 0;
+
+	if (map->table == NULL) {
+		free(map);
+		return NULL;
+	}
+
+	return map;
+}
+
+/**
+ * igt_map_destroy:
+ * @map: igt_map pointer
+ * @delete_function: function that frees data in igt_map_entry
+ *
+ * Frees the given hash table. If @delete_function is passed, it gets called
+ * on each entry present before freeing.
+ */
+void
+igt_map_destroy(struct igt_map *map,
+		void (*delete_function)(struct igt_map_entry *entry))
+{
+	if (!map)
+		return;
+
+	if (delete_function) {
+		struct igt_map_entry *entry;
+
+		igt_map_foreach(map, entry) {
+			delete_function(entry);
+		}
+	}
+	free(map->table);
+	free(map);
+}
+
+/**
+ * igt_map_search:
+ * @map: igt_map pointer
+ * @key: pointer to searched key
+ *
+ * Finds a map entry's data with the given @key.
+ *
+ * Returns: data pointer if the entry was found, %NULL otherwise.
+ * Note that it may be modified by the user.
+ */
+void *
+igt_map_search(struct igt_map *map, const void *key)
+{
+	uint32_t hash = map->hash_function(key);
+	struct igt_map_entry *entry;
+
+	entry = igt_map_search_pre_hashed(map, hash, key);
+	return entry ? entry->data : NULL;
+}
+
+/**
+ * igt_map_search_entry:
+ * @map: igt_map pointer
+ * @key: pointer to searched key
+ *
+ * Finds a map entry with the given @key.
+ *
+ * Returns: map entry or %NULL if no entry is found.
+ * Note that the data pointer may be modified by the user.
+ */
+struct igt_map_entry *
+igt_map_search_entry(struct igt_map *map, const void *key)
+{
+	uint32_t hash = map->hash_function(key);
+
+	return igt_map_search_pre_hashed(map, hash, key);
+}
+
+/**
+ * igt_map_search_pre_hashed:
+ * @map: igt_map pointer
+ * @hash: hash of @key
+ * @key: pointer to searched key
+ *
+ * Finds a map entry with the given @key and @hash of that key.
+ *
+ * Returns: map entry or %NULL if no entry is found.
+ * Note that the data pointer may be modified by the user.
+ */
+struct igt_map_entry *
+igt_map_search_pre_hashed(struct igt_map *map, uint32_t hash,
+			  const void *key)
+{
+	uint32_t start_hash_address = hash % map->size;
+	uint32_t hash_address = start_hash_address;
+
+	do {
+		uint32_t double_hash;
+
+		struct igt_map_entry *entry = map->table + hash_address;
+
+		if (entry_is_free(entry)) {
+			return NULL;
+		} else if (entry_is_present(entry) && entry->hash == hash) {
+			if (map->key_equals_function(key, entry->key)) {
+				return entry;
+			}
+		}
+
+		double_hash = 1 + hash % map->rehash;
+
+		hash_address = (hash_address + double_hash) % map->size;
+	} while (hash_address != start_hash_address);
+
+	return NULL;
+}
+
+static void
+igt_map_rehash(struct igt_map *map, int new_size_index)
+{
+	struct igt_map old_map;
+	struct igt_map_entry *table, *entry;
+
+	if (new_size_index >= ARRAY_SIZE(hash_sizes))
+		return;
+
+	table = calloc(hash_sizes[new_size_index].size, sizeof(*map->table));
+	if (table == NULL)
+		return;
+
+	old_map = *map;
+
+	map->table = table;
+	map->size_index = new_size_index;
+	map->size = hash_sizes[map->size_index].size;
+	map->rehash = hash_sizes[map->size_index].rehash;
+	map->max_entries = hash_sizes[map->size_index].max_entries;
+	map->entries = 0;
+	map->deleted_entries = 0;
+
+	igt_map_foreach(&old_map, entry) {
+		igt_map_insert_pre_hashed(map, entry->hash,
+					     entry->key, entry->data);
+	}
+
+	free(old_map.table);
+}
+
+/**
+ * igt_map_insert:
+ * @map: igt_map pointer
+ * @data: data to be store
+ * @key: pointer to searched key
+ *
+ * Inserts the @data indexed by given @key into the map. If the @map already
+ * contains an entry with the @key, it will be replaced. To avoid memory leaks,
+ * perform a search before inserting.
+ *
+ * Note that insertion may rearrange the table on a resize or rehash,
+ * so previously found hash entries are no longer valid after this function.
+ *
+ * Returns: pointer to just inserted entry
+ */
+struct igt_map_entry *
+igt_map_insert(struct igt_map *map, const void *key, void *data)
+{
+	uint32_t hash = map->hash_function(key);
+
+	/* Make sure nobody tries to add one of the magic values as a
+	 * key. If you need to do so, either do so in a wrapper, or
+	 * store keys with the magic values separately in the struct
+	 * igt_map.
+	 */
+	assert(key != NULL);
+
+	return igt_map_insert_pre_hashed(map, hash, key, data);
+}
+
+/**
+ * igt_map_insert_pre_hashed:
+ * @map: igt_map pointer
+ * @hash: hash of @key
+ * @data: data to be store
+ * @key: pointer to searched key
+ *
+ * Inserts the @data indexed by given @key and @hash of that @key into the map.
+ * If the @map already contains an entry with the @key, it will be replaced.
+ * To avoid memory leaks, perform a search before inserting.
+ *
+ * Note that insertion may rearrange the table on a resize or rehash,
+ * so previously found hash entries are no longer valid after this function.
+ *
+ * Returns: pointer to just inserted entry
+ */
+struct igt_map_entry *
+igt_map_insert_pre_hashed(struct igt_map *map, uint32_t hash,
+			  const void *key, void *data)
+{
+	uint32_t start_hash_address, hash_address;
+	struct igt_map_entry *available_entry = NULL;
+
+	if (map->entries >= map->max_entries) {
+		igt_map_rehash(map, map->size_index + 1);
+	} else if (map->deleted_entries + map->entries >= map->max_entries) {
+		igt_map_rehash(map, map->size_index);
+	}
+
+	start_hash_address = hash % map->size;
+	hash_address = start_hash_address;
+	do {
+		struct igt_map_entry *entry = map->table + hash_address;
+		uint32_t double_hash;
+
+		if (!entry_is_present(entry)) {
+			/* Stash the first available entry we find */
+			if (available_entry == NULL)
+				available_entry = entry;
+			if (entry_is_free(entry))
+				break;
+		}
+
+		/* Implement replacement when another insert happens
+		 * with a matching key.  This is a relatively common
+		 * feature of hash tables, with the alternative
+		 * generally being "insert the new value as well, and
+		 * return it first when the key is searched for".
+		 *
+		 * Note that the hash table doesn't have a delete
+		 * callback.  If freeing of old data pointers is
+		 * required to avoid memory leaks, perform a search
+		 * before inserting.
+		 */
+		if (!entry_is_deleted(entry) &&
+		    entry->hash == hash &&
+		    map->key_equals_function(key, entry->key)) {
+			entry->key = key;
+			entry->data = data;
+			return entry;
+		}
+
+
+		double_hash = 1 + hash % map->rehash;
+
+		hash_address = (hash_address + double_hash) % map->size;
+	} while (hash_address != start_hash_address);
+
+	if (available_entry) {
+		if (entry_is_deleted(available_entry))
+			map->deleted_entries--;
+		available_entry->hash = hash;
+		available_entry->key = key;
+		available_entry->data = data;
+		map->entries++;
+		return available_entry;
+	}
+
+	/* We could hit here if a required resize failed. An unchecked-malloc
+	 * application could ignore this result.
+	 */
+	return NULL;
+}
+
+/**
+ * igt_map_remove:
+ * @map: igt_map pointer
+ * @key: pointer to searched key
+ * @delete_function: function that frees data in igt_map_entry
+ *
+ * Function searches for an entry with a given @key, and removes it from
+ * the map. If @delete_function is passed, it will be called on removed entry.
+ *
+ * If the caller has previously found a struct igt_map_entry pointer,
+ * (from calling igt_map_search() or remembering it from igt_map_insert()),
+ * then igt_map_remove_entry() can be called instead to avoid an extra search.
+ */
+void
+igt_map_remove(struct igt_map *map, const void *key,
+		void (*delete_function)(struct igt_map_entry *entry))
+{
+	struct igt_map_entry *entry;
+
+	entry = igt_map_search_entry(map, key);
+	if (delete_function)
+		delete_function(entry);
+
+	igt_map_remove_entry(map, entry);
+}
+
+/**
+ * igt_map_remove_entry:
+ * @map: igt_map pointer
+ * @entry: pointer to map entry
+ *
+ * Function deletes the given hash entry.
+ *
+ * Note that deletion doesn't otherwise modify the table, so an iteration over
+ * the map deleting entries is safe.
+ */
+void
+igt_map_remove_entry(struct igt_map *map, struct igt_map_entry *entry)
+{
+	if (!entry)
+		return;
+
+	entry->key = deleted_key;
+	map->entries--;
+	map->deleted_entries++;
+}
+
+/**
+ * igt_map_next_entry:
+ * @map: igt_map pointer
+ * @entry: pointer to map entry, %NULL for the first map entry
+ *
+ * This function is an iterator over the hash table.
+ * Note that an iteration over the table is O(table_size) not O(entries).
+ *
+ * Returns: pointer to the next entry
+ */
+struct igt_map_entry *
+igt_map_next_entry(struct igt_map *map, struct igt_map_entry *entry)
+{
+	if (entry == NULL)
+		entry = map->table;
+	else
+		entry = entry + 1;
+
+	for (; entry != map->table + map->size; entry++) {
+		if (entry_is_present(entry)) {
+			return entry;
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * igt_map_random_entry:
+ * @map: igt_map pointer
+ * @predicate: filtering entries function
+ *
+ * Functions returns random entry from the map. This may be useful in
+ * implementing random replacement (as opposed to just removing everything)
+ * in caches based on this hash table implementation. @predicate may be used to
+ * filter entries, or may be set to %NULL for no filtering.
+ *
+ * Returns: pointer to the randomly chosen map entry
+ */
+struct igt_map_entry *
+igt_map_random_entry(struct igt_map *map,
+		     int (*predicate)(struct igt_map_entry *entry))
+{
+	struct igt_map_entry *entry;
+	uint32_t i = random() % map->size;
+
+	if (map->entries == 0)
+		return NULL;
+
+	for (entry = map->table + i; entry != map->table + map->size; entry++) {
+		if (entry_is_present(entry) &&
+		    (!predicate || predicate(entry))) {
+			return entry;
+		}
+	}
+
+	for (entry = map->table; entry != map->table + i; entry++) {
+		if (entry_is_present(entry) &&
+		    (!predicate || predicate(entry))) {
+			return entry;
+		}
+	}
+
+	return NULL;
+}
diff --git a/lib/igt_map.h b/lib/igt_map.h
new file mode 100644
index 000000000..cadcd6e35
--- /dev/null
+++ b/lib/igt_map.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright © 2009,2021 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#ifndef IGT_MAP_H
+#define IGT_MAP_H
+
+#include <inttypes.h>
+
+/**
+ * SECTION:igt_map
+ * @short_description: a linear-reprobing hashmap implementation
+ * @title: IGT Map
+ * @include: igt_map.h
+ *
+ * Implements an open-addressing, linear-reprobing hash table.
+ *
+ * For more information, see:
+ * http://cgit.freedesktop.org/~anholt/hash_table/tree/README
+ *
+ * Example usage:
+ *
+ *|[<!-- language="C" -->
+ * #define GOLDEN_RATIO_PRIME_32 0x9e370001UL
+ *
+ * static inline uint32_t hash_identifier(const void *val)
+ * {
+ *	uint32_t hash = *(uint32_t *) val;
+ *
+ *	hash = hash * GOLDEN_RATIO_PRIME_32;
+ *	return hash;
+ * }
+ *
+ * static int equal_identifiers(const void *a, const void *b)
+ * {
+ *	uint32_t *key1 = (uint32_t *) a, *key2 = (uint32_t *) b;
+ *
+ *	return *key1 == *key2;
+ * }
+ *
+ * static void free_func(struct igt_map_entry *entry)
+ * {
+ * 	free(entry->data);
+ * }
+ *
+ * struct igt_map *map;
+ *
+ * struct record {
+ *      int foo;
+ *      uint32_t unique_identifier;
+ * };
+ *
+ * struct record *r1, r2, *record;
+ * struct igt_map_entry *entry;
+ *
+ * r1 = malloc(sizeof(struct record));
+ * map = igt_map_create(hash_identifier, equal_identifiers);
+ * igt_map_insert(map, &r1->unique_identifier, r1);
+ * igt_map_insert(map, &r2.unique_identifier, &r2);
+ *
+ * igt_map_foreach(map, entry) {
+ * 	record = entry->data;
+ * 	printf("key: %u, foo: %d\n", *(uint32_t *) entry->key, record->foo);
+ * }
+ *
+ * record = igt_map_search(map, &r1->unique_identifier);
+ * entry = igt_map_search_entry(map, &r2.unique_identifier);
+ *
+ * igt_map_remove(map, &r1->unique_identifier, free_func);
+ * igt_map_remove_entry(map, entry);
+ *
+ *  igt_map_destroy(map, NULL);
+ * ]|
+ */
+
+struct igt_map_entry {
+	uint32_t hash;
+	const void *key;
+	void *data;
+};
+
+struct igt_map {
+	struct igt_map_entry *table;
+	uint32_t (*hash_function)(const void *key);
+	int (*key_equals_function)(const void *a, const void *b);
+	uint32_t size;
+	uint32_t rehash;
+	uint32_t max_entries;
+	uint32_t size_index;
+	uint32_t entries;
+	uint32_t deleted_entries;
+};
+
+struct igt_map *
+igt_map_create(uint32_t (*hash_function)(const void *key),
+	       int (*key_equals_function)(const void *a, const void *b));
+void
+igt_map_destroy(struct igt_map *map,
+		void (*delete_function)(struct igt_map_entry *entry));
+
+struct igt_map_entry *
+igt_map_insert(struct igt_map *map, const void *key, void *data);
+
+void *
+igt_map_search(struct igt_map *map, const void *key);
+
+struct igt_map_entry *
+igt_map_search_entry(struct igt_map *map, const void *key);
+
+void
+igt_map_remove(struct igt_map *map, const void *key,
+	       void (*delete_function)(struct igt_map_entry *entry));
+
+void
+igt_map_remove_entry(struct igt_map *map, struct igt_map_entry *entry);
+
+struct igt_map_entry *
+igt_map_next_entry(struct igt_map *map, struct igt_map_entry *entry);
+
+struct igt_map_entry *
+igt_map_random_entry(struct igt_map *map,
+		     int (*predicate)(struct igt_map_entry *entry));
+/**
+ * igt_map_foreach
+ * @map: igt_map pointer
+ * @entry: igt_map_entry pointer
+ *
+ * Macro is a loop, which iterates through each map entry. Inside a
+ * loop block current element is accessible by the @entry pointer.
+ *
+ * This foreach function is safe against deletion (which just replaces
+ * an entry's data with the deleted marker), but not against insertion
+ * (which may rehash the table, making entry a dangling pointer).
+ */
+#define igt_map_foreach(map, entry)				\
+	for (entry = igt_map_next_entry(map, NULL);		\
+	     entry != NULL;					\
+	     entry = igt_map_next_entry(map, entry))
+
+/* Alternate interfaces to reduce repeated calls to hash function. */
+struct igt_map_entry *
+igt_map_search_pre_hashed(struct igt_map *map,
+			     uint32_t hash,
+			     const void *key);
+
+struct igt_map_entry *
+igt_map_insert_pre_hashed(struct igt_map *map,
+			     uint32_t hash,
+			     const void *key, void *data);
+
+#endif
diff --git a/lib/meson.build b/lib/meson.build
index 672b42062..7254faeac 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -61,6 +61,7 @@ lib_sources = [
 	'igt_core.c',
 	'igt_draw.c',
 	'igt_list.c',
+	'igt_map.c',
 	'igt_pm.c',
 	'igt_dummyload.c',
 	'uwildmat/uwildmat.c',
-- 
2.26.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

  parent reply	other threads:[~2021-03-22 12:38 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-22 12:37 [igt-dev] [PATCH i-g-t v28 00/36] Introduce IGT allocator Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 01/36] lib/igt_list: Add igt_list_del_init() Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 02/36] lib/igt_list: igt_hlist implementation Zbigniew Kempczyński
2021-03-22 12:37 ` Zbigniew Kempczyński [this message]
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 04/36] lib/igt_core: Track child process pid and tid Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 05/36] lib/intel_allocator_simple: Add simple allocator Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 06/36] lib/intel_allocator_reloc: Add reloc allocator Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 07/36] lib/intel_allocator_random: Add random allocator Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 08/36] lib/intel_allocator: Add intel_allocator core Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 09/36] lib/intel_allocator: Try to stop smoothly instead of deinit Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 10/36] lib/intel_allocator_msgchannel: Scale to 4k of parallel clients Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 11/36] lib/intel_allocator: Separate allocator multiprocess start Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 12/36] lib/intel_bufops: Change size from 32->64 bit Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 13/36] lib/intel_bufops: Add init with handle and size function Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 14/36] lib/intel_batchbuffer: Integrate intel_bb with allocator Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 15/36] lib/intel_batchbuffer: Use relocations in intel-bb up to gen12 Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 16/36] lib/intel_batchbuffer: Create bb with strategy / vm ranges Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 17/36] lib/intel_batchbuffer: Add tracking intel_buf to intel_bb Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 18/36] lib/intel_batchbuffer: Don't collect relocations for newer gens Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 19/36] lib/igt_fb: Initialize intel_buf with same size as fb Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 20/36] tests/api_intel_bb: Remove check-canonical test Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 21/36] tests/api_intel_bb: Modify test to verify intel_bb with allocator Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 22/36] tests/api_intel_bb: Add compressed->compressed copy Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 23/36] tests/api_intel_bb: Add purge-bb test Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 24/36] tests/api_intel_bb: Add simple intel-bb which uses allocator Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 25/36] tests/api_intel_bb: Use allocator in delta-check test Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 26/36] tests/api_intel_bb: Check switching vm in intel-bb Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 27/36] tests/api_intel_allocator: Simple allocator test suite Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 28/36] tests/api_intel_allocator: Add execbuf with allocator example Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 29/36] tests/api_intel_allocator: Verify child can use its standalone allocator Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 30/36] tests/gem_softpin: Verify allocator and execbuf pair work together Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 31/36] tests/gem|kms: Remove intel_bb from fixture Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 32/36] tests/gem_mmap_offset: Use intel_buf wrapper code instead direct Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 33/36] tests/gem_ppgtt: Adopt test to use intel_bb with allocator Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 34/36] tests/gem_render_copy_redux: Adopt to use with intel_bb and allocator Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 35/36] tests/perf.c: Remove buffer from batch Zbigniew Kempczyński
2021-03-22 12:37 ` [igt-dev] [PATCH i-g-t v28 36/36] tests/gem_linear_blits: Use intel allocator Zbigniew Kempczyński
2021-03-22 13:28 ` [igt-dev] ✓ Fi.CI.BAT: success for Introduce IGT allocator (rev31) Patchwork
2021-03-23 15:28 ` [igt-dev] ✗ Fi.CI.IGT: failure " Patchwork
2021-03-23 16:32   ` Zbigniew Kempczyński
2021-03-23 18:16   ` Zbigniew Kempczyński

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210322123750.94772-4-zbigniew.kempczynski@intel.com \
    --to=zbigniew.kempczynski@intel.com \
    --cc=igt-dev@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.