[PATCH 6/6] drm/i915: Keep the most recently used active-fence upon discard
Chris Wilson
chris at chris-wilson.co.uk
Thu Jul 9 09:11:25 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 | 64 +++++++++++++++++-------
drivers/gpu/drm/i915/i915_active.h | 4 ++
drivers/gpu/drm/i915/i915_active_types.h | 12 ++++-
3 files changed, 60 insertions(+), 20 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_active.c b/drivers/gpu/drm/i915/i915_active.c
index b8e33cdb5774..5b68c1d6379f 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,6 +118,18 @@ static inline void debug_active_assert(struct i915_active *ref) { }
#endif
+#ifdef CONFIG_64BIT
+static struct i915_active_node *reset_shared(struct i915_active *ref)
+{
+ ref->shared.timeline = 0; /* needs cmpxchg(u64) */
+
+ rb_link_node(&ref->shared.node, NULL, &ref->tree.rb_node);
+ rb_insert_color(&ref->shared.node, &ref->tree);
+
+ return &ref->shared;
+}
+#endif
+
static void
__active_retire(struct i915_active *ref)
{
@@ -141,6 +146,17 @@ __active_retire(struct i915_active *ref)
GEM_BUG_ON(rcu_access_pointer(ref->excl.fence));
debug_active_deactivate(ref);
+#ifdef CONFIG_64BIT
+ 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_shared(ref);
+ }
+ GEM_BUG_ON(ref->cache != &ref->shared);
+#else
/* Keep the MRU cached node for reuse */
if (ref->cache) {
/* Discard all other nodes in the tree */
@@ -151,12 +167,8 @@ __active_retire(struct i915_active *ref)
rb_link_node(&ref->cache->node, NULL, &ref->tree.rb_node);
rb_insert_color(&ref->cache->node, &ref->tree);
GEM_BUG_ON(ref->tree.rb_node != &ref->cache->node);
-
-#ifdef CONFIG_64BIT
- /* Make the cached node available for reuse with any timeline */
- ref->cache->timeline = 0; /* needs cmpxchg(u64) */
-#endif
}
+#endif
spin_unlock_irqrestore(&ref->tree_lock, flags);
@@ -239,11 +251,11 @@ __active_lookup(struct i915_active *ref, u64 idx)
GEM_BUG_ON(idx == 0);
node = READ_ONCE(ref->cache);
- if (node && node->timeline == idx)
- return node;
-
#ifdef CONFIG_64BIT
- if (node && !cmpxchg(&node->timeline, 0, idx))
+ if (node->timeline == idx || !cmpxchg(&node->timeline, 0, idx))
+ return node;
+#else
+ if (node && node->timeline == idx)
return node;
#endif
@@ -325,6 +337,19 @@ active_instance(struct i915_active *ref, u64 idx)
return &node->base;
}
+static struct i915_active_node *init_cache(struct i915_active *ref)
+{
+#ifdef CONFIG_64BIT
+ ref->shared.ref = ref;
+ __i915_active_fence_init(&ref->shared.base, NULL, node_retire);
+
+ return reset_shared(ref);
+#else
+ ref->tree = RB_ROOT;
+ return NULL;
+#endif
+}
+
void __i915_active_init(struct i915_active *ref,
int (*active)(struct i915_active *ref),
void (*retire)(struct i915_active *ref),
@@ -342,8 +367,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);
@@ -752,6 +776,7 @@ int i915_sw_fence_await_active(struct i915_sw_fence *fence,
return await_active(ref, flags, sw_await_fence, fence, fence);
}
+#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) || !defined(CONFIG_64BIT)
void i915_active_fini(struct i915_active *ref)
{
debug_active_fini(ref);
@@ -759,9 +784,10 @@ void i915_active_fini(struct i915_active *ref)
GEM_BUG_ON(work_pending(&ref->work));
mutex_destroy(&ref->mutex);
- if (ref->cache)
+ if (!IS_ENABLED(CONFIG_64BIT) && ref->cache)
kmem_cache_free(global.slab_cache, ref->cache);
}
+#endif
static inline bool is_idle_barrier(struct i915_active_node *node, u64 idx)
{
diff --git a/drivers/gpu/drm/i915/i915_active.h b/drivers/gpu/drm/i915/i915_active.h
index b9e0394e2975..d6c35fe794b9 100644
--- a/drivers/gpu/drm/i915/i915_active.h
+++ b/drivers/gpu/drm/i915/i915_active.h
@@ -217,7 +217,11 @@ i915_active_is_idle(const struct i915_active *ref)
return !atomic_read(&ref->count);
}
+#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) || !defined(CONFIG_64BIT)
void i915_active_fini(struct i915_active *ref);
+#else
+static inline void i915_active_fini(struct i915_active *ref) { }
+#endif
int i915_active_acquire_preallocate_barrier(struct i915_active *ref,
struct intel_engine_cs *engine);
diff --git a/drivers/gpu/drm/i915/i915_active_types.h b/drivers/gpu/drm/i915/i915_active_types.h
index bbb22213eeba..5d8dd573e692 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,11 @@ struct i915_active {
/* Preallocated "exclusive" node */
struct i915_active_fence excl;
+#ifdef CONFIG_64BIT
+ /* Preallocated common node */
+ struct i915_active_node shared;
+#endif
+
unsigned long flags;
#define I915_ACTIVE_RETIRE_SLEEPS BIT(0)
--
2.20.1
More information about the Intel-gfx-trybot
mailing list