[PATCH v2 1/2] drm/scheduler: Avoid using wait_event_killable for dying process.
Christian König
ckoenig.leichtzumerken at gmail.com
Sun Jun 3 18:52:49 UTC 2018
Am 01.06.2018 um 21:56 schrieb Andrey Grodzovsky:
>
>
> 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...
Just the unmodified timeout. The timeout should begin only after the
process is killed.
> 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
Hui? Why do you want to fiddle with the max_wait here all together?
The usual pattern of using timeouts with multiple wait_event_timeout
calls is the following:
timeout = MAX_TIMEOUT;
while (more_events_to_handle) {
timeout = wait_event_timeout(... timeout);
if (timeout == 0)
break;
}
if (timeout == 0)
we_timeout_out_waiting_for_all_events();
Christian.
>
> 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,
>>
>
> _______________________________________________
> amd-gfx mailing list
> amd-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx
More information about the amd-gfx
mailing list