[Intel-gfx] [PATCH v6 1/5] drm/i915: Implement a framework for batch buffer pools
Michael H. Nguyen
michael.h.nguyen at intel.com
Wed Dec 10 08:33:50 PST 2014
Hi Jon,
On 12/10/2014 03:06 AM, Bloomfield, Jon wrote:
>> -----Original Message-----
>> From: Intel-gfx [mailto:intel-gfx-bounces at lists.freedesktop.org] On Behalf
>> Of Daniel Vetter
>> Sent: Tuesday, December 09, 2014 1:18 PM
>> To: Nguyen, Michael H
>> Cc: Brad Volkin; intel-gfx at lists.freedesktop.org
>> Subject: Re: [Intel-gfx] [PATCH v6 1/5] drm/i915: Implement a framework for
>> batch buffer pools
>>
>> On Mon, Dec 08, 2014 at 02:33:46PM -0800, michael.h.nguyen at intel.com
>> wrote:
>>> From: Brad Volkin <bradley.d.volkin at intel.com>
>>>
>>> This adds a small module for managing a pool of batch buffers.
>>> The only current use case is for the command parser, as described in
>>> the kerneldoc in the patch. The code is simple, but separating it out
>>> makes it easier to change the underlying algorithms and to extend to
>>> future use cases should they arise.
>>>
>>> The interface is simple: init to create an empty pool, fini to clean
>>> it up, get to obtain a new buffer. Note that all buffers are expected
>>> to be inactive before cleaning up the pool.
>>>
>>> Locking is currently based on the caller holding the struct_mutex.
>>> We already do that in the places where we will use the batch pool for
>>> the command parser.
>>>
>>> v2:
>>> - s/BUG_ON/WARN_ON/ for locking assertions
>>> - Remove the cap on pool size
>>> - Switch from alloc/free to init/fini
>>>
>>> v3:
>>> - Idiomatic looping structure in _fini
>>> - Correct handling of purged objects
>>> - Don't return a buffer that's too much larger than needed
>>>
>>> v4:
>>> - Rebased to latest -nightly
>>>
>>> v5:
>>> - Remove _put() function and clean up comments to match
>>>
>>> v6:
>>> - Move purged check inside the loop (danvet, from v4 1/7 feedback)
>>>
>>> v7:
>>> - Use single list instead of two. (Chris W)
>>> - s/active_list/cache_list
>>> - Squashed in debug patches (Chris W)
>>> drm/i915: Add a batch pool debugfs file
>>>
>>> It provides some useful information about the buffers in
>>> the global command parser batch pool.
>>>
>>> v2: rebase on global pool instead of per-ring pools
>>> v3: rebase
>>>
>>> drm/i915: Add batch pool details to i915_gem_objects debugfs
>>>
>>> To better account for the potentially large memory consumption
>>> of the batch pool.
>>>
>>> Issue: VIZ-4719
>>> Signed-off-by: Brad Volkin <bradley.d.volkin at intel.com>
>>> ---
>>> Documentation/DocBook/drm.tmpl | 5 ++
>>> drivers/gpu/drm/i915/Makefile | 1 +
>>> drivers/gpu/drm/i915/i915_debugfs.c | 71 ++++++++++++++--
>>> drivers/gpu/drm/i915/i915_drv.h | 21 +++++
>>> drivers/gpu/drm/i915/i915_gem.c | 1 +
>>> drivers/gpu/drm/i915/i915_gem_batch_pool.c | 132
>>> +++++++++++++++++++++++++++++
>>> 6 files changed, 222 insertions(+), 9 deletions(-) create mode
>>> 100644 drivers/gpu/drm/i915/i915_gem_batch_pool.c
>>>
>>> diff --git a/Documentation/DocBook/drm.tmpl
>>> b/Documentation/DocBook/drm.tmpl index 85287cb..022923a 100644
>>> --- a/Documentation/DocBook/drm.tmpl
>>> +++ b/Documentation/DocBook/drm.tmpl
>>> @@ -4029,6 +4029,11 @@ int num_ioctls;</synopsis>
>>> !Idrivers/gpu/drm/i915/i915_cmd_parser.c
>>> </sect2>
>>> <sect2>
>>> + <title>Batchbuffer Pools</title>
>>> +!Pdrivers/gpu/drm/i915/i915_gem_batch_pool.c batch pool
>>> +!Idrivers/gpu/drm/i915/i915_gem_batch_pool.c
>>> + </sect2>
>>> + <sect2>
>>> <title>Logical Rings, Logical Ring Contexts and
>>> Execlists</title> !Pdrivers/gpu/drm/i915/intel_lrc.c Logical Rings,
>>> Logical Ring Contexts and Execlists
>>> !Idrivers/gpu/drm/i915/intel_lrc.c
>>> diff --git a/drivers/gpu/drm/i915/Makefile
>>> b/drivers/gpu/drm/i915/Makefile index e4083e4..c8dbb37d 100644
>>> --- a/drivers/gpu/drm/i915/Makefile
>>> +++ b/drivers/gpu/drm/i915/Makefile
>>> @@ -19,6 +19,7 @@ i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o
>>>
>>> # GEM code
>>> i915-y += i915_cmd_parser.o \
>>> + i915_gem_batch_pool.o \
>>> i915_gem_context.o \
>>> i915_gem_render_state.o \
>>> i915_gem_debug.o \
>>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c
>>> b/drivers/gpu/drm/i915/i915_debugfs.c
>>> index d0e445e..3c3bf98 100644
>>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>>> @@ -359,6 +359,33 @@ static int per_file_stats(int id, void *ptr, void
>> *data)
>>> return 0;
>>> }
>>>
>>> +#define print_file_stats(m, name, stats) \
>>> + seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive,
>> %zu global, %zu shared, %zu unbound)\n", \
>>> + name, \
>>> + stats.count, \
>>> + stats.total, \
>>> + stats.active, \
>>> + stats.inactive, \
>>> + stats.global, \
>>> + stats.shared, \
>>> + stats.unbound)
>
> "print_file_stats" might be better named "print_obj_stats" or similar. As it stands
> there is nothing in its name to suggest its purpose is to describe an object.
I guess the fnc name 'print_file_stats' was chosen b/c it takes a
'stats' parameter of type 'struct file_stats' and prints the members.
Seems fair to leave it I think as its generic.
>
>
>>> +
>>> +static void print_batch_pool_stats(struct seq_file *m,
>>> + struct drm_i915_private *dev_priv) {
>>> + struct drm_i915_gem_object *obj;
>>> + struct file_stats stats;
>>> +
>>> + memset(&stats, 0, sizeof(stats));
>>> +
>>> + list_for_each_entry(obj,
>>> + &dev_priv->mm.batch_pool.cache_list,
>>> + batch_pool_list)
>>> + per_file_stats(0, obj, &stats);
>
> Shouldn't we be holding the batch_pool lock here ?
Think we're okay here. The callers of print_batch_pool_stats() hold
dev->struct_mutex.
Thanks,
-Mike
>
>
>>> +
>>> + print_file_stats(m, "batch pool", stats); }
>>> +
>>> #define count_vmas(list, member) do { \
>>> list_for_each_entry(vma, list, member) { \
>>> size += i915_gem_obj_ggtt_size(vma->obj); \ @@ -441,6
>> +468,9 @@
>>> static int i915_gem_object_info(struct seq_file *m, void* data)
>>> dev_priv->gtt.mappable_end - dev_priv->gtt.base.start);
>>>
>>> seq_putc(m, '\n');
>>> + print_batch_pool_stats(m, dev_priv);
>>> +
>>> + seq_putc(m, '\n');
>>> list_for_each_entry_reverse(file, &dev->filelist, lhead) {
>>> struct file_stats stats;
>>> struct task_struct *task;
>>> @@ -458,15 +488,7 @@ static int i915_gem_object_info(struct seq_file *m,
>> void* data)
>>> */
>>> rcu_read_lock();
>>> task = pid_task(file->pid, PIDTYPE_PID);
>>> - seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu
>> inactive, %zu global, %zu shared, %zu unbound)\n",
>>> - task ? task->comm : "<unknown>",
>>> - stats.count,
>>> - stats.total,
>>> - stats.active,
>>> - stats.inactive,
>>> - stats.global,
>>> - stats.shared,
>>> - stats.unbound);
>>> + print_file_stats(m, task ? task->comm : "<unknown>", stats);
>>> rcu_read_unlock();
>>> }
>>>
>>> @@ -583,6 +605,36 @@ static int i915_gem_pageflip_info(struct seq_file
>> *m, void *data)
>>> return 0;
>>> }
>>>
>>> +static int i915_gem_batch_pool_info(struct seq_file *m, void *data) {
>>> + struct drm_info_node *node = m->private;
>>> + struct drm_device *dev = node->minor->dev;
>>> + struct drm_i915_private *dev_priv = dev->dev_private;
>>> + struct drm_i915_gem_object *obj;
>>> + int count = 0;
>>> + int ret;
>>> +
>>> + ret = mutex_lock_interruptible(&dev->struct_mutex);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + seq_puts(m, "cache:\n");
>>> + list_for_each_entry(obj,
>>> + &dev_priv->mm.batch_pool.cache_list,
>>> + batch_pool_list) {
>>> + seq_puts(m, " ");
>>> + describe_obj(m, obj);
>>> + seq_putc(m, '\n');
>>> + count++;
>>> + }
>>> +
>>> + seq_printf(m, "total: %d\n", count);
>>> +
>>> + mutex_unlock(&dev->struct_mutex);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> static int i915_gem_request_info(struct seq_file *m, void *data) {
>>> struct drm_info_node *node = m->private; @@ -4324,6 +4376,7 @@
>>> static const struct drm_info_list i915_debugfs_list[] = {
>>> {"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS},
>>> {"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS},
>>> {"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS},
>>> + {"i915_gem_batch_pool", i915_gem_batch_pool_info, 0},
>>> {"i915_frequency_info", i915_frequency_info, 0},
>>> {"i915_drpc_info", i915_drpc_info, 0},
>>> {"i915_emon_status", i915_emon_status, 0}, diff --git
>>> a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
>>> index 11e85cb..f3e27e9 100644
>>> --- a/drivers/gpu/drm/i915/i915_drv.h
>>> +++ b/drivers/gpu/drm/i915/i915_drv.h
>>> @@ -1129,6 +1129,11 @@ struct intel_l3_parity {
>>> int which_slice;
>>> };
>>>
>>> +struct i915_gem_batch_pool {
>>> + struct drm_device *dev;
>>> + struct list_head cache_list;
>>> +};
>>> +
>>> struct i915_gem_mm {
>>> /** Memory allocator for GTT stolen memory */
>>> struct drm_mm stolen;
>>> @@ -1142,6 +1147,13 @@ struct i915_gem_mm {
>>> */
>>> 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 */
>>> unsigned long stolen_base; /* limited to low memory (32-bit) */
>>>
>>> @@ -1872,6 +1884,8 @@ struct drm_i915_gem_object {
>>> /** Used in execbuf to temporarily hold a ref */
>>> struct list_head obj_exec_link;
>>>
>>> + struct list_head batch_pool_list;
>>> +
>>> /**
>>> * This is set if the object is on the active lists (has pending
>>> * rendering and so a non-zero seqno), and is not set if it i s on
>>> @@ -2876,6 +2890,13 @@ void i915_destroy_error_state(struct
>> drm_device
>>> *dev); void i915_get_extra_instdone(struct drm_device *dev, uint32_t
>>> *instdone); const char *i915_cache_level_str(struct drm_i915_private
>>> *i915, int type);
>>>
>>> +/* i915_gem_batch_pool.c */
>>> +void i915_gem_batch_pool_init(struct drm_device *dev,
>>> + struct i915_gem_batch_pool *pool); void
>>> +i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool); struct
>>> +drm_i915_gem_object* i915_gem_batch_pool_get(struct
>>> +i915_gem_batch_pool *pool, size_t size);
>>> +
>>> /* i915_cmd_parser.c */
>>> int i915_cmd_parser_get_version(void);
>>> int i915_cmd_parser_init_ring(struct intel_engine_cs *ring); diff
>>> --git a/drivers/gpu/drm/i915/i915_gem.c
>>> b/drivers/gpu/drm/i915/i915_gem.c index de241eb..2f14ae1 100644
>>> --- a/drivers/gpu/drm/i915/i915_gem.c
>>> +++ b/drivers/gpu/drm/i915/i915_gem.c
>>> @@ -4384,6 +4384,7 @@ void i915_gem_object_init(struct
>> drm_i915_gem_object *obj,
>>> INIT_LIST_HEAD(&obj->ring_list);
>>> INIT_LIST_HEAD(&obj->obj_exec_link);
>>> INIT_LIST_HEAD(&obj->vma_list);
>>> + INIT_LIST_HEAD(&obj->batch_pool_list);
>>>
>>> obj->ops = ops;
>>>
>>> diff --git a/drivers/gpu/drm/i915/i915_gem_batch_pool.c
>>> b/drivers/gpu/drm/i915/i915_gem_batch_pool.c
>>> new file mode 100644
>>> index 0000000..e9349e3
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/i915/i915_gem_batch_pool.c
>>> @@ -0,0 +1,132 @@
>>> +/*
>>> + * Copyright © 2014 Intel Corporation
>>> + *
>>> + * Permission is hereby granted, free of charge, to any person
>>> +obtaining a
>>> + * copy of this software and associated documentation files (the
>>> +"Software"),
>>> + * to deal in the Software without restriction, including without
>>> +limitation
>>> + * the rights to use, copy, modify, merge, publish, distribute,
>>> +sublicense,
>>> + * and/or sell copies of the Software, and to permit persons to whom
>>> +the
>>> + * Software is furnished to do so, subject to the following conditions:
>>> + *
>>> + * The above copyright notice and this permission notice (including
>>> +the next
>>> + * paragraph) shall be included in all copies or substantial portions
>>> +of the
>>> + * Software.
>>> + *
>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
>> KIND,
>>> +EXPRESS OR
>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>> +MERCHANTABILITY,
>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
>> NO EVENT
>>> +SHALL
>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
>> DAMAGES
>>> +OR OTHER
>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
>> OTHERWISE,
>>> +ARISING
>>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
>> OR
>>> +OTHER DEALINGS
>>> + * IN THE SOFTWARE.
>>> + *
>>> + */
>>> +
>>> +#include "i915_drv.h"
>>> +
>>> +/**
>>> + * DOC: batch pool
>>> + *
>>> + * In order to submit batch buffers as 'secure', the software command
>>> +parser
>>> + * must ensure that a batch buffer cannot be modified after parsing.
>>> +It does
>>> + * this by copying the user provided batch buffer contents to a
>>> +kernel owned
>>> + * buffer from which the hardware will actually execute, and by
>>> +carefully
>>> + * managing the address space bindings for such buffers.
>>> + *
>>> + * The batch pool framework provides a mechanism for the driver to
>>> +manage a
>>> + * set of scratch buffers to use for this purpose. The framework can
>>> +be
>>> + * extended to support other uses cases should they arise.
>>> + */
>>> +
>>> +/**
>>> + * i915_gem_batch_pool_init() - initialize a batch buffer pool
>>> + * @dev: the drm device
>>> + * @pool: the batch buffer pool
>>> + */
>>> +void i915_gem_batch_pool_init(struct drm_device *dev,
>>> + struct i915_gem_batch_pool *pool) {
>>> + pool->dev = dev;
>>> + INIT_LIST_HEAD(&pool->cache_list);
>>> +}
>>> +
>>> +/**
>>> + * i915_gem_batch_pool_fini() - clean up a batch buffer pool
>>> + * @pool: the pool to clean up
>>> + *
>>> + * Note: Callers must hold the struct_mutex.
>>> + */
>>> +void i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool) {
>>> + WARN_ON(!mutex_is_locked(&pool->dev->struct_mutex));
>>> +
>>> + while (!list_empty(&pool->cache_list)) {
>>> + struct drm_i915_gem_object *obj =
>>> + list_first_entry(&pool->cache_list,
>>> + struct drm_i915_gem_object,
>>> + batch_pool_list);
>>> +
>>> + WARN_ON(obj->active);
>>> +
>>> + list_del_init(&obj->batch_pool_list);
>>> + drm_gem_object_unreference(&obj->base);
>>> + }
>>> +}
>>> +
>>> +/**
>>> + * i915_gem_batch_pool_get() - select a buffer from the pool
>>> + * @pool: the batch buffer pool
>>> + * @size: the minimum desired size of the returned buffer
>>> + *
>>> + * Finds or allocates a batch buffer in the pool with at least the
>>> +requested
>>> + * size. The caller is responsible for any domain, active/inactive,
>>> +or
>>> + * purgeability management for the returned buffer.
>>> + *
>>> + * Note: Callers must hold the struct_mutex
>>> + *
>>> + * Return: the selected batch buffer object */ struct
>>> +drm_i915_gem_object * i915_gem_batch_pool_get(struct
>>> +i915_gem_batch_pool *pool,
>>> + size_t size)
>>> +{
>>> + struct drm_i915_gem_object *obj = NULL;
>>> + struct drm_i915_gem_object *tmp, *next;
>>> +
>>> + WARN_ON(!mutex_is_locked(&pool->dev->struct_mutex));
>>> +
>>> + list_for_each_entry_safe(tmp, next,
>>> + &pool->cache_list, batch_pool_list) {
>>> +
>>> + if (tmp->active)
>>> + continue;
>>> +
>>> + /* While we're looping, do some clean up */
>>> + if (tmp->madv == __I915_MADV_PURGED) {
>>> + list_del(&tmp->batch_pool_list);
>>> + drm_gem_object_unreference(&tmp->base);
>>> + continue;
>>> + }
>>> +
>>> + /*
>>> + * Select a buffer that is at least as big as needed
>>> + * but not 'too much' bigger. A better way to do this
>>> + * might be to bucket the pool objects based on size.
>>> + */
>>> + if (tmp->base.size >= size &&
>>> + tmp->base.size <= (2 * size)) {
>>> + obj = tmp;
>>> + break;
>>> + }
>>> + }
>>> +
>>> + if (!obj) {
>>> + obj = i915_gem_alloc_object(pool->dev, size);
>>> + if (!obj)
>>> + return ERR_PTR(-ENOMEM);
>>> +
>>> + list_add_tail(&obj->batch_pool_list, &pool->cache_list);
>>> + }
>>
>> Shouldn't we have a else list_move_tail here to keep the list in lru order?
>> -Daniel
>>
>>> +
>>> + return obj;
>>> +}
>>> --
>>> 1.9.1
>>>
>>> _______________________________________________
>>> Intel-gfx mailing list
>>> Intel-gfx at lists.freedesktop.org
>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>
>> --
>> Daniel Vetter
>> Software Engineer, Intel Corporation
>> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
More information about the Intel-gfx
mailing list