[PATCH v2 1/2] drm/scheduler: Avoid using wait_event_killable for dying process.
Andrey Grodzovsky
Andrey.Grodzovsky at amd.com
Fri Jun 1 19:56:54 UTC 2018
On 06/01/2018 01:22 PM, Christian König wrote:
> Am 01.06.2018 um 19:11 schrieb Andrey Grodzovsky:
>> Dying process might be blocked from receiving any more signals
>> so avoid using it.
>>
>> Also retire enity->fini_status and just check the SW queue,
>> if it's not empty do the fallback cleanup.
>>
>> Also handle entity->last_scheduled == NULL use case which
>> happens when HW ring is already hangged whem a new entity
>> tried to enqeue jobs.
>>
>> v2:
>> Return the remaining timeout and use that as parameter for the next
>> call.
>> This way when we need to cleanup multiple queues we don't wait for the
>> entire TO period for each queue but rather in total.
>> Styling comments.
>> Rebase.
>>
>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky at amd.com>
>> ---
>> drivers/gpu/drm/scheduler/gpu_scheduler.c | 74
>> ++++++++++++++++++++++++-------
>> include/drm/gpu_scheduler.h | 7 +--
>> 2 files changed, 61 insertions(+), 20 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c
>> b/drivers/gpu/drm/scheduler/gpu_scheduler.c
>> index 8c1e80c..c594d17 100644
>> --- a/drivers/gpu/drm/scheduler/gpu_scheduler.c
>> +++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c
>> @@ -181,7 +181,6 @@ int drm_sched_entity_init(struct
>> drm_gpu_scheduler *sched,
>> entity->rq = rq;
>> entity->sched = sched;
>> entity->guilty = guilty;
>> - entity->fini_status = 0;
>> entity->last_scheduled = NULL;
>> spin_lock_init(&entity->rq_lock);
>> @@ -219,7 +218,8 @@ static bool
>> drm_sched_entity_is_initialized(struct drm_gpu_scheduler *sched,
>> static bool drm_sched_entity_is_idle(struct drm_sched_entity *entity)
>> {
>> rmb();
>> - if (spsc_queue_peek(&entity->job_queue) == NULL)
>> +
>> + if (!entity->rq || spsc_queue_peek(&entity->job_queue) == NULL)
>> return true;
>> return false;
>> @@ -260,25 +260,48 @@ static void
>> drm_sched_entity_kill_jobs_cb(struct dma_fence *f,
>> *
>> * @sched: scheduler instance
>> * @entity: scheduler entity
>> + * @timeout: time to wait in ms for Q to become empty.
>> *
>> * Splitting drm_sched_entity_fini() into two functions, The first
>> one does the waiting,
>> * removes the entity from the runqueue and returns an error when
>> the process was killed.
>> + *
>> + * Returns amount of time spent in waiting for TO.
>> + * 0 if wait wasn't with time out.
>> + * MAX_WAIT_SCHED_ENTITY_Q_EMPTY_MS if wait timed out with condition
>> false
>> + * Number of MS spent in waiting before condition became true
>> + *
>> */
>> -void drm_sched_entity_do_release(struct drm_gpu_scheduler *sched,
>> - struct drm_sched_entity *entity)
>> +unsigned drm_sched_entity_do_release(struct drm_gpu_scheduler *sched,
>> + struct drm_sched_entity *entity, unsigned timeout)
>
> Better use long for return type and timeout.
>
>> {
>> + unsigned ret = 0;
>
> Also use a long here and initialize it with timeout.
Please see bellow
>
>> +
>> if (!drm_sched_entity_is_initialized(sched, entity))
>> return;
>> /**
>> * The client will not queue more IBs during this fini, consume
>> existing
>> * queued IBs or discard them on SIGKILL
>> */
>> - if ((current->flags & PF_SIGNALED) && current->exit_code ==
>> SIGKILL)
>> - entity->fini_status = -ERESTARTSYS;
>> - else
>> - entity->fini_status = wait_event_killable(sched->job_scheduled,
>> - drm_sched_entity_is_idle(entity));
>> - drm_sched_entity_set_rq(entity, NULL);
>> + if (current->flags & PF_EXITING) {
>> + if (timeout) {
>> + ret = jiffies_to_msecs(
>> + wait_event_timeout(
>> + sched->job_scheduled,
>> + drm_sched_entity_is_idle(entity),
>> + msecs_to_jiffies(timeout)));
>
> Oh please don't use msecs as timeout, just use jiffies and let the
> caller do the conversion.
>
>> +
>> + if (!ret)
>> + ret = MAX_WAIT_SCHED_ENTITY_Q_EMPTY_MS;
>
> Why that? It is common coding style to return 0 when a timeout occurs.
>
> Christian.
What should i return when i do wait_event_killable, it's return values
are opposite to wait_event_timeout...
This way returning 0 has no impact on remaining waiting time, dong it
the other way will force the caller
to do some cumbersome logic instead of just
max_wait = max_wait >= ret ? max_wait - ret : 0;
like in amdgpu_ctx_mgr_entity_fini
Andrey
>
>> + }
>> + } else
>> + wait_event_killable(sched->job_scheduled,
>> drm_sched_entity_is_idle(entity));
>> +
>> +
>> + /* For killed process disable any more IBs enqueue right now */
>> + if ((current->flags & PF_EXITING) && (current->exit_code ==
>> SIGKILL))
>> + drm_sched_entity_set_rq(entity, NULL);
>> +
>> + return ret;
>> }
>> EXPORT_SYMBOL(drm_sched_entity_do_release);
>> @@ -290,11 +313,18 @@ EXPORT_SYMBOL(drm_sched_entity_do_release);
>> *
>> * This should be called after @drm_sched_entity_do_release. It
>> goes over the
>> * entity and signals all jobs with an error code if the process
>> was killed.
>> + *
>> */
>> void drm_sched_entity_cleanup(struct drm_gpu_scheduler *sched,
>> struct drm_sched_entity *entity)
>> {
>> - if (entity->fini_status) {
>> +
>> + drm_sched_entity_set_rq(entity, NULL);
>> +
>> + /* Consumption of existing IBs wasn't completed. Forcefully
>> + * remove them here.
>> + */
>> + if (spsc_queue_peek(&entity->job_queue)) {
>> struct drm_sched_job *job;
>> int r;
>> @@ -314,12 +344,22 @@ void drm_sched_entity_cleanup(struct
>> drm_gpu_scheduler *sched,
>> struct drm_sched_fence *s_fence = job->s_fence;
>> drm_sched_fence_scheduled(s_fence);
>> dma_fence_set_error(&s_fence->finished, -ESRCH);
>> - r = dma_fence_add_callback(entity->last_scheduled,
>> &job->finish_cb,
>> - drm_sched_entity_kill_jobs_cb);
>> - if (r == -ENOENT)
>> +
>> + /*
>> + * When pipe is hanged by older entity, new entity might
>> + * not even have chance to submit it's first job to HW
>> + * and so entity->last_scheduled will remain NULL
>> + */
>> + if (!entity->last_scheduled) {
>> drm_sched_entity_kill_jobs_cb(NULL, &job->finish_cb);
>> - else if (r)
>> - DRM_ERROR("fence add callback failed (%d)\n", r);
>> + } else {
>> + r = dma_fence_add_callback(entity->last_scheduled,
>> &job->finish_cb,
>> + drm_sched_entity_kill_jobs_cb);
>> + if (r == -ENOENT)
>> + drm_sched_entity_kill_jobs_cb(NULL,
>> &job->finish_cb);
>> + else if (r)
>> + DRM_ERROR("fence add callback failed (%d)\n", r);
>> + }
>> }
>> }
>> @@ -339,7 +379,7 @@ EXPORT_SYMBOL(drm_sched_entity_cleanup);
>> void drm_sched_entity_fini(struct drm_gpu_scheduler *sched,
>> struct drm_sched_entity *entity)
>> {
>> - drm_sched_entity_do_release(sched, entity);
>> + drm_sched_entity_do_release(sched, entity,
>> MAX_WAIT_SCHED_ENTITY_Q_EMPTY_MS);
>> drm_sched_entity_cleanup(sched, entity);
>> }
>> EXPORT_SYMBOL(drm_sched_entity_fini);
>> diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h
>> index 496442f..af07875 100644
>> --- a/include/drm/gpu_scheduler.h
>> +++ b/include/drm/gpu_scheduler.h
>> @@ -27,6 +27,8 @@
>> #include <drm/spsc_queue.h>
>> #include <linux/dma-fence.h>
>> +#define MAX_WAIT_SCHED_ENTITY_Q_EMPTY_MS 1000
>
> I suggest to use msecs_to_jiffies(1000) here and drop the _MS postfix.
>
> Christian.
>
>> +
>> struct drm_gpu_scheduler;
>> struct drm_sched_rq;
>> @@ -84,7 +86,6 @@ struct drm_sched_entity {
>> struct dma_fence *dependency;
>> struct dma_fence_cb cb;
>> atomic_t *guilty;
>> - int fini_status;
>> struct dma_fence *last_scheduled;
>> };
>> @@ -283,8 +284,8 @@ int drm_sched_entity_init(struct
>> drm_gpu_scheduler *sched,
>> struct drm_sched_entity *entity,
>> struct drm_sched_rq *rq,
>> atomic_t *guilty);
>> -void drm_sched_entity_do_release(struct drm_gpu_scheduler *sched,
>> - struct drm_sched_entity *entity);
>> +unsigned drm_sched_entity_do_release(struct drm_gpu_scheduler *sched,
>> + struct drm_sched_entity *entity, unsigned timeout);
>> void drm_sched_entity_cleanup(struct drm_gpu_scheduler *sched,
>> struct drm_sched_entity *entity);
>> void drm_sched_entity_fini(struct drm_gpu_scheduler *sched,
>
More information about the dri-devel
mailing list