diff mbox

[32/34] drm: Apply tight eviction scanning to color_adjust

Message ID 20161212115350.780-33-chris@chris-wilson.co.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Chris Wilson Dec. 12, 2016, 11:53 a.m. UTC
Using mm->color_adjust makes the eviction scanner much tricker since we
don't know the actual neighbours of the target hole until after it is
created (after scanning is complete). To work out whether we need to
evict the neighbours because they impact upon the hole, we have to then
check the hole afterwards - requiring an extra step in the user of the
eviction scanner when they apply color_adjust.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/drm_mm.c                | 46 +++++++++++++++++++++------------
 drivers/gpu/drm/i915/i915_gem_evict.c   |  6 +++++
 drivers/gpu/drm/selftests/test-drm_mm.c | 20 ++++++++++++++
 include/drm/drm_mm.h                    |  1 +
 4 files changed, 56 insertions(+), 17 deletions(-)

Comments

Joonas Lahtinen Dec. 13, 2016, 4:03 p.m. UTC | #1
On ma, 2016-12-12 at 11:53 +0000, Chris Wilson wrote:
> Using mm->color_adjust makes the eviction scanner much tricker since we
> don't know the actual neighbours of the target hole until after it is
> created (after scanning is complete). To work out whether we need to
> evict the neighbours because they impact upon the hole, we have to then
> check the hole afterwards - requiring an extra step in the user of the
> eviction scanner when they apply color_adjust.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

<SNIP>

> @@ -887,6 +872,33 @@ bool drm_mm_scan_remove_block(struct drm_mm_scan *scan,
>  }
>  EXPORT_SYMBOL(drm_mm_scan_remove_block);
>  
> +struct drm_mm_node *drm_mm_scan_color_evict(struct drm_mm_scan *scan)
> +

Kerneldoc so I can verify this function makes sense.

> diff --git a/drivers/gpu/drm/selftests/test-drm_mm.c b/drivers/gpu/drm/selftests/test-drm_mm.c
> index 09ead31a094d..73353f87f46a 100644
> --- a/drivers/gpu/drm/selftests/test-drm_mm.c
> +++ b/drivers/gpu/drm/selftests/test-drm_mm.c

Use helper func in this file?

Regards, Joonas
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index ba1a244fe6e5..b061066066d8 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -823,23 +823,8 @@  bool drm_mm_scan_add_block(struct drm_mm_scan *scan,
 		}
 	}
 
-	if (mm->color_adjust) {
-		/* If allocations need adjusting due to neighbouring colours,
-		 * we do not have enough information to decide if we need
-		 * to evict nodes on either side of [adj_start, adj_end].
-		 * What almost works is
-		 * hit_start = adj_start + (hole_start - col_start);
-		 * hit_end = adj_start + scan->size + (hole_end - col_end);
-		 * but because the decision is only made on the final hole,
-		 * we may underestimate the required adjustments for an
-		 * interior allocation.
-		 */
-		scan->hit_start = hole_start;
-		scan->hit_end = hole_end;
-	} else {
-		scan->hit_start = adj_start;
-		scan->hit_end = adj_start + scan->size;
-	}
+	scan->hit_start = adj_start;
+	scan->hit_end = adj_start + scan->size;
 
 	DRM_MM_BUG_ON(scan->hit_start >= scan->hit_end);
 	DRM_MM_BUG_ON(scan->hit_start < hole_start);
@@ -887,6 +872,33 @@  bool drm_mm_scan_remove_block(struct drm_mm_scan *scan,
 }
 EXPORT_SYMBOL(drm_mm_scan_remove_block);
 
