Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/msm/gem: Evict active GEM objects when necessary

If we are under enough memory pressure, we should stall waiting for
active buffers to become idle in order to evict.

v2: Check for __GFP_ATOMIC before blocking

Signed-off-by: Rob Clark <robdclark@chromium.org>
Patchwork: https://patchwork.freedesktop.org/patch/496135/
Link: https://lore.kernel.org/r/20220802155152.1727594-14-robdclark@gmail.com

+67 -17
+57 -11
drivers/gpu/drm/msm/msm_gem_shrinker.c
··· 24 24 return enable_eviction && get_nr_swap_pages() > 0; 25 25 } 26 26 27 + static bool can_block(struct shrink_control *sc) 28 + { 29 + if (sc->gfp_mask & __GFP_ATOMIC) 30 + return false; 31 + return current_is_kswapd() || (sc->gfp_mask & __GFP_RECLAIM); 32 + } 33 + 27 34 static unsigned long 28 35 msm_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc) 29 36 { ··· 72 65 return true; 73 66 } 74 67 68 + static bool 69 + wait_for_idle(struct drm_gem_object *obj) 70 + { 71 + enum dma_resv_usage usage = dma_resv_usage_rw(true); 72 + return dma_resv_wait_timeout(obj->resv, usage, false, 1000) > 0; 73 + } 74 + 75 + static bool 76 + active_purge(struct drm_gem_object *obj) 77 + { 78 + if (!wait_for_idle(obj)) 79 + return false; 80 + 81 + return purge(obj); 82 + } 83 + 84 + static bool 85 + active_evict(struct drm_gem_object *obj) 86 + { 87 + if (!wait_for_idle(obj)) 88 + return false; 89 + 90 + return evict(obj); 91 + } 92 + 75 93 static unsigned long 76 94 msm_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) 77 95 { 78 96 struct msm_drm_private *priv = 79 97 container_of(shrinker, struct msm_drm_private, shrinker); 98 + struct { 99 + struct drm_gem_lru *lru; 100 + bool (*shrink)(struct drm_gem_object *obj); 101 + bool cond; 102 + unsigned long freed; 103 + } stages[] = { 104 + /* Stages of progressively more aggressive/expensive reclaim: */ 105 + { &priv->lru.dontneed, purge, true }, 106 + { &priv->lru.willneed, evict, can_swap() }, 107 + { &priv->lru.dontneed, active_purge, can_block(sc) }, 108 + { &priv->lru.willneed, active_evict, can_swap() && can_block(sc) }, 109 + }; 80 110 long nr = sc->nr_to_scan; 81 - unsigned long freed, purged, evicted = 0; 111 + unsigned long freed = 0; 82 112 83 - purged = drm_gem_lru_scan(&priv->lru.dontneed, nr, purge); 84 - nr -= purged; 85 - 86 - if (can_swap() && nr > 0) { 87 - evicted = drm_gem_lru_scan(&priv->lru.willneed, nr, evict); 88 - nr -= evicted; 113 + for (unsigned i = 0; (nr > 0) && (i < ARRAY_SIZE(stages)); i++) { 114 + if (!stages[i].cond) 115 + continue; 116 + stages[i].freed = 117 + drm_gem_lru_scan(stages[i].lru, nr, stages[i].shrink); 118 + nr -= stages[i].freed; 119 + freed += stages[i].freed; 89 120 } 90 121 91 - freed = purged + evicted; 92 - 93 - if (freed) 94 - trace_msm_gem_shrink(sc->nr_to_scan, purged, evicted); 122 + if (freed) { 123 + trace_msm_gem_shrink(sc->nr_to_scan, stages[0].freed, 124 + stages[1].freed, stages[2].freed, 125 + stages[3].freed); 126 + } 95 127 96 128 return (freed > 0) ? freed : SHRINK_STOP; 97 129 }
+10 -6
drivers/gpu/drm/msm/msm_gpu_trace.h
··· 116 116 117 117 118 118 TRACE_EVENT(msm_gem_shrink, 119 - TP_PROTO(u32 nr_to_scan, u32 purged, u32 evicted), 120 - TP_ARGS(nr_to_scan, purged, evicted), 119 + TP_PROTO(u32 nr_to_scan, u32 purged, u32 evicted, 120 + u32 active_purged, u32 active_evicted), 121 + TP_ARGS(nr_to_scan, purged, evicted, active_purged, active_evicted), 121 122 TP_STRUCT__entry( 122 123 __field(u32, nr_to_scan) 123 124 __field(u32, purged) 124 125 __field(u32, evicted) 126 + __field(u32, active_purged) 127 + __field(u32, active_evicted) 125 128 ), 126 129 TP_fast_assign( 127 130 __entry->nr_to_scan = nr_to_scan; 128 131 __entry->purged = purged; 129 132 __entry->evicted = evicted; 133 + __entry->active_purged = active_purged; 134 + __entry->active_evicted = active_evicted; 130 135 ), 131 - TP_printk("nr_to_scan=%u pages, purged=%u pages, evicted=%u pages", 132 - __entry->nr_to_scan, 133 - __entry->purged, 134 - __entry->evicted) 136 + TP_printk("nr_to_scan=%u pg, purged=%u pg, evicted=%u pg, active_purged=%u pg, active_evicted=%u pg", 137 + __entry->nr_to_scan, __entry->purged, __entry->evicted, 138 + __entry->active_purged, __entry->active_evicted) 135 139 ); 136 140 137 141