Linux实时调度-kworker线程无法运行,导致性能受到影响



我有一个应用程序,其中一些线程使用CPU亲和性固定到特定的核心。

我已经尝试使用SCHED_FIFO/SCHED_RR将这些线程移动到实时优先级策略,其中SCHED_FFIFO/SCHED_RR在这些策略中具有系统上可用的最低优先级:

param.sched_priority = sched_get_priority_min(SCHED_FIFO);
pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);

因此,这些线程的性能受到了很大的影响。

经过一些研究,我发现原因是一个线程调用:kworker/1:0处于R状态,但由于它有一个常规策略而不是实时的,因此无法运行。

当我把这个kworker线程移到RT优先级时,我的应用程序又恢复了高性能:

chrt --fifo -p 99 <kworker_pid>

这看起来像是某种优先级反转,我的线程正在等待这个优先级较低的kworker,因此无法运行。

我试图弄清楚这个kwroker线程到底做了什么,以及为什么它被卡住会对我的应用程序产生如此大的影响,然而,我从它的内核回溯中得到的唯一线索是:

/proc/<kworker PID>/stack
[<ffffffff8107c1f3>] worker_thread+0x123/0x400
[<ffffffff810820be>] kthread+0xce/0xe0
[<ffffffff81602cec>] ret_from_fork+0x7c/0xb0

有什么想法吗?

要了解kworker线程正在做什么,可以使用perf调查情况。

由于kworker线程通常执行工作队列项目,因此可以查看工作队列跟踪事件,例如:

perf trace -e 'workqueue:workqueue_queue_work' --call-graph dwarf -C $CPU_NO

其中$CPU_NO是应用程序的固定线程被阻止的CPU核心编号。

如果工作项是由另一个CPU执行的操作排队的,则必须使用bcc跟踪或bpftrace添加一个条件,例如:

/usr/share/bcc/tools/trace -C -t -K -U 
't:workqueue:workqueue_queue_work (args->req_cpu==1) 
"%d => %d", args->cpu, args->req_cpu'

bpftrace -e ' tracepoint:workqueue:workqueue_queue_work /args->req_cpu==1/ 
{ printf("%d => %u   %s %sn",  args->cpu, args->req_cpu, kstack, ustack)  }  '

(跟踪点还有一个带有工作队列名称的字符串参数,这在这里也很有趣,但访问起来可能很棘手)

堆栈跟踪可能包括足够的提示,以了解应用程序是如何触发该工作队列项的。你会得到一些线索来研究你是否可以对此做点什么,例如,这样它就不会再发生在CPU上了(另请参阅Documentation/kernel-per-CPU-kthreads.txt以获得一些初步提示)。

最新更新