+struct drm_mm_node *drm_mm_scan_color_evict(struct drm_mm_scan *scan)
+{
+	struct drm_mm *mm = scan->mm;
+	struct drm_mm_node *hole;
+	u64 hole_start, hole_end;
+
+	if (!mm->color_adjust)
+		return NULL;
+
+	hole = list_first_entry(&mm->hole_stack, typeof(*hole), hole_stack);
+
+	hole_start = __drm_mm_hole_node_start(hole);
+	hole_end = __drm_mm_hole_node_end(hole);
+
+	DRM_MM_BUG_ON(hole_start > scan->hit_start);
+	DRM_MM_BUG_ON(hole_end < scan->hit_end);
+
+	mm->color_adjust(hole, scan->color, &hole_start, &hole_end);
+	if (hole_start > scan->hit_start)
+		return hole;
+	if (hole_end < scan->hit_end)
+		return list_next_entry(hole, node_list);
+
+	return NULL;
+}
+EXPORT_SYMBOL(drm_mm_scan_color_evict);
+
 /**
  * drm_mm_init - initialize a drm-mm allocator
  * @mm: the drm_mm structure to initialize
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index 89da9225043f..e4987e354311 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -108,6 +108,7 @@  i915_gem_evict_something(struct i915_address_space *vm,
 		NULL,
 	}, **phase;
 	struct i915_vma *vma, *next;
+	struct drm_mm_node *node;
 	int ret;
 
 	lockdep_assert_held(&vm->i915->drm.struct_mutex);
@@ -212,6 +213,11 @@  i915_gem_evict_something(struct i915_address_space *vm,
 			ret = i915_vma_unbind(vma);
 	}
 
+	while (ret == 0 && (node = drm_mm_scan_color_evict(&scan))) {
+		vma = container_of(node, struct i915_vma, node);
+		ret = i915_vma_unbind(vma);
+	}
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/selftests/test-drm_mm.c b/drivers/gpu/drm/selftests/test-drm_mm.c
index 09ead31a094d..73353f87f46a 100644
--- a/drivers/gpu/drm/selftests/test-drm_mm.c
+++ b/drivers/gpu/drm/selftests/test-drm_mm.c
@@ -1662,6 +1662,11 @@  static int igt_color_evict(void *ignored)
 
 		list_for_each_entry(e, &evict_list, link)
 			drm_mm_remove_node(&e->node);
+		while ((node = drm_mm_scan_color_evict(&scan))) {
+			e = container_of(node, struct evict_node, node);
+			drm_mm_remove_node(&e->node);
+			list_add(&e->link, &evict_list);
+		}
 
 		memset(&tmp, 0, sizeof(tmp));
 		err = drm_mm_insert_node_generic(&mm, &tmp, nsize, n, c,
@@ -1735,6 +1740,11 @@  static int igt_color_evict(void *ignored)
 
 		list_for_each_entry(e, &evict_list, link)
 			drm_mm_remove_node(&e->node);
+		while ((node = drm_mm_scan_color_evict(&scan))) {
+			e = container_of(node, struct evict_node, node);
+			drm_mm_remove_node(&e->node);
+			list_add(&e->link, &evict_list);
+		}
 
 		memset(&tmp, 0, sizeof(tmp));
 		err = drm_mm_insert_node_generic(&mm, &tmp, nsize, n, c,
@@ -1867,6 +1877,11 @@  static int igt_color_evict_range(void *ignored)
 
 		list_for_each_entry(e, &evict_list, link)
 			drm_mm_remove_node(&e->node);
+		while ((node = drm_mm_scan_color_evict(&scan))) {
+			e = container_of(node, struct evict_node, node);
+			drm_mm_remove_node(&e->node);
+			list_add(&e->link, &evict_list);
+		}
 
 		memset(&tmp, 0, sizeof(tmp));
 		err = drm_mm_insert_node_in_range_generic(&mm, &tmp, nsize, n, c,
@@ -1943,6 +1958,11 @@  static int igt_color_evict_range(void *ignored)
 
 		list_for_each_entry(e, &evict_list, link)
 			drm_mm_remove_node(&e->node);
+		while ((node = drm_mm_scan_color_evict(&scan))) {
+			e = container_of(node, struct evict_node, node);
+			drm_mm_remove_node(&e->node);
+			list_add(&e->link, &evict_list);
+		}
 
 		memset(&tmp, 0, sizeof(tmp));
 		err = drm_mm_insert_node_in_range_generic(&mm, &tmp, nsize, n, c,
diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h
index 4ff76d0ab849..884166b91e90 100644
--- a/include/drm/drm_mm.h
+++ b/include/drm/drm_mm.h
@@ -403,6 +403,7 @@  bool drm_mm_scan_add_block(struct drm_mm_scan *scan,
 			   struct drm_mm_node *node);
 bool drm_mm_scan_remove_block(struct drm_mm_scan *scan,
 			      struct drm_mm_node *node);
+struct drm_mm_node *drm_mm_scan_color_evict(struct drm_mm_scan *scan);
 
 void drm_mm_debug_table(const struct drm_mm *mm, const char *prefix);
 #ifdef CONFIG_DEBUG_FS