[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