Skip to content

Commit 3365e22

Browse files
committed
drm/i915: Lazily unbind vma on close
When userspace is passing around swapbuffers using DRI, we frequently have to open and close the same object in the foreign address space. This shows itself as the same object being rebound at roughly 30fps (with a second object also being rebound at 30fps), which involves us having to rewrite the page tables and maintain the drm_mm range manager every time. However, since the object still exists and it is only the local handle that disappears, if we are lazy and do not unbind the VMA immediately when the local user closes the object but defer it until the GPU is idle, then we can reuse the same VMA binding. We still have to be careful to mark the handle and lookup tables as closed to maintain the uABI, just allowing the underlying VMA to be resurrected if the user is able to access the same object from the same context again. If the object itself is destroyed (neither userspace keeping a handle to it), the VMA will be reaped immediately as usual. In the future, this will be even more useful as instantiating a new VMA for use on the GPU will become heavier. A nuisance indeed, so nip it in the bud. v2: s/__i915_vma_final_close/i915_vma_destroy/ etc. v3: Leave a hint as to why we deferred the unbind on close. Signed-off-by: Chris Wilson <[email protected]> Cc: Tvrtko Ursulin <[email protected]> Reviewed-by: Tvrtko Ursulin <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent dc74f6f commit 3365e22

File tree

8 files changed

+79
-25
lines changed

8 files changed

+79
-25
lines changed

drivers/gpu/drm/i915/i915_drv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2062,6 +2062,7 @@ struct drm_i915_private {
20622062
struct list_head timelines;
20632063

20642064
struct list_head active_rings;
2065+
struct list_head closed_vma;
20652066
u32 active_requests;
20662067
u32 request_serial;
20672068

drivers/gpu/drm/i915/i915_gem.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ static u32 __i915_gem_park(struct drm_i915_private *i915)
165165
i915_timelines_park(i915);
166166

167167
i915_pmu_gt_parked(i915);
168+
i915_vma_parked(i915);
168169

169170
i915->gt.awake = false;
170171

@@ -4795,7 +4796,7 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915,
47954796
&obj->vma_list, obj_link) {
47964797
GEM_BUG_ON(i915_vma_is_active(vma));
47974798
vma->flags &= ~I915_VMA_PIN_MASK;
4798-
i915_vma_close(vma);
4799+
i915_vma_destroy(vma);
47994800
}
48004801
GEM_BUG_ON(!list_empty(&obj->vma_list));
48014802
GEM_BUG_ON(!RB_EMPTY_ROOT(&obj->vma_tree));
@@ -5598,6 +5599,7 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
55985599

55995600
INIT_LIST_HEAD(&dev_priv->gt.timelines);
56005601
INIT_LIST_HEAD(&dev_priv->gt.active_rings);
5602+
INIT_LIST_HEAD(&dev_priv->gt.closed_vma);
56015603

56025604
i915_gem_init__mm(dev_priv);
56035605

drivers/gpu/drm/i915/i915_gem_execbuffer.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,8 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb)
762762
}
763763

764764
/* transfer ref to ctx */
765-
vma->open_count++;
765+
if (!vma->open_count++)
766+
i915_vma_reopen(vma);
766767
list_add(&lut->obj_link, &obj->lut_list);
767768
list_add(&lut->ctx_link, &eb->ctx->handles_list);
768769
lut->ctx = eb->ctx;

drivers/gpu/drm/i915/i915_gem_gtt.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2218,6 +2218,12 @@ i915_ppgtt_create(struct drm_i915_private *dev_priv,
22182218
}
22192219

22202220
void i915_ppgtt_close(struct i915_address_space *vm)
2221+
{
2222+
GEM_BUG_ON(vm->closed);
2223+
vm->closed = true;
2224+
}
2225+
2226+
static void ppgtt_destroy_vma(struct i915_address_space *vm)
22212227
{
22222228
struct list_head *phases[] = {
22232229
&vm->active_list,
@@ -2226,15 +2232,12 @@ void i915_ppgtt_close(struct i915_address_space *vm)
22262232
NULL,
22272233
}, **phase;
22282234

2229-
GEM_BUG_ON(vm->closed);
22302235
vm->closed = true;
2231-
22322236
for (phase = phases; *phase; phase++) {
22332237
struct i915_vma *vma, *vn;
22342238

22352239
list_for_each_entry_safe(vma, vn, *phase, vm_link)
2236-
if (!i915_vma_is_closed(vma))
2237-
i915_vma_close(vma);
2240+
i915_vma_destroy(vma);
22382241
}
22392242
}
22402243

