On Wed, Jun 18, 2014 at 10:49:05AM -0700, Volkin, Bradley D wrote: > On Wed, Jun 18, 2014 at 09:52:52AM -0700, Chris Wilson wrote: > > On Wed, Jun 18, 2014 at 09:36:14AM -0700, bradley.d.vol...@intel.com wrote: > > > From: Brad Volkin <bradley.d.vol...@intel.com> > > > > > > This patch sets up all of the tracking and copying necessary to > > > use batch pools with the command parser, but does not actually > > > dispatch the copied (shadow) batch to the hardware yet. We still > > > aren't quite ready to set the secure bit during dispatch. > > > > > > Note that performance takes a hit from the copy in some cases > > > and will likely need some work. At a rough pass, the memcpy > > > appears to be the bottleneck. Without having done a deeper > > > analysis, two ideas that come to mind are: > > > 1) Copy sections of the batch at a time, as they are reached > > > by parsing. Might improve cache locality. > > > 2) Copy only up to the userspace-supplied batch length and > > > memset the rest of the buffer. Reduces the number of reads. > > > > > > Signed-off-by: Brad Volkin <bradley.d.vol...@intel.com> > > > --- > > > drivers/gpu/drm/i915/i915_cmd_parser.c | 75 > > > ++++++++++++++++++++++------ > > > drivers/gpu/drm/i915/i915_drv.h | 7 ++- > > > drivers/gpu/drm/i915/i915_gem.c | 8 ++- > > > drivers/gpu/drm/i915/i915_gem_execbuffer.c | 45 +++++++++++++++-- > > > drivers/gpu/drm/i915/i915_gem_render_state.c | 2 +- > > > drivers/gpu/drm/i915/intel_ringbuffer.c | 12 +++++ > > > drivers/gpu/drm/i915/intel_ringbuffer.h | 7 +++ > > > 7 files changed, 134 insertions(+), 22 deletions(-) > > > > > > diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c > > > b/drivers/gpu/drm/i915/i915_cmd_parser.c > > > index dea99d9..669afb0 100644 > > > --- a/drivers/gpu/drm/i915/i915_cmd_parser.c > > > +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c > > > @@ -831,6 +831,53 @@ finish: > > > return (u32*)addr; > > > } > > > > > > +/* Returns a vmap'd pointer to dest_obj, which the caller must unmap */ > > > +static u32 *copy_batch(struct drm_i915_gem_object *dest_obj, > > > + struct drm_i915_gem_object *src_obj) > > > +{ > > > + int ret = 0; > > > + int needs_clflush = 0; > > > + u32 *src_addr, *dest_addr = NULL; > > > + > > > + ret = i915_gem_obj_prepare_shmem_read(src_obj, &needs_clflush); > > > + if (ret) { > > > + DRM_DEBUG_DRIVER("CMD: failed to prep read\n"); > > > + return ERR_PTR(ret); > > > + } > > > + > > > + src_addr = vmap_batch(src_obj); > > > + if (!src_addr) { > > > + DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n"); > > > + ret = -ENOMEM; > > > + goto unpin_src; > > > + } > > > + > > > + if (needs_clflush) > > > + drm_clflush_virt_range((char *)src_addr, src_obj->base.size); > > > + > > > + ret = i915_gem_object_set_to_cpu_domain(dest_obj, true); > > > + if (ret) { > > > + DRM_DEBUG_DRIVER("CMD: Failed to set batch CPU domain\n"); > > > + goto unmap_src; > > > + } > > > + > > > + dest_addr = vmap_batch(dest_obj); > > > + if (!dest_addr) { > > > + DRM_DEBUG_DRIVER("CMD: Failed to vmap shadow batch\n"); > > > + ret = -ENOMEM; > > > + goto unmap_src; > > > + } > > > + > > > + memcpy(dest_addr, src_addr, src_obj->base.size); > > > + > > > +unmap_src: > > > + vunmap(src_addr); > > > +unpin_src: > > > + i915_gem_object_unpin_pages(src_obj); > > > + > > > + return ret ? ERR_PTR(ret) : dest_addr; > > > +} > > > > src_obj->size? You should perhaps borrow a byt. > > Not sure I completely follow you here. The dest_obj is as big or bigger than > the source, so I think copying only as much data as exists in the source > object is right. I should be writing nops into any extra space though. And in > parse_cmds, I should update the batch_end calculation. Were those the issues > that you saw?
Just that generally src->size >> batch len and clflush will make it twice as expensive on byt. (The object may be about 1000 times larger than the batch at the extreme, libva *cough*.) > > > static int > > > @@ -1087,6 +1088,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void > > > *data, > > > struct drm_i915_private *dev_priv = dev->dev_private; > > > struct eb_vmas *eb; > > > struct drm_i915_gem_object *batch_obj; > > > + struct drm_i915_gem_object *shadow_batch_obj = NULL; > > > struct drm_clip_rect *cliprects = NULL; > > > struct intel_engine_cs *ring; > > > struct intel_context *ctx; > > > @@ -1288,8 +1290,31 @@ i915_gem_do_execbuffer(struct drm_device *dev, > > > void *data, > > > batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND; > > > > > > if (i915_needs_cmd_parser(ring)) { > > > + shadow_batch_obj = > > > + i915_gem_batch_pool_get(ring->batch_pool, > > > + batch_obj->base.size); > > > + if (IS_ERR(shadow_batch_obj)) { > > > + ret = PTR_ERR(shadow_batch_obj); > > > + /* Don't try to clean up the obj in the error path */ > > > + shadow_batch_obj = NULL; > > > + > > > + /* > > > + * If the pool is at capcity, retiring requests might > > > + * return some buffers. > > > + */ > > > + if (ret == -EAGAIN) > > > + i915_gem_retire_requests_ring(ring); > > > + > > > + goto err; > > > + } > > > + > > > + ret = i915_gem_obj_ggtt_pin(shadow_batch_obj, 4096, 0); > > > + if (ret) > > > + goto err; > > > + > > > ret = i915_parse_cmds(ring, > > > batch_obj, > > > + shadow_batch_obj, > > > args->batch_start_offset, > > > file->is_master); > > > > You could just allocate the shadow inside parse_cmds and return it. Then > > replace the conventional batch_boj with the new pointer and add it to > > the eb list. Similarly, you do not need to track shadow_batch_obj > > explicitly in the requests, the pool can do its own busy tracking > > external to the core and reduce the invasiveness of the patch. > > Overall, I agree that this touched more places than I would have liked. > > I initially thought about replacing batch_obj and hooking into the eb list, > but that seemed like it would involve trickier code w.r.t. ref counting, > making up an exec_entry for the vma, etc. Not the end of the world, but > it felt less obvious. I can look again though if you think it's worth it. I think so. The request is already complicated enough and I think the shadow batch can fit neatly inside the rules we already have with a modicum of stitching here. > What specifically are you thinking in terms of implementing busy tracking > in the pool? The idea with adding the shadow object to the request was just > to get it back in the pool and purgeable asap. I also thought it would limit > some additional code given that we know buffers in the pool have had any > pending work completed. Maybe the suggested approach would do a better job > of those things though. I was thinking that a pool is basically a list of bo, and you simply query whether the oldest was still busy when we need a new bo. Which is the same as how userspace implements its pool of active/inactive objects. > > > diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h > > > b/drivers/gpu/drm/i915/intel_ringbuffer.h > > > index e72017b..82aae29 100644 > > > --- a/drivers/gpu/drm/i915/intel_ringbuffer.h > > > +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h > > > @@ -188,6 +188,13 @@ struct intel_engine_cs { > > > bool needs_cmd_parser; > > > > > > /* > > > + * 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; > > > > Why are they tied to a ring? > > There was a question as to whether to make a global pool or per-ring > pools way back when I first sent the parser series. Daniel expressed > a slight preference for per-ring, but I don't object to a global pool. > I suppose a potential benefit to per-ring would be if userspace uses > different sized buffers on different rings, we'd more easily find a > suitable buffer. But enhancing the pool management could fix that too. Batch buffer sizes are not fixed per ring anyway. I guess Daniel thought it might work out easier, but memory is a global resource and should be tracked primarily at the device level. Userspace segregates its caches based on size to speed up searches. -Chris -- Chris Wilson, Intel Open Source Technology Centre _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx