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 04/35] lib/igt_map: Introduce igt_map
Date: Tue, 16 Feb 2021 12:39:36 +0100	[thread overview]
Message-ID: <20210216114007.122175-5-zbigniew.kempczynski@intel.com> (raw)
In-Reply-To: <20210216114007.122175-1-zbigniew.kempczynski@intel.com>

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

Implementation of generic, non-thread safe, dynamic size hash map.

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>
---
 .../igt-gpu-tools/igt-gpu-tools-docs.xml      |   1 +
 lib/Makefile.sources                          |   2 +
 lib/igt_map.c                                 | 131 ++++++++++++++++++
 lib/igt_map.h                                 | 104 ++++++++++++++
 lib/meson.build                               |   1 +
 5 files changed, 239 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..ca58efbd9
--- /dev/null
+++ b/lib/igt_map.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include "igt_map.h"
+#include "igt.h"
+#include "igt_x86.h"
+
+#define MIN_CAPACITY_BITS 2
+
+static bool igt_map_filled(struct igt_map *map)
+{
+	return IGT_MAP_CAPACITY(map) * 4 / 5 <= map->size;
+}
+
+static void igt_map_extend(struct igt_map *map)
+{
+	struct igt_hlist_head *new_heads;
+	struct igt_map_entry *pos;
+	struct igt_hlist_node *tmp;
+	uint32_t new_bits = map->capacity_bits + 1;
+	int i;
+
+	new_heads = calloc(1ULL << new_bits,
+			   sizeof(struct igt_hlist_head));
+	igt_assert(new_heads);
+
+	igt_map_for_each_safe(map, i, tmp, pos)
+		igt_hlist_add_head(&pos->link, &new_heads[map->hash_fn(pos->key, new_bits)]);
+
+	free(map->heads);
+	map->capacity_bits++;
+
+	map->heads = new_heads;
+}
+
+static bool equal_4bytes(const void *key1, const void *key2)
+{
+	const uint32_t *k1 = key1, *k2 = key2;
+	return *k1 == *k2;
+}
+
+/*  2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
+#define GOLDEN_RATIO_PRIME_64 0x9e37fffffffc0001ULL
+
+static inline uint64_t hash_64_4bytes(const void *val, unsigned int bits)
+{
+	uint64_t hash = *(uint32_t *)val;
+
+	hash = hash * GOLDEN_RATIO_PRIME_64;
+	/* High bits are more random, so use them. */
+	return hash >> (64 - bits);
+}
+
+void __igt_map_init(struct igt_map *map, igt_map_equal_fn eq_fn,
+		 igt_map_hash_fn hash_fn, uint32_t initial_bits)
+{
+	map->equal_fn = eq_fn == NULL ? equal_4bytes : eq_fn;
+	map->hash_fn = hash_fn == NULL ? hash_64_4bytes : hash_fn;
+	map->capacity_bits = initial_bits > 0 ? initial_bits
+					      : MIN_CAPACITY_BITS;
+	map->heads = calloc(IGT_MAP_CAPACITY(map),
+			    sizeof(struct igt_hlist_head));
+
+	igt_assert(map->heads);
+	map->size = 0;
+}
+
+void igt_map_add(struct igt_map *map, const void *key, void *value)
+{
+	struct igt_map_entry *entry;
+
+	if (igt_map_filled(map))
+		igt_map_extend(map);
+
+	entry = malloc(sizeof(struct igt_map_entry));
+	entry->value = value;
+	entry->key = key;
+	igt_hlist_add_head(&entry->link,
+			   &map->heads[map->hash_fn(key, map->capacity_bits)]);
+	map->size++;
+}
+
+void *igt_map_del(struct igt_map *map, const void *key)
+{
+	struct igt_map_entry *pos;
+	struct igt_hlist_node *tmp;
+	void *val = NULL;
+
+	igt_map_for_each_possible_safe(map, pos, tmp, key) {
+		if (map->equal_fn(pos->key, key)) {
+			igt_hlist_del(&pos->link);
+			val = pos->value;
+			free(pos);
+		}
+	}
+	return val;
+}
+
+void *igt_map_find(struct igt_map *map, const void *key)
+{
+	struct igt_map_entry *pos = NULL;
+
+	igt_map_for_each_possible(map, pos, key)
+		if (map->equal_fn(pos->key, key))
+			break;
+
+	return pos ? pos->value : NULL;
+}
+
+void igt_map_free(struct igt_map *map)
+{
+	struct igt_map_entry *pos;
+	struct igt_hlist_node *tmp;
+	int i;
+
+	igt_map_for_each_safe(map, i, tmp, pos) {
+		igt_hlist_del(&pos->link);
+		free(pos);
+	}
+
+	free(map->heads);
+}
+
+bool igt_map_empty(struct igt_map *map)
+{
+	return map->size;
+}
diff --git a/lib/igt_map.h b/lib/igt_map.h
new file mode 100644
index 000000000..7924c8911
--- /dev/null
+++ b/lib/igt_map.h
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+
+#ifndef IGT_MAP_H
+#define IGT_MAP_H
+
+#include <stdint.h>
+#include "igt_list.h"
+
+/**
+ * SECTION:igt_map
+ * @short_description: a dynamic sized hashmap implementation
+ * @title: IGT Map
+ * @include: igt_map.h
+ *
+ * igt_map is a dynamic sized, non-thread-safe implementation of a hashmap.
+ * This map grows exponentially when it's over 80% filled. The structure allows
+ * indexing records by any key through the hash and equal functions.
+ * By default, hashmap compares and hashes the first four bytes of a key.
+ *
+ * Example usage:
+ *
+ * |[<!-- language="C" -->
+ * struct igt_map *map;
+ *
+ * struct record {
+ * 	int foo;
+ * 	uint32_t unique_identifier;
+ * };
+ *
+ * struct record r1, r2, *r_ptr;
+ *
+ * map = malloc(sizeof(*map));
+ * igt_map_init(map); // initiaize the map with default parameters
+ * igt_map_add(map, &r1.unique_identifier, &r1);
+ * igt_map_add(map, &r2.unique_identifier, &r2);
+ *
+ * struct igt_map_entry *pos; int i;
+ * igt_map_for_each(map, i, pos) {
+ * 	r_ptr = pos->value;
+ * 	printf("key: %u, foo: %d\n", *(uint32_t*) pos->key, r_ptr->foo);
+ * }
+ *
+ * uint32_t key = r1.unique_identifier;
+ * r_ptr = igt_map_find(map, &key); // get r1
+ *
+ * r_ptr = igt_map_del(map, &r2.unique_identifier);
+ * if (r_ptr)
+ * 	printf("record with key %u deleted\n", r_ptr->unique_identifier);
+ *
+ * igt_map_free(map);
+ * free(map);
+ * ]|
+ */
+
+typedef bool (*igt_map_equal_fn)(const void *key1, const void *key2);
+typedef uint64_t (*igt_map_hash_fn)(const void *val, unsigned int bits);
+struct igt_map {
+	uint32_t size;
+	uint32_t capacity_bits;
+	igt_map_equal_fn equal_fn;
+	igt_map_hash_fn hash_fn;
+	struct igt_hlist_head *heads;
+};
+
+struct igt_map_entry {
+	const void *key;
+	void *value;
+	struct igt_hlist_node link;
+};
+
+void __igt_map_init(struct igt_map *map, igt_map_equal_fn eq_fn,
+		  igt_map_hash_fn hash_fn, uint32_t initial_bits);
+void igt_map_add(struct igt_map *map, const void *key, void *value);
+void *igt_map_del(struct igt_map *map, const void *key);
+void *igt_map_find(struct igt_map *map, const void *key);
+void igt_map_free(struct igt_map *map);
+bool igt_map_empty(struct igt_map *map);
+
+#define igt_map_init(map) __igt_map_init(map, NULL, NULL, 8)
+
+#define IGT_MAP_CAPACITY(map) (1ULL << map->capacity_bits)
+
+#define igt_map_for_each_safe(map, bkt, tmp, obj) \
+	for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < IGT_MAP_CAPACITY(map); \
+	(bkt)++)\
+	igt_hlist_for_each_entry_safe(obj, tmp, &map->heads[bkt], link)
+
+#define igt_map_for_each(map, bkt, obj) \
+	for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < IGT_MAP_CAPACITY(map); \
+	(bkt)++)\
+	igt_hlist_for_each_entry(obj, &map->heads[bkt], link)
+
+#define igt_map_for_each_possible(map, obj, key) \
+	igt_hlist_for_each_entry(obj, \
+		&map->heads[map->hash_fn(key, map->capacity_bits)], link)
+
+#define igt_map_for_each_possible_safe(map, obj, tmp, key) \
+	igt_hlist_for_each_entry_safe(obj, tmp, \
+		&map->heads[map->hash_fn(key, map->capacity_bits)], link)
+
+#endif /* IGT_MAP_H */
diff --git a/lib/meson.build b/lib/meson.build
index 02ecef53e..c2e176447 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-02-16 11:40 UTC|newest]

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

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=20210216114007.122175-5-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.