[Mesa-dev] [PATCH] nouveau: avoid queueing too much work onto a single fence

Ilia Mirkin imirkin at alum.mit.edu
Thu Nov 5 22:36:19 PST 2015


On Fri, Nov 6, 2015 at 1:27 AM, Jan Vesely <jan.vesely at rutgers.edu> wrote:
> On Fri, 2015-11-06 at 00:46 -0500, Ilia Mirkin wrote:
>> Force the fence to get kicked off, which won't actually wait for its
>> completion, but any additional work will be put onto a fresh list.
>>
>> This fixes crashes in teximage-colors --benchmark with too many
>> active
>> maps.
>>
>> Signed-off-by: Ilia Mirkin <imirkin at alum.mit.edu>
>> ---
>>  src/gallium/drivers/nouveau/nouveau_fence.c | 68 ++++++++++++++++++-
>> ----------
>>  src/gallium/drivers/nouveau/nouveau_fence.h |  1 +
>>  2 files changed, 43 insertions(+), 26 deletions(-)
>>
>> diff --git a/src/gallium/drivers/nouveau/nouveau_fence.c
>> b/src/gallium/drivers/nouveau/nouveau_fence.c
>> index d3a3406..691553a 100644
>> --- a/src/gallium/drivers/nouveau/nouveau_fence.c
>> +++ b/src/gallium/drivers/nouveau/nouveau_fence.c
>> @@ -59,26 +59,6 @@ nouveau_fence_trigger_work(struct nouveau_fence
>> *fence)
>>     }
>>  }
>>
>> -bool
>> -nouveau_fence_work(struct nouveau_fence *fence,
>> -                   void (*func)(void *), void *data)
>> -{
>> -   struct nouveau_fence_work *work;
>> -
>> -   if (!fence || fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) {
>> -      func(data);
>> -      return true;
>> -   }
>> -
>> -   work = CALLOC_STRUCT(nouveau_fence_work);
>> -   if (!work)
>> -      return false;
>> -   work->func = func;
>> -   work->data = data;
>> -   LIST_ADD(&work->list, &fence->work);
>> -   return true;
>> -}
>> -
>>  void
>>  nouveau_fence_emit(struct nouveau_fence *fence)
>>  {
>> @@ -182,12 +162,10 @@ nouveau_fence_signalled(struct nouveau_fence
>> *fence)
>>     return fence->state == NOUVEAU_FENCE_STATE_SIGNALLED;
>>  }
>>
>> -bool
>> -nouveau_fence_wait(struct nouveau_fence *fence, struct
>> pipe_debug_callback *debug)
>> +static bool
>> +nouveau_fence_kick(struct nouveau_fence *fence)
>>  {
>>     struct nouveau_screen *screen = fence->screen;
>> -   uint32_t spins = 0;
>> -   int64_t start = 0;
>>
>>     /* wtf, someone is waiting on a fence in flush_notify handler? */
>>     assert(fence->state != NOUVEAU_FENCE_STATE_EMITTING);
>> @@ -208,12 +186,25 @@ nouveau_fence_wait(struct nouveau_fence *fence,
>> struct pipe_debug_callback *debu
>>     if (fence == screen->fence.current)
>>        nouveau_fence_next(screen);
>>
>> +   nouveau_fence_update(screen, false);
>> +
>> +   return true;
>> +}
>> +
>> +bool
>> +nouveau_fence_wait(struct nouveau_fence *fence, struct
>> pipe_debug_callback *debug)
>> +{
>> +   struct nouveau_screen *screen = fence->screen;
>> +   uint32_t spins = 0;
>> +   int64_t start = 0;
>> +
>>     if (debug && debug->debug_message)
>>        start = os_time_get_nano();
>>
>> -   do {
>> -      nouveau_fence_update(screen, false);
>> +   if (!nouveau_fence_kick(fence))
>> +      return false;
>>
>> +   do {
>>        if (fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) {
>>           if (debug && debug->debug_message)
>>              pipe_debug_message(debug, PERF_INFO,
>> @@ -228,6 +219,8 @@ nouveau_fence_wait(struct nouveau_fence *fence,
>> struct pipe_debug_callback *debu
>>        if (!(spins % 8)) /* donate a few cycles */
>>           sched_yield();
>>  #endif
>> +
>> +      nouveau_fence_update(screen, false);
>>     } while (spins < NOUVEAU_FENCE_MAX_SPINS);
>>
>>     debug_printf("Wait on fence %u (ack = %u, next = %u) timed out
>> !\n",
>> @@ -259,3 +252,26 @@ nouveau_fence_unref_bo(void *data)
>>
>>     nouveau_bo_ref(NULL, &bo);
>>  }
>> +
>> +bool
>> +nouveau_fence_work(struct nouveau_fence *fence,
>> +                   void (*func)(void *), void *data)
>> +{
>> +   struct nouveau_fence_work *work;
>> +
>> +   if (!fence || fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) {
>> +      func(data);
>> +      return true;
>> +   }
>> +
>> +   work = CALLOC_STRUCT(nouveau_fence_work);
>> +   if (!work)
>> +      return false;
>> +   work->func = func;
>> +   work->data = data;
>> +   LIST_ADD(&work->list, &fence->work);
>> +   p_atomic_inc(&fence->work_count);
>> +   if (fence->work_count > 64)
>
> Is 64 just an arbitrary number?

Yep!

>
>> +      nouveau_fence_kick(fence);
>> +   return true;
>> +}
>> diff --git a/src/gallium/drivers/nouveau/nouveau_fence.h
>> b/src/gallium/drivers/nouveau/nouveau_fence.h
>> index 0fa9d02..f10016d 100644
>> --- a/src/gallium/drivers/nouveau/nouveau_fence.h
>> +++ b/src/gallium/drivers/nouveau/nouveau_fence.h
>> @@ -25,6 +25,7 @@ struct nouveau_fence {
>>     int state;
>>     int ref;
>>     uint32_t sequence;
>> +   uint32_t work_count;
>>     struct list_head work;
>>  };
>>


More information about the mesa-dev mailing list