summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/panfrost
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/panfrost')
-rw-r--r--src/gallium/drivers/panfrost/pan_bo.c50
-rw-r--r--src/gallium/drivers/panfrost/pan_bo.h10
-rw-r--r--src/gallium/drivers/panfrost/pan_screen.c1
-rw-r--r--src/gallium/drivers/panfrost/pan_screen.h6
4 files changed, 61 insertions, 6 deletions
diff --git a/src/gallium/drivers/panfrost/pan_bo.c b/src/gallium/drivers/panfrost/pan_bo.c
index 1fe7e225b8a..1a945daf237 100644
--- a/src/gallium/drivers/panfrost/pan_bo.c
+++ b/src/gallium/drivers/panfrost/pan_bo.c
@@ -203,7 +203,8 @@ panfrost_bo_cache_fetch(struct panfrost_screen *screen,
struct panfrost_bo *bo = NULL;
/* Iterate the bucket looking for something suitable */
- list_for_each_entry_safe(struct panfrost_bo, entry, bucket, link) {
+ list_for_each_entry_safe(struct panfrost_bo, entry, bucket,
+ bucket_link) {
if (entry->size < size || entry->flags != flags)
continue;
@@ -218,7 +219,8 @@ panfrost_bo_cache_fetch(struct panfrost_screen *screen,
int ret;
/* This one works, splice it out of the cache */
- list_del(&entry->link);
+ list_del(&entry->bucket_link);
+ list_del(&entry->lru_link);
ret = drmIoctl(screen->fd, DRM_IOCTL_PANFROST_MADVISE, &madv);
if (!ret && !madv.retained) {
@@ -234,6 +236,31 @@ panfrost_bo_cache_fetch(struct panfrost_screen *screen,
return bo;
}
+static void
+panfrost_bo_cache_evict_stale_bos(struct panfrost_screen *screen)
+{
+ struct timespec time;
+
+ clock_gettime(CLOCK_MONOTONIC, &time);
+ list_for_each_entry_safe(struct panfrost_bo, entry,
+ &screen->bo_cache.lru, lru_link) {
+ /* We want all entries that have been used more than 1 sec
+ * ago to be dropped, others can be kept.
+ * Note the <= 2 check and not <= 1. It's here to account for
+ * the fact that we're only testing ->tv_sec, not ->tv_nsec.
+ * That means we might keep entries that are between 1 and 2
+ * seconds old, but we don't really care, as long as unused BOs
+ * are dropped at some point.
+ */
+ if (time.tv_sec - entry->last_used <= 2)
+ break;
+
+ list_del(&entry->bucket_link);
+ list_del(&entry->lru_link);
+ panfrost_bo_free(entry);
+ }
+}
+
/* Tries to add a BO to the cache. Returns if it was
* successful */
@@ -248,6 +275,7 @@ panfrost_bo_cache_put(struct panfrost_bo *bo)
pthread_mutex_lock(&screen->bo_cache.lock);
struct list_head *bucket = pan_bucket(screen, bo->size);
struct drm_panfrost_madvise madv;
+ struct timespec time;
madv.handle = bo->gem_handle;
madv.madv = PANFROST_MADV_DONTNEED;
@@ -256,7 +284,17 @@ panfrost_bo_cache_put(struct panfrost_bo *bo)
drmIoctl(screen->fd, DRM_IOCTL_PANFROST_MADVISE, &madv);
/* Add us to the bucket */
- list_addtail(&bo->link, bucket);
+ list_addtail(&bo->bucket_link, bucket);
+
+ /* Add us to the LRU list and update the last_used field. */
+ list_addtail(&bo->lru_link, &screen->bo_cache.lru);
+ clock_gettime(CLOCK_MONOTONIC, &time);
+ bo->last_used = time.tv_sec;
+
+ /* Let's do some cleanup in the BO cache while we hold the
+ * lock.
+ */
+ panfrost_bo_cache_evict_stale_bos(screen);
pthread_mutex_unlock(&screen->bo_cache.lock);
return true;
@@ -276,8 +314,10 @@ panfrost_bo_cache_evict_all(
for (unsigned i = 0; i < ARRAY_SIZE(screen->bo_cache.buckets); ++i) {
struct list_head *bucket = &screen->bo_cache.buckets[i];
- list_for_each_entry_safe(struct panfrost_bo, entry, bucket, link) {
- list_del(&entry->link);
+ list_for_each_entry_safe(struct panfrost_bo, entry, bucket,
+ bucket_link) {
+ list_del(&entry->bucket_link);
+ list_del(&entry->lru_link);
panfrost_bo_free(entry);
}
}
diff --git a/src/gallium/drivers/panfrost/pan_bo.h b/src/gallium/drivers/panfrost/pan_bo.h
index 78e9b7526e0..414c356b95c 100644
--- a/src/gallium/drivers/panfrost/pan_bo.h
+++ b/src/gallium/drivers/panfrost/pan_bo.h
@@ -82,7 +82,15 @@ struct panfrost_screen;
struct panfrost_bo {
/* Must be first for casting */
- struct list_head link;
+ struct list_head bucket_link;
+
+ /* Used to link the BO to the BO cache LRU list. */
+ struct list_head lru_link;
+
+ /* Store the time this BO was use last, so the BO cache logic can evict
+ * stale BOs.
+ */
+ time_t last_used;
struct pipe_reference reference;
diff --git a/src/gallium/drivers/panfrost/pan_screen.c b/src/gallium/drivers/panfrost/pan_screen.c
index 9e98cf3375c..c9c50e4ef18 100644
--- a/src/gallium/drivers/panfrost/pan_screen.c
+++ b/src/gallium/drivers/panfrost/pan_screen.c
@@ -755,6 +755,7 @@ panfrost_create_screen(int fd, struct renderonly *ro)
panfrost_active_bos_cmp);
pthread_mutex_init(&screen->bo_cache.lock, NULL);
+ list_inithead(&screen->bo_cache.lru);
for (unsigned i = 0; i < ARRAY_SIZE(screen->bo_cache.buckets); ++i)
list_inithead(&screen->bo_cache.buckets[i]);
diff --git a/src/gallium/drivers/panfrost/pan_screen.h b/src/gallium/drivers/panfrost/pan_screen.h
index dde745fb0ed..c864629a372 100644
--- a/src/gallium/drivers/panfrost/pan_screen.h
+++ b/src/gallium/drivers/panfrost/pan_screen.h
@@ -92,6 +92,12 @@ struct panfrost_screen {
struct {
pthread_mutex_t lock;
+ /* List containing all cached BOs sorted in LRU (Least
+ * Recently Used) order. This allows us to quickly evict BOs
+ * that are more than 1 second old.
+ */
+ struct list_head lru;
+
/* The BO cache is a set of buckets with power-of-two sizes
* ranging from 2^12 (4096, the page size) to
* 2^(12 + MAX_BO_CACHE_BUCKETS).