我有一个应用程序,一些线程被固定到使用CPU亲和力的特定内核。
我已经尝试将这些线程移动到实时优先级策略,其中SCHED_FIFO / SCHED_RR在这些策略中具有系统上可用的最低优先级:
param.sched_priority = sched_get_priority_min(SCHED_FIFO);
pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m);
结果,我对这些线程产生了很高的性能影响。
经过一番研究后,我发现原因是一个线程叫做: 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
有什么想法吗?
答案 0 :(得分:0)
要了解 kworker 线程在做什么,您可以使用 perf
调查情况。
由于 kworker 线程通常执行 workqueue-items,因此您可以查看工作队列跟踪事件,例如:
perf trace -e 'workqueue:workqueue_queue_work' --call-graph dwarf -C $CPU_NO
其中 $CPU_NO
是 CPU 内核编号,其中应用程序的固定线程被阻塞。
如果工作项由另一个 CPU 执行的操作排队,则必须使用 bcc-trace 或 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 %s\n", args->cpu, args->req_cpu, kstack, ustack) } '
(跟踪点还有一个带有工作队列名称的字符串参数,这里也很有趣,但是 might be tricky to access)
堆栈跟踪可能包含足够的提示来了解您的应用程序如何触发该工作队列项。你会得到一些研究你是否可以做些什么的指示——例如这样它就不会再发生在那个 CPU 上(see also Documentation/kernel-per-CPU-kthreads.txt 以获得一些初始提示)。