[Mesa-dev] [PATCH 5/5] i965/query: Cache whether the batch references the query BO.
Ben Widawsky
ben at bwidawsk.net
Mon Dec 15 13:38:47 PST 2014
On Mon, Dec 15, 2014 at 01:28:52PM -0800, Ian Romanick wrote:
> On 12/14/2014 04:39 PM, Ben Widawsky wrote:
> > On Fri, Dec 12, 2014 at 11:15:42PM -0800, Kenneth Graunke wrote:
> >> Chris Wilson noted that repeated calls to CheckQuery() would call
> >> drm_intel_bo_references(brw->batch.bo, query->bo) on each invocation,
> >> which is expensive. Once we've flushed, we know that future batches
> >> won't reference query->bo, so there's no point in asking more than once.
> >>
> >> This patch adds a brw_query_object::flushed flag, which is a
> >> conservative estimate of whether the batch has been flushed.
> >>
> >> On the first call to CheckQuery() or WaitQuery(), we check if the
> >> batch references query->bo. If not, it must have been flushed for
> >> some reason (such as being full). We record that it was flushed.
> >> If it does reference query->bo, we explicitly flush, and record that
> >> we did so.
> >>
> >> Any subsequent checks will simply see that query->flushed is set,
> >> and skip the drm_intel_bo_references() call.
> >>
> >> Inspired by a patch from Chris Wilson.
> >>
> >> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=86969
> >> Signed-off-by: Kenneth Graunke <kenneth at whitecape.org>
> >> Cc: Chris Wilson <chris at chris-wilson.co.uk>
> >> Cc: Eero Tamminen <eero.t.tamminen at intel.com>
> >> ---
> >> src/mesa/drivers/dri/i965/brw_context.h | 3 +++
> >> src/mesa/drivers/dri/i965/gen6_queryobj.c | 27 +++++++++++++++++++++++----
> >> 2 files changed, 26 insertions(+), 4 deletions(-)
> >>
> >> ickle's patch in bug #86969 eliminated all calls to drm_intel_bo_references
> >> in the query object code. One consequence is that the first call to
> >> CheckQuery or WaitQuery would always flush the batch, even if it wasn't
> >> necessary (say, the batch had been flushed).
> >>
> >> Mine is a bit different - it still uses bo_references on the first call to
> >> CheckQuery/WaitQuery - but then records that the batch has been flushed, so
> >> we never have to call it again.
> >>
> >> Either approach should greatly reduce the overhead from repeatedly calling
> >> drm_intel_bo_references.
> >>
> >> Eero, would you be able to test this and see if it solves the issue you
> >> were seeing? If so, could you provide some simple statistics showing the
> >> benefit? Thanks!
> >>
> >> This is available as the 'query-references' branch in my tree (~kwg/mesa).
> >>
> >> diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h
> >> index 1b8f0bb..a63c483 100644
> >> --- a/src/mesa/drivers/dri/i965/brw_context.h
> >> +++ b/src/mesa/drivers/dri/i965/brw_context.h
> >> @@ -831,6 +831,9 @@ struct brw_query_object {
> >>
> >> /** Last index in bo with query data for this object. */
> >> int last_index;
> >> +
> >> + /** True if we know the batch has been flushed since we ended the query. */
> >> + bool flushed;
> >> };
> >>
> >> struct intel_sync_object {
> >> diff --git a/src/mesa/drivers/dri/i965/gen6_queryobj.c b/src/mesa/drivers/dri/i965/gen6_queryobj.c
> >> index 0d51390..de71bb5 100644
> >> --- a/src/mesa/drivers/dri/i965/gen6_queryobj.c
> >> +++ b/src/mesa/drivers/dri/i965/gen6_queryobj.c
> >> @@ -281,6 +281,27 @@ gen6_end_query(struct gl_context *ctx, struct gl_query_object *q)
> >> default:
> >> unreachable("Unrecognized query target in brw_end_query()");
> >> }
> >> +
> >> + /* The current batch contains the commands to handle EndQuery(),
> >> + * but they won't actually execute until it is flushed.
> >> + */
> >> + query->flushed = false;
> >> +}
> >
> > I think it makes more sense to set the flushed state at BeginQuery, and to
> > remove this hunk. I think that's feasible. Am I correct that this is the
> > generalized regex for the callchain?
> > BeginQuery->(flush_batch_if_needed)*->EndQuery->(flush_batch_if_needed)*->EndQuery
>
>
> No. It's BeginQuery->(flush_batch_if_needed)*->EndQuery. The
> application cannot ask for the query results until after the EndQuery.
> I think the way Ken has it is correct.
>
It seems like until we implement QueryCounter that's not true. (I mentioned
this below)
> > If this is correct, BeginBatch is the real marker of when we need to frob the
> > flushed state, since EndQuery is either a transient point, or the final call in
> > the Query object's life through the GL sequence.
> >
> > Additionally, it looks like if we implement QueryCounter (consistent naming
> > FTW), EndQuery would only ever be called the last time the query object is
> > referenced, and that simplifies this even more.
> >
> >> +
> >> +/**
> >> + * Flush the batch if it still references the query object BO.
> >> + */
> >> +static void
> >> +flush_batch_if_needed(struct brw_context *brw, struct brw_query_object *query)
> >> +{
> >> + /* If the batch doesn't reference the BO, it must have been flushed
> >> + * (for example, due to being full). Record that it's been flushed.
> >> + */
> >> + query->flushed = query->flushed ||
> >> + !drm_intel_bo_references(brw->batch.bo, query->bo);
> >> +
> >> + if (!query->flushed)
> >> + intel_batchbuffer_flush(brw);
> >> }
> >>
> >> /**
> >
> > Do you want to add an always_flush_batch check here?
> >
> >> @@ -298,8 +319,7 @@ static void gen6_wait_query(struct gl_context *ctx, struct gl_query_object *q)
> >> * still contributing to it, flush it now to finish that work so the
> >> * result will become available (eventually).
> >> */
> >> - if (drm_intel_bo_references(brw->batch.bo, query->bo))
> >> - intel_batchbuffer_flush(brw);
> >> + flush_batch_if_needed(brw, query);
> >>
> >> gen6_queryobj_get_results(ctx, query);
> >> }
> >> @@ -328,8 +348,7 @@ static void gen6_check_query(struct gl_context *ctx, struct gl_query_object *q)
> >> * not ready yet on the first time it is queried. This ensures that
> >> * the async query will return true in finite time.
> >> */
> >> - if (drm_intel_bo_references(brw->batch.bo, query->bo))
> >> - intel_batchbuffer_flush(brw);
> >> + flush_batch_if_needed(brw, query);
> >>
> >> if (!drm_intel_bo_busy(query->bo)) {
> >> gen6_queryobj_get_results(ctx, query);
> >
> > So while I had a verbose nit (which may not even be correct), I don't see
> > anything wrong here, so it's:
> > Reviewed-by: Ben Widawsky <ben at bwidawsk.net>
> >
> > I do hope to see some perf improvements.
> > _______________________________________________
> > mesa-dev mailing list
> > mesa-dev at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/mesa-dev
> >
>
--
Ben Widawsky, Intel Open Source Technology Center
More information about the mesa-dev
mailing list