scx_layered: keep_running must account for local-DSQ-dispatched tasks#3709
scx_layered: keep_running must account for local-DSQ-dispatched tasks#3709ByteLab-David wants to merge 2 commits into
Conversation
keep_running() is invoked on the dispatch path when deciding whether a CPU should continue running the task whose slice has expired, or should instead pick a different task. It currently has a fairly serious bug in that it does not check whether there is a task queued on the CPU's local DSQ. Pinned tasks such as per-CPU kthreads are direct-inserted there and can run nowhere else. antistall can't rescue them either, since it only scans layer and fallback DSQs. Such a task can therefore starve until the runnable-stall watchdog trips and ejects the scheduler. Let's therefore add a check in keep_running() for whether there is another task on the local DSQ. This fixes stalls that were observed in production in GKE and EKS scenarios experiencing sustained CPU pressure. Signed-off-by: David Vernet <void@mainfault.com>
|
Is this reproducible? |
Hmm, I'm almost certain I saw this happen in some of the runs I was doing. I don't have the trace anymore but a latency-sensitive pcpu task got dispatched to the core and then got stuck behind the task that was currently on the CPU. Now that I'm looking at this more closely though, I think I must've conflated this with some other watchdog trigger I was trying to debug b/c I don't think a watchdog timeout should be possible. I think what might have happened is that there was a race between the rq lock being dropped on the dispatch path (e.g. from antistall_consume() when hitting the consume_dispatch_q() path), and a pcpu task being direct dispatched to the local DSQ in that window? Not sure, seems far fetched but I do explicitly remember it happening that a pcpu task woke up on the core and stayed runnable even though I'd have expected it to preempt the running task. I wish I still had the trace. In any case I think the commit is way overstated as is and I don't see how this would result in a watchdog trip. Feel free to just close this, or if I'm not missing something and the above race is possible, I can reframe the summary + comment to be accurate. |
keep_running() is invoked on the dispatch path when deciding whether a CPU should continue running the task whose slice has expired, or should instead pick a different task.
It currently has a fairly serious bug in that it does not check whether there is a task queued on the CPU's local DSQ. Pinned tasks such as per-CPU kthreads are direct-inserted there and can run nowhere else. antistall can't rescue them either, since it only scans layer and fallback DSQs. Such a task can therefore starve until the runnable-stall watchdog trips and ejects the scheduler.
Let's therefore add a check in keep_running() for whether there is another task on the local DSQ. This fixes stalls that were observed in production in GKE and EKS scenarios experiencing sustained CPU pressure.