Commit 06fbca71 authored by Chris Wilson's avatar Chris Wilson Committed by Daniel Vetter

drm/i915: Split the batch pool by engine

I woke up one morning and found 50k objects sitting in the batch pool
and every search seemed to iterate the entire list... Painting the
screen in oils would provide a more fluid display.

One issue with the current design is that we only check for retirements
on the current ring when preparing to submit a new batch. This means
that we can have thousands of "active" batches on another ring that we
have to walk over. The simplest way to avoid that is to split the pools
per ring and then our LRU execution ordering will also ensure that the
inactive buffers remain at the front.

v2: execlists still requires duplicate code.
v3: execlists requires more duplicate code
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: default avatarTvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent de4e783a
...@@ -377,13 +377,17 @@ static void print_batch_pool_stats(struct seq_file *m, ...@@ -377,13 +377,17 @@ static void print_batch_pool_stats(struct seq_file *m,
{ {
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj;
struct file_stats stats; struct file_stats stats;
struct intel_engine_cs *ring;
int i;
memset(&stats, 0, sizeof(stats)); memset(&stats, 0, sizeof(stats));
list_for_each_entry(obj, for_each_ring(ring, dev_priv, i) {
&dev_priv->mm.batch_pool.cache_list, list_for_each_entry(obj,
batch_pool_list) &ring->batch_pool.cache_list,
per_file_stats(0, obj, &stats); batch_pool_list)
per_file_stats(0, obj, &stats);
}
print_file_stats(m, "batch pool", stats); print_file_stats(m, "batch pool", stats);
} }
...@@ -613,21 +617,24 @@ static int i915_gem_batch_pool_info(struct seq_file *m, void *data) ...@@ -613,21 +617,24 @@ static int i915_gem_batch_pool_info(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev; struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj;
struct intel_engine_cs *ring;
int count = 0; int count = 0;
int ret; int ret, i;
ret = mutex_lock_interruptible(&dev->struct_mutex); ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret) if (ret)
return ret; return ret;
seq_puts(m, "cache:\n"); for_each_ring(ring, dev_priv, i) {
list_for_each_entry(obj, seq_printf(m, "%s cache:\n", ring->name);
&dev_priv->mm.batch_pool.cache_list, list_for_each_entry(obj,
batch_pool_list) { &ring->batch_pool.cache_list,
seq_puts(m, " "); batch_pool_list) {
describe_obj(m, obj); seq_puts(m, " ");
seq_putc(m, '\n'); describe_obj(m, obj);
count++; seq_putc(m, '\n');
count++;
}
} }
seq_printf(m, "total: %d\n", count); seq_printf(m, "total: %d\n", count);
......
...@@ -1072,7 +1072,6 @@ int i915_driver_unload(struct drm_device *dev) ...@@ -1072,7 +1072,6 @@ int i915_driver_unload(struct drm_device *dev)
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev); i915_gem_cleanup_ringbuffer(dev);
i915_gem_batch_pool_fini(&dev_priv->mm.batch_pool);
i915_gem_context_fini(dev); i915_gem_context_fini(dev);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
i915_gem_cleanup_stolen(dev); i915_gem_cleanup_stolen(dev);
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#include "intel_bios.h" #include "intel_bios.h"
#include "intel_ringbuffer.h" #include "intel_ringbuffer.h"
#include "intel_lrc.h" #include "intel_lrc.h"
#include "i915_gem_batch_pool.h"
#include "i915_gem_gtt.h" #include "i915_gem_gtt.h"
#include "i915_gem_render_state.h" #include "i915_gem_render_state.h"
#include <linux/io-mapping.h> #include <linux/io-mapping.h>
...@@ -1156,13 +1155,6 @@ struct i915_gem_mm { ...@@ -1156,13 +1155,6 @@ struct i915_gem_mm {
*/ */
struct list_head unbound_list; struct list_head unbound_list;
/*
* A pool of objects to use as shadow copies of client batch buffers
* when the command parser is enabled. Prevents the client from
* modifying the batch contents after software parsing.
*/
struct i915_gem_batch_pool batch_pool;
/** Usable portion of the GTT for GEM */ /** Usable portion of the GTT for GEM */
unsigned long stolen_base; /* limited to low memory (32-bit) */ unsigned long stolen_base; /* limited to low memory (32-bit) */
......
...@@ -5021,8 +5021,6 @@ i915_gem_load(struct drm_device *dev) ...@@ -5021,8 +5021,6 @@ i915_gem_load(struct drm_device *dev)
i915_gem_shrinker_init(dev_priv); i915_gem_shrinker_init(dev_priv);
i915_gem_batch_pool_init(dev, &dev_priv->mm.batch_pool);
mutex_init(&dev_priv->fb_tracking.lock); mutex_init(&dev_priv->fb_tracking.lock);
} }
......
...@@ -96,8 +96,9 @@ i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool, ...@@ -96,8 +96,9 @@ i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool,
list_for_each_entry_safe(tmp, next, list_for_each_entry_safe(tmp, next,
&pool->cache_list, batch_pool_list) { &pool->cache_list, batch_pool_list) {
/* The batches are strictly LRU ordered */
if (tmp->active) if (tmp->active)
continue; break;
/* While we're looping, do some clean up */ /* While we're looping, do some clean up */
if (tmp->madv == __I915_MADV_PURGED) { if (tmp->madv == __I915_MADV_PURGED) {
......
...@@ -1136,12 +1136,11 @@ i915_gem_execbuffer_parse(struct intel_engine_cs *ring, ...@@ -1136,12 +1136,11 @@ i915_gem_execbuffer_parse(struct intel_engine_cs *ring,
u32 batch_len, u32 batch_len,
bool is_master) bool is_master)
{ {
struct drm_i915_private *dev_priv = to_i915(batch_obj->base.dev);
struct drm_i915_gem_object *shadow_batch_obj; struct drm_i915_gem_object *shadow_batch_obj;
struct i915_vma *vma; struct i915_vma *vma;
int ret; int ret;
shadow_batch_obj = i915_gem_batch_pool_get(&dev_priv->mm.batch_pool, shadow_batch_obj = i915_gem_batch_pool_get(&ring->batch_pool,
PAGE_ALIGN(batch_len)); PAGE_ALIGN(batch_len));
if (IS_ERR(shadow_batch_obj)) if (IS_ERR(shadow_batch_obj))
return shadow_batch_obj; return shadow_batch_obj;
......
...@@ -1384,6 +1384,7 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *ring) ...@@ -1384,6 +1384,7 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
ring->cleanup(ring); ring->cleanup(ring);
i915_cmd_parser_fini_ring(ring); i915_cmd_parser_fini_ring(ring);
i915_gem_batch_pool_fini(&ring->batch_pool);
if (ring->status_page.obj) { if (ring->status_page.obj) {
kunmap(sg_page(ring->status_page.obj->pages->sgl)); kunmap(sg_page(ring->status_page.obj->pages->sgl));
...@@ -1401,6 +1402,7 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin ...@@ -1401,6 +1402,7 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
ring->dev = dev; ring->dev = dev;
INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->active_list);
INIT_LIST_HEAD(&ring->request_list); INIT_LIST_HEAD(&ring->request_list);
i915_gem_batch_pool_init(dev, &ring->batch_pool);
init_waitqueue_head(&ring->irq_queue); init_waitqueue_head(&ring->irq_queue);
INIT_LIST_HEAD(&ring->execlist_queue); INIT_LIST_HEAD(&ring->execlist_queue);
......
...@@ -1975,6 +1975,7 @@ static int intel_init_ring_buffer(struct drm_device *dev, ...@@ -1975,6 +1975,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->active_list);
INIT_LIST_HEAD(&ring->request_list); INIT_LIST_HEAD(&ring->request_list);
INIT_LIST_HEAD(&ring->execlist_queue); INIT_LIST_HEAD(&ring->execlist_queue);
i915_gem_batch_pool_init(dev, &ring->batch_pool);
ringbuf->size = 32 * PAGE_SIZE; ringbuf->size = 32 * PAGE_SIZE;
ringbuf->ring = ring; ringbuf->ring = ring;
memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno)); memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
...@@ -2053,6 +2054,7 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring) ...@@ -2053,6 +2054,7 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring)
cleanup_status_page(ring); cleanup_status_page(ring);
i915_cmd_parser_fini_ring(ring); i915_cmd_parser_fini_ring(ring);
i915_gem_batch_pool_fini(&ring->batch_pool);
kfree(ringbuf); kfree(ringbuf);
ring->buffer = NULL; ring->buffer = NULL;
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define _INTEL_RINGBUFFER_H_ #define _INTEL_RINGBUFFER_H_
#include <linux/hashtable.h> #include <linux/hashtable.h>
#include "i915_gem_batch_pool.h"
#define I915_CMD_HASH_ORDER 9 #define I915_CMD_HASH_ORDER 9
...@@ -133,6 +134,13 @@ struct intel_engine_cs { ...@@ -133,6 +134,13 @@ struct intel_engine_cs {
struct drm_device *dev; struct drm_device *dev;
struct intel_ringbuffer *buffer; struct intel_ringbuffer *buffer;
/*
* A pool of objects to use as shadow copies of client batch buffers
* when the command parser is enabled. Prevents the client from
* modifying the batch contents after software parsing.
*/
struct i915_gem_batch_pool batch_pool;
struct intel_hw_status_page status_page; struct intel_hw_status_page status_page;
unsigned irq_refcount; /* protected by dev_priv->irq_lock */ unsigned irq_refcount; /* protected by dev_priv->irq_lock */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment