[PATCH] drm/scheduler: fix race condition in load balancer

Nirmoy nirmodas at amd.com
Tue Jan 14 16:13:55 UTC 2020


On 1/14/20 5:01 PM, Christian König wrote:
> Am 14.01.20 um 16:43 schrieb Nirmoy Das:
>> Jobs submitted in an entity should execute in the order those jobs
>> are submitted. We make sure that by checking entity->job_queue in
>> drm_sched_entity_select_rq() so that we don't loadbalance jobs within
>> an entity.
>>
>> But because we update entity->job_queue later in 
>> drm_sched_entity_push_job(),
>> there remains a open window when it is possibe that entity->rq might get
>> updated by drm_sched_entity_select_rq() which should not be allowed.
>
> NAK, concurrent calls to 
> drm_sched_job_init()/drm_sched_entity_push_job() are not allowed in 
> the first place or otherwise we mess up the fence sequence order and 
> risk memory corruption.

>
>>
>> Changes in this part also improves job distribution.
>> Below are test results after running amdgpu_test from mesa drm
>>
>> Before this patch:
>>
>> sched_name     num of many times it got scheduled
>> =========      ==================================
>> sdma0          314
>> sdma1          32
>> comp_1.0.0     56
>> comp_1.1.0     0
>> comp_1.1.1     0
>> comp_1.2.0     0
>> comp_1.2.1     0
>> comp_1.3.0     0
>> comp_1.3.1     0
>>
>> After this patch:
>>
>> sched_name     num of many times it got scheduled
>> =========      ==================================
>>   sdma1          243
>>   sdma0          164
>>   comp_1.0.1     14
>>   comp_1.1.0     11
>>   comp_1.1.1     10
>>   comp_1.2.0     15
>>   comp_1.2.1     14
>>   comp_1.3.0     10
>>   comp_1.3.1     10
>
> Well that is still rather nice to have, why does that happen?

I think it is because we are updating num_jobs immediately after 
selecting a new rq. Previously  we do that way after

drm_sched_job_init() in drm_sched_entity_push_job(). The problem is if I 
just do

@@ -562,6 +562,7 @@ int drm_sched_job_init(struct drm_sched_job *job,
           return -ENOENT;
         sched = entity->rq->sched;
+    atomic_inc(&entity->rq->sched->num_jobs);

  @@ -498,7 +504,6 @@ void drm_sched_entity_push_job(struct 
drm_sched_job *sched_job,
       bool first;
         trace_drm_sched_job(sched_job, entity);
-    atomic_inc(&entity->rq->sched->num_jobs);


num_jobs gets negative somewhere down the line somewhere. I am guessing  
it's hitting the race condition as I explained in the commit message


Regards,

Nirmoy

>
> Christian.
>
>>
>> Fixes: 35e160e781a048 (drm/scheduler: change entities rq even earlier)
>>
>> Signed-off-by: Nirmoy Das <nirmoy.das at amd.com>
>> Reported-by: Pierre-Eric Pelloux-Prayer 
>> <pierre-eric.pelloux-prayer at amd.com>
>> ---
>>   drivers/gpu/drm/scheduler/sched_entity.c | 9 +++++++--
>>   drivers/gpu/drm/scheduler/sched_main.c   | 1 +
>>   include/drm/gpu_scheduler.h              | 1 +
>>   3 files changed, 9 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/scheduler/sched_entity.c 
>> b/drivers/gpu/drm/scheduler/sched_entity.c
>> index 2e3a058fc239..8414e084b6ac 100644
>> --- a/drivers/gpu/drm/scheduler/sched_entity.c
>> +++ b/drivers/gpu/drm/scheduler/sched_entity.c
>> @@ -67,6 +67,7 @@ int drm_sched_entity_init(struct drm_sched_entity 
>> *entity,
>>       entity->priority = priority;
>>       entity->sched_list = num_sched_list > 1 ? sched_list : NULL;
>>       entity->last_scheduled = NULL;
>> +    entity->loadbalance_on = true;
>>         if(num_sched_list)
>>           entity->rq = &sched_list[0]->sched_rq[entity->priority];
>> @@ -447,6 +448,9 @@ struct drm_sched_job 
>> *drm_sched_entity_pop_job(struct drm_sched_entity *entity)
>>       entity->last_scheduled = 
>> dma_fence_get(&sched_job->s_fence->finished);
>>         spsc_queue_pop(&entity->job_queue);
>> +    if (!spsc_queue_count(&entity->job_queue))
>> +        entity->loadbalance_on = true;
>> +
>>       return sched_job;
>>   }
>>   @@ -463,7 +467,8 @@ void drm_sched_entity_select_rq(struct 
>> drm_sched_entity *entity)
>>       struct dma_fence *fence;
>>       struct drm_sched_rq *rq;
>>   -    if (spsc_queue_count(&entity->job_queue) || 
>> entity->num_sched_list <= 1)
>> +    atomic_inc(&entity->rq->sched->num_jobs);
>> +    if ((entity->num_sched_list <= 1) || !entity->loadbalance_on)
>>           return;
>>         fence = READ_ONCE(entity->last_scheduled);
>> @@ -477,6 +482,7 @@ void drm_sched_entity_select_rq(struct 
>> drm_sched_entity *entity)
>>           entity->rq = rq;
>>       }
>>   +    entity->loadbalance_on = false;
>>       spin_unlock(&entity->rq_lock);
>>   }
>>   @@ -498,7 +504,6 @@ void drm_sched_entity_push_job(struct 
>> drm_sched_job *sched_job,
>>       bool first;
>>         trace_drm_sched_job(sched_job, entity);
>> -    atomic_inc(&entity->rq->sched->num_jobs);
>>       WRITE_ONCE(entity->last_user, current->group_leader);
>>       first = spsc_queue_push(&entity->job_queue, 
>> &sched_job->queue_node);
>>   diff --git a/drivers/gpu/drm/scheduler/sched_main.c 
>> b/drivers/gpu/drm/scheduler/sched_main.c
>> index 3fad5876a13f..00fdc350134e 100644
>> --- a/drivers/gpu/drm/scheduler/sched_main.c
>> +++ b/drivers/gpu/drm/scheduler/sched_main.c
>> @@ -562,6 +562,7 @@ int drm_sched_job_init(struct drm_sched_job *job,
>>           return -ENOENT;
>>         sched = entity->rq->sched;
>> +    atomic_inc(&entity->rq->sched->num_jobs);
>>         job->sched = sched;
>>       job->entity = entity;
>> diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h
>> index 96a1a1b7526e..a5190869d323 100644
>> --- a/include/drm/gpu_scheduler.h
>> +++ b/include/drm/gpu_scheduler.h
>> @@ -97,6 +97,7 @@ struct drm_sched_entity {
>>       struct dma_fence                *last_scheduled;
>>       struct task_struct        *last_user;
>>       bool                 stopped;
>> +    bool                loadbalance_on;
>>       struct completion        entity_idle;
>>   };
>


More information about the amd-gfx mailing list