@@ -2245,7 +2248,8 @@ void i915_ppgtt_release(struct kref *kref)
22452248

22462249
trace_i915_ppgtt_release(&ppgtt->base);
22472250

2248-
/* vmas should already be unbound and destroyed */
2251+
ppgtt_destroy_vma(&ppgtt->base);
2252+
22492253
GEM_BUG_ON(!list_empty(&ppgtt->base.active_list));
22502254
GEM_BUG_ON(!list_empty(&ppgtt->base.inactive_list));
22512255
GEM_BUG_ON(!list_empty(&ppgtt->base.unbound_list));

drivers/gpu/drm/i915/i915_vma.c

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ i915_vma_retire(struct i915_gem_active *active, struct i915_request *rq)
4646

4747
GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
4848
list_move_tail(&vma->vm_link, &vma->vm->inactive_list);
49-
if (unlikely(i915_vma_is_closed(vma) && !i915_vma_is_pinned(vma)))
50-
WARN_ON(i915_vma_unbind(vma));
5149

5250
GEM_BUG_ON(!i915_gem_object_is_active(obj));
5351
if (--obj->active_count)
@@ -232,7 +230,6 @@ i915_vma_instance(struct drm_i915_gem_object *obj,
232230
if (!vma)
233231
vma = vma_create(obj, vm, view);
234232

235-
GEM_BUG_ON(!IS_ERR(vma) && i915_vma_is_closed(vma));
236233
GEM_BUG_ON(!IS_ERR(vma) && i915_vma_compare(vma, vm, view));
237234
GEM_BUG_ON(!IS_ERR(vma) && vma_lookup(obj, vm, view) != vma);
238235
return vma;
@@ -684,13 +681,43 @@ int __i915_vma_do_pin(struct i915_vma *vma,
684681
return ret;
685682
}
686683

687-
static void i915_vma_destroy(struct i915_vma *vma)
684+
void i915_vma_close(struct i915_vma *vma)
685+
{
686+
lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);
687+
688+
GEM_BUG_ON(i915_vma_is_closed(vma));
689+
vma->flags |= I915_VMA_CLOSED;
690+
691+
/*
692+
* We defer actually closing, unbinding and destroying the VMA until
693+
* the next idle point, or if the object is freed in the meantime. By
694+
* postponing the unbind, we allow for it to be resurrected by the
695+
* client, avoiding the work required to rebind the VMA. This is
696+
* advantageous for DRI, where the client/server pass objects
697+
* between themselves, temporarily opening a local VMA to the
698+
* object, and then closing it again. The same object is then reused
699+
* on the next frame (or two, depending on the depth of the swap queue)
700+
* causing us to rebind the VMA once more. This ends up being a lot
701+
* of wasted work for the steady state.
702+
*/
703+
list_add_tail(&vma->closed_link, &vma->vm->i915->gt.closed_vma);
704+
}
705+
706+
void i915_vma_reopen(struct i915_vma *vma)
707+
{
708+
lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);
709+
710+
if (vma->flags & I915_VMA_CLOSED) {
711+
vma->flags &= ~I915_VMA_CLOSED;
712+
list_del(&vma->closed_link);
713+
}
714+
}
715+
716+
static void __i915_vma_destroy(struct i915_vma *vma)
688717
{
689718
int i;
690719

691720
GEM_BUG_ON(vma->node.allocated);
692-
GEM_BUG_ON(i915_vma_is_active(vma));
693-
GEM_BUG_ON(!i915_vma_is_closed(vma));
694721
GEM_BUG_ON(vma->fence);
695722

696723
for (i = 0; i < ARRAY_SIZE(vma->last_read); i++)
@@ -699,22 +726,38 @@ static void i915_vma_destroy(struct i915_vma *vma)
699726

700727
list_del(&vma->obj_link);
701728
list_del(&vma->vm_link);
729+
rb_erase(&vma->obj_node, &vma->obj->vma_tree);
702730

703731
if (!i915_vma_is_ggtt(vma))
704732
i915_ppgtt_put(i915_vm_to_ppgtt(vma->vm));
705733

706734
kmem_cache_free(to_i915(vma->obj->base.dev)->vmas, vma);
707735
}
708736

