[igt-dev] [PATCH i-g-t 2/3] lib/intel_bufops: Add simple object cache

Dominik Grzegorzek dominik.grzegorzek at intel.com
Tue Sep 29 10:48:17 UTC 2020


From: Zbigniew Kempczyński <zbigniew.kempczynski at intel.com>

For simplify writing of benchmarks when we want to keep GPU busy
all the time we should reuse buffers whenever possible. Simply
reusing the buffer is not enough because to schedule new execbuf
we have to wait until previous rendering will complete on those
buffers. Creating new ones should occur only if there're no spare
buffers, for other cases we can verify does a potential buffer
is still busy. If it is not busy we can reuse it and use its
previous address to avoid relocation.

Change in intel_buf adds some caching layer which will create
new buffer if there's no free buffer or reuse buffer which size
is maching and buffer is not busy.

Signed-off-by: Zbigniew Kempczyński <zbigniew.kempczynski at intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek at intel.com>
Cc: Chris Wilson <chris at chris-wilson.co.uk>
---
 lib/intel_bufops.c | 135 +++++++++++++++++++++++++++++++++++++++++++--
 lib/intel_bufops.h |   2 +
 2 files changed, 133 insertions(+), 4 deletions(-)

diff --git a/lib/intel_bufops.c b/lib/intel_bufops.c
index a1e9ba55..0fd4ce4e 100644
--- a/lib/intel_bufops.c
+++ b/lib/intel_bufops.c
@@ -24,7 +24,9 @@
 
 #include <sys/ioctl.h>
 #include <cairo.h>
+#include <pthread.h>
 #include "igt.h"
+#include "igt_list.h"
 #include "igt_x86.h"
 #include "intel_bufops.h"
 
@@ -115,6 +117,94 @@ struct buf_ops {
 	bo_copy ys_to_linear;
 };
 
+struct cache_entry {
+	int fd;
+	uint32_t size;
+	uint32_t handle;
+	uint64_t prev_offset;
+	bool reserved;
+	bool busy;
+	struct igt_list_head link;
+};
+
+#define CACHE_BUCKETS 253
+struct {
+	pthread_mutex_t mutex;
+	struct igt_list_head head[CACHE_BUCKETS];
+	uint32_t entries;
+} cache;
+
+static bool use_caching;
+
+static inline int cache_bucket(int fd, uint32_t size) {
+	return (size >> 12) * fd % CACHE_BUCKETS;
+}
+
+static uint32_t cache_find_or_create(int fd, uint32_t size, uint64_t *poffset)
+{
+	struct cache_entry *pos;
+	uint32_t handle;
+	bool alloc = true;
+	int bucket = cache_bucket(fd, size);
+
+	pthread_mutex_lock(&cache.mutex);
+	if (!igt_list_empty(&cache.head[bucket])) {
+		igt_list_for_each_entry(pos, &cache.head[bucket], link) {
+			if (fd == pos->fd && size == pos->size) {
+				/* Update busy state */
+				if (!pos->reserved && pos->busy)
+					pos->busy = gem_bo_busy(fd, pos->handle);
+
+				if (!pos->busy && !pos->reserved) {
+					handle = pos->handle;
+					pos->busy = true;
+					pos->reserved = true;
+					if (poffset)
+						*poffset = pos->prev_offset;
+					alloc = false;
+					break;
+				}
+			}
+		}
+	}
+
+	if (alloc) {
+		handle = gem_create(fd, size);
+		pos = calloc(sizeof(*pos), 1);
+		igt_assert(pos);
+
+		pos->fd = fd;
+		pos->size = size;
+		pos->handle = handle;
+		pos->busy = true;
+		pos->reserved = true;
+		pos->prev_offset = INTEL_BUF_INVALID_ADDRESS;
+		if (poffset)
+			*poffset = pos->prev_offset;
+		igt_list_add(&pos->link, &cache.head[bucket]);
+	}
+	pthread_mutex_unlock(&cache.mutex);
+
+	return handle;
+}
+
+static void cache_remove(int fd, uint32_t handle, uint32_t size, uint64_t offset)
+{
+	struct cache_entry *pos;
+	int bucket = cache_bucket(fd, size);
+
+	pthread_mutex_lock(&cache.mutex);
+	if (!igt_list_empty(&cache.head[bucket])) {
+		igt_list_for_each_entry(pos, &cache.head[bucket], link) {
+			if (fd == pos->fd && size == pos->size && handle == pos->handle) {
+				pos->prev_offset = offset;
+				pos->reserved = false;
+			}
+		}
+	}
+	pthread_mutex_unlock(&cache.mutex);
+}
+
 static const char *tiling_str(uint32_t tiling)
 {
 	switch (tiling) {
@@ -702,6 +792,39 @@ void linear_to_intel_buf(struct buf_ops *bops, struct intel_buf *buf,
 		__copy_ccs(bops, buf, linear, CCS_LINEAR_TO_BUF);
 }
 
+void intel_buf_use_caching(bool caching)
+{
+	if (caching == use_caching)
+		return;
+
+	use_caching = caching;
+	pthread_mutex_init(&cache.mutex, NULL);
+	for (int i = 0; i < CACHE_BUCKETS; i++)
+		IGT_INIT_LIST_HEAD(&cache.head[i]);
+}
+
+static uint32_t get_gem(struct intel_buf *buf, uint32_t size,
+			  uint64_t *poffset)
+{
+	if (!use_caching) {
+		*poffset = INTEL_BUF_INVALID_ADDRESS;
+		return gem_create(buf->fd, size);
+	}
+
+	return cache_find_or_create(buf->fd, size, poffset);
+}
+
+static void put_gem(struct intel_buf *buf)
+{
+	if (!use_caching) {
+		gem_close(buf->fd, buf->handle);
+		return;
+	}
+
+	cache_remove(buf->fd, buf->handle,
+		     intel_buf_bo_size(buf), buf->addr.offset);
+}
+
 static void __intel_buf_init(struct buf_ops *bops,
 			     uint32_t handle,
 			     struct intel_buf *buf,
@@ -723,6 +846,7 @@ static void __intel_buf_init(struct buf_ops *bops,
 	memset(buf, 0, sizeof(*buf));
 
 	buf->bops = bops;
+	buf->fd = buf_ops_get_fd(bops);
 	buf->addr.offset = INTEL_BUF_INVALID_ADDRESS;
 
 	if (compression) {
@@ -774,10 +898,13 @@ static void __intel_buf_init(struct buf_ops *bops,
 		size = buf->surface[0].stride * ALIGN(height, align_h);
 	}
 
-	if (handle)
+	if (handle) {
 		buf->handle = handle;
-	else
-		buf->handle = gem_create(bops->fd, size);
+	} else {
+		uint64_t offset;
+		buf->handle = get_gem(buf, size, &offset);
+		buf->addr.offset = offset;
+	}
 
 	set_hw_tiled(bops, buf);
 }
@@ -824,7 +951,7 @@ void intel_buf_close(struct buf_ops *bops, struct intel_buf *buf)
 	igt_assert(buf);
 
 	if (buf->is_owner)
-		gem_close(bops->fd, buf->handle);
+		put_gem(buf);
 }
 
 /**
diff --git a/lib/intel_bufops.h b/lib/intel_bufops.h
index 8debe7f2..74162213 100644
--- a/lib/intel_bufops.h
+++ b/lib/intel_bufops.h
@@ -11,6 +11,7 @@ struct buf_ops;
 #define INTEL_BUF_NAME_MAXSIZE 32
 struct intel_buf {
 	struct buf_ops *bops;
+	int fd;
 	bool is_owner;
 	uint32_t handle;
 	uint32_t tiling;
@@ -113,6 +114,7 @@ static inline void intel_buf_set_ownership(struct intel_buf *buf, bool is_owner)
 	buf->is_owner = is_owner;
 }
 
+void intel_buf_use_caching(bool caching);
 void intel_buf_init(struct buf_ops *bops, struct intel_buf *buf,
 		    int width, int height, int bpp, int alignment,
 		    uint32_t tiling, uint32_t compression);
-- 
2.20.1



More information about the igt-dev mailing list