[PATCH 03/29] drm/i915: Keep the most recently used active-fence upon discard

Chris Wilson chris at chris-wilson.co.uk
Thu Jul 9 01:08:27 UTC 2020


Whenever an i915_active idles, we prune its tree of old fence slots to
prevent a gradual leak should it be used to track many, many timelines.
The downside is that we then have to frequently reallocate the rbtree.
A compromise is that we keep the most recently used fence slot, and
reuse that for the next active reference.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_active.c       | 45 ++++++++++++++++--------
 drivers/gpu/drm/i915/i915_active_types.h | 10 +++++-
 2 files changed, 39 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_active.c b/drivers/gpu/drm/i915/i915_active.c
index f3ba03e74a41..e368f2ecb919 100644
--- a/drivers/gpu/drm/i915/i915_active.c
+++ b/drivers/gpu/drm/i915/i915_active.c
@@ -27,13 +27,6 @@ static struct i915_global_active {
 	struct kmem_cache *slab_cache;
 } global;
 
-struct i915_active_node {
-	struct i915_active_fence base;
-	struct i915_active *ref;
-	struct rb_node node;
-	u64 timeline;
-};
-
 static inline struct i915_active_node *
 node_from_active(struct i915_active_fence *active)
 {
@@ -125,11 +118,21 @@ static inline void debug_active_assert(struct i915_active *ref) { }
 
 #endif
 
+static struct i915_active_node *reset_cache(struct i915_active *ref)
+{
+	ref->shared.timeline = 0;
+
+	rb_link_node(&ref->shared.node, NULL, &ref->tree.rb_node);
+	rb_insert_color(&ref->shared.node, &ref->tree);
+
+	return &ref->shared;
+}
+
 static void
 __active_retire(struct i915_active *ref)
 {
 	struct i915_active_node *it, *n;
-	struct rb_root root;
+	struct rb_root root = RB_ROOT;
 	unsigned long flags;
 
 	GEM_BUG_ON(i915_active_is_idle(ref));
@@ -141,9 +144,15 @@ __active_retire(struct i915_active *ref)
 	GEM_BUG_ON(rcu_access_pointer(ref->excl.fence));
 	debug_active_deactivate(ref);
 
-	root = ref->tree;
-	ref->tree = RB_ROOT;
-	ref->cache = NULL;
+	if (ref->shared.timeline) {
+		/* Discard all other nodes in the tree */
+		rb_erase(&ref->shared.node, &ref->tree);
+		root = ref->tree;
+
+		/* Rebuild the tree with just this node */
+		ref->cache = reset_cache(ref);
+	}
+	GEM_BUG_ON(ref->cache != &ref->shared);
 
 	spin_unlock_irqrestore(&ref->tree_lock, flags);
 
@@ -231,7 +240,7 @@ active_instance(struct i915_active *ref, struct intel_timeline *tl)
 	 * current timeline.
 	 */
 	node = READ_ONCE(ref->cache);
-	if (node && node->timeline == idx)
+	if (node->timeline == idx || !cmpxchg(&node->timeline, 0, idx))
 		return &node->base;
 
 	/* Preallocate a replacement, just in case */
@@ -275,6 +284,14 @@ active_instance(struct i915_active *ref, struct intel_timeline *tl)
 	return &node->base;
 }
 
+static struct i915_active_node *init_cache(struct i915_active *ref)
+{
+	ref->shared.ref = ref;
+	__i915_active_fence_init(&ref->shared.base, NULL, node_retire);
+
+	return reset_cache(ref);
+}
+
 void __i915_active_init(struct i915_active *ref,
 			int (*active)(struct i915_active *ref),
 			void (*retire)(struct i915_active *ref),
@@ -292,8 +309,7 @@ void __i915_active_init(struct i915_active *ref,
 		ref->flags |= I915_ACTIVE_RETIRE_SLEEPS;
 
 	spin_lock_init(&ref->tree_lock);
-	ref->tree = RB_ROOT;
-	ref->cache = NULL;
+	ref->cache = init_cache(ref);
 
 	init_llist_head(&ref->preallocated_barriers);
 	atomic_set(&ref->count, 0);
@@ -657,7 +673,6 @@ void i915_active_fini(struct i915_active *ref)
 	debug_active_fini(ref);
 	GEM_BUG_ON(atomic_read(&ref->count));
 	GEM_BUG_ON(work_pending(&ref->work));
-	GEM_BUG_ON(!RB_EMPTY_ROOT(&ref->tree));
 	mutex_destroy(&ref->mutex);
 }
 #endif
diff --git a/drivers/gpu/drm/i915/i915_active_types.h b/drivers/gpu/drm/i915/i915_active_types.h
index bbb22213eeba..c4f95b86d8eb 100644
--- a/drivers/gpu/drm/i915/i915_active_types.h
+++ b/drivers/gpu/drm/i915/i915_active_types.h
@@ -22,7 +22,12 @@ struct i915_active_fence {
 	struct dma_fence_cb cb;
 };
 
-struct i915_active_node;
+struct i915_active_node {
+	struct i915_active_fence base;
+	struct i915_active *ref;
+	struct rb_node node;
+	u64 timeline;
+};
 
 #define I915_ACTIVE_MAY_SLEEP BIT(0)
 
@@ -40,6 +45,9 @@ struct i915_active {
 	/* Preallocated "exclusive" node */
 	struct i915_active_fence excl;
 
+	/* Preallocated common node */
+	struct i915_active_node shared;
+
 	unsigned long flags;
 #define I915_ACTIVE_RETIRE_SLEEPS BIT(0)
 
-- 
2.20.1



More information about the Intel-gfx-trybot mailing list