709-
void i915_vma_close(struct i915_vma *vma)
737+
void i915_vma_destroy(struct i915_vma *vma)
710738
{
711-
GEM_BUG_ON(i915_vma_is_closed(vma));
712-
vma->flags |= I915_VMA_CLOSED;
739+
lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);
713740

714-
rb_erase(&vma->obj_node, &vma->obj->vma_tree);
741+
GEM_BUG_ON(i915_vma_is_active(vma));
742+
GEM_BUG_ON(i915_vma_is_pinned(vma));
743+
744+
if (i915_vma_is_closed(vma))
745+
list_del(&vma->closed_link);
746+
747+
WARN_ON(i915_vma_unbind(vma));
748+
__i915_vma_destroy(vma);
749+
}
750+
751+
void i915_vma_parked(struct drm_i915_private *i915)
752+
{
753+
struct i915_vma *vma, *next;
715754

716-
if (!i915_vma_is_active(vma) && !i915_vma_is_pinned(vma))
717-
WARN_ON(i915_vma_unbind(vma));
755+
list_for_each_entry_safe(vma, next, &i915->gt.closed_vma, closed_link) {
756+
GEM_BUG_ON(!i915_vma_is_closed(vma));
757+
i915_vma_destroy(vma);
758+
}
759+
760+
GEM_BUG_ON(!list_empty(&i915->gt.closed_vma));
718761
}
719762

720763
static void __i915_vma_iounmap(struct i915_vma *vma)
@@ -804,7 +847,7 @@ int i915_vma_unbind(struct i915_vma *vma)
804847
return -EBUSY;
805848

806849
if (!drm_mm_node_allocated(&vma->node))
807-
goto destroy;
850+
return 0;
808851

809852
GEM_BUG_ON(obj->bind_count == 0);
810853
GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
@@ -841,10 +884,6 @@ int i915_vma_unbind(struct i915_vma *vma)
841884

842885
i915_vma_remove(vma);
843886

844-
destroy:
845-
if (unlikely(i915_vma_is_closed(vma)))
846-
i915_vma_destroy(vma);
847-
848887
return 0;
849888
}
850889

drivers/gpu/drm/i915/i915_vma.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ struct i915_vma {
119119
/** This vma's place in the eviction list */
120120
struct list_head evict_link;
121121

122+
struct list_head closed_link;
123+
122124
/**
123125
* Used for performing relocations during execbuffer insertion.
124126
*/
@@ -285,6 +287,8 @@ void i915_vma_revoke_mmap(struct i915_vma *vma);
285287
int __must_check i915_vma_unbind(struct i915_vma *vma);
286288
void i915_vma_unlink_ctx(struct i915_vma *vma);
287289
void i915_vma_close(struct i915_vma *vma);
290+
void i915_vma_reopen(struct i915_vma *vma);
291+
void i915_vma_destroy(struct i915_vma *vma);
288292

289293
int __i915_vma_do_pin(struct i915_vma *vma,
290294
u64 size, u64 alignment, u64 flags);
@@ -408,6 +412,8 @@ i915_vma_unpin_fence(struct i915_vma *vma)
408412
__i915_vma_unpin_fence(vma);
409413
}
410414

415+
void i915_vma_parked(struct drm_i915_private *i915);
416+
411417
#define for_each_until(cond) if (cond) break; else
412418

413419
/**

drivers/gpu/drm/i915/selftests/huge_pages.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,7 @@ static int __igt_write_huge(struct i915_gem_context *ctx,
10911091
out_vma_unpin:
10921092
i915_vma_unpin(vma);
10931093
out_vma_close:
1094-
i915_vma_close(vma);
1094+
i915_vma_destroy(vma);
10951095

10961096
return err;
10971097
}

drivers/gpu/drm/i915/selftests/mock_gem_device.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ struct drm_i915_private *mock_gem_device(void)
226226

227227
INIT_LIST_HEAD(&i915->gt.timelines);
228228
INIT_LIST_HEAD(&i915->gt.active_rings);
229+
INIT_LIST_HEAD(&i915->gt.closed_vma);
229230

230231
mutex_lock(&i915->drm.struct_mutex);
231232
mock_init_ggtt(i915);

0 commit comments

Comments
 (0)