[PATCH libdrm] etnaviv: Use hash table to track BO indexes

Marek Vasut marex at denx.de
Mon Jun 3 23:39:29 UTC 2019


Use hash table instead of ad-hoc arrays.

Signed-off-by: Marek Vasut <marex at denx.de>
Cc: Christian Gmeiner <christian.gmeiner at gmail.com>
Cc: Lucas Stach <l.stach at pengutronix.de>
---
 etnaviv/etnaviv_bo.c         |  6 +++---
 etnaviv/etnaviv_cmd_stream.c | 31 ++++++++++++++++++++++---------
 etnaviv/etnaviv_priv.h       | 17 ++++++++++-------
 3 files changed, 35 insertions(+), 19 deletions(-)

diff --git a/etnaviv/etnaviv_bo.c b/etnaviv/etnaviv_bo.c
index 43ce6b4e..28ad3162 100644
--- a/etnaviv/etnaviv_bo.c
+++ b/etnaviv/etnaviv_bo.c
@@ -44,14 +44,14 @@ drm_private void bo_del(struct etna_bo *bo)
 	if (bo->map)
 		drm_munmap(bo->map, bo->size);
 
-	if (bo->name)
-		drmHashDelete(bo->dev->name_table, bo->name);
-
 	if (bo->handle) {
 		struct drm_gem_close req = {
 			.handle = bo->handle,
 		};
 
+		if (bo->name)
+			drmHashDelete(bo->dev->name_table, bo->name);
+
 		drmHashDelete(bo->dev->handle_table, bo->handle);
 		drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
 	}
diff --git a/etnaviv/etnaviv_cmd_stream.c b/etnaviv/etnaviv_cmd_stream.c
index 261777b0..f550b2ff 100644
--- a/etnaviv/etnaviv_cmd_stream.c
+++ b/etnaviv/etnaviv_cmd_stream.c
@@ -61,6 +61,7 @@ drm_public struct etna_cmd_stream *etna_cmd_stream_new(struct etna_pipe *pipe,
 		void *priv)
 {
 	struct etna_cmd_stream_priv *stream = NULL;
+	struct etna_device *dev = pipe->gpu->dev;
 
 	if (size == 0) {
 		ERROR_MSG("invalid size of 0");
@@ -86,6 +87,7 @@ drm_public struct etna_cmd_stream *etna_cmd_stream_new(struct etna_pipe *pipe,
 	stream->pipe = pipe;
 	stream->reset_notify = reset_notify;
 	stream->reset_notify_priv = priv;
+	stream->seqno = ++dev->stream_cnt;
 
 	return &stream->base;
 
@@ -150,18 +152,24 @@ static uint32_t bo2idx(struct etna_cmd_stream *stream, struct etna_bo *bo,
 
 	pthread_mutex_lock(&idx_lock);
 
-	if (bo->current_stream == stream) {
+	if (bo->current_stream_seqno == priv->seqno) {
 		idx = bo->idx;
 	} else {
-		/* slow-path: */
-		for (idx = 0; idx < priv->nr_bos; idx++)
-			if (priv->bos[idx] == bo)
-				break;
-		if (idx == priv->nr_bos) {
-			/* not found */
+		void *val;
+
+		if (!priv->bo_table)
+			priv->bo_table = drmHashCreate();
+
+		if (!drmHashLookup(priv->bo_table, bo->handle, &val)) {
+			/* found */
+			idx = (uint32_t)(uintptr_t)val;
+		} else {
 			idx = append_bo(stream, bo);
+			val = (void *)(uintptr_t)idx;
+			drmHashInsert(priv->bo_table, bo->handle, val);
 		}
-		bo->current_stream = stream;
+
+		bo->current_stream_seqno = priv->seqno;
 		bo->idx = idx;
 	}
 	pthread_mutex_unlock(&idx_lock);
@@ -213,10 +221,15 @@ static void flush(struct etna_cmd_stream *stream, int in_fence_fd,
 	for (uint32_t i = 0; i < priv->nr_bos; i++) {
 		struct etna_bo *bo = priv->bos[i];
 
-		bo->current_stream = NULL;
+		bo->current_stream_seqno = 0;
 		etna_bo_del(bo);
 	}
 
+	if (priv->bo_table) {
+		drmHashDestroy(priv->bo_table);
+		priv->bo_table = NULL;
+	}
+
 	if (out_fence_fd)
 		*out_fence_fd = req.fence_fd;
 }
diff --git a/etnaviv/etnaviv_priv.h b/etnaviv/etnaviv_priv.h
index eef7f49c..bc82324e 100644
--- a/etnaviv/etnaviv_priv.h
+++ b/etnaviv/etnaviv_priv.h
@@ -76,6 +76,8 @@ struct etna_device {
 	struct etna_bo_cache bo_cache;
 
 	int closefd;        /* call close(fd) upon destruction */
+
+	unsigned int stream_cnt;
 };
 
 drm_private void etna_bo_cache_init(struct etna_bo_cache *cache);
@@ -98,14 +100,12 @@ struct etna_bo {
 	uint64_t        offset;         /* offset to mmap() */
 	atomic_t        refcnt;
 
-	/* in the common case, a bo won't be referenced by more than a single
-	 * command stream.  So to avoid looping over all the bo's in the
-	 * reloc table to find the idx of a bo that might already be in the
-	 * table, we cache the idx in the bo.  But in order to detect the
-	 * slow-path where bo is ref'd in multiple streams, we also must track
-	 * the current_stream for which the idx is valid.  See bo2idx().
+	/*
+	 * To avoid excess hashtable lookups, cache the stream this bo was
+	 * last emitted on (since that will probably also be the next ring
+	 * it is emitted on).
 	 */
-	struct etna_cmd_stream *current_stream;
+	unsigned int current_stream_seqno;
 	uint32_t idx;
 
 	int reuse;
@@ -153,6 +153,9 @@ struct etna_cmd_stream_priv {
 	/* notify callback if buffer reset happened */
 	void (*reset_notify)(struct etna_cmd_stream *stream, void *priv);
 	void *reset_notify_priv;
+
+	unsigned int seqno;
+	void *bo_table;
 };
 
 struct etna_perfmon {
-- 
2.20.1



More information about the dri-devel mailing list