单个进程中不公平的linux线程调度

时间:2017-01-21 16:29:51

标签: linux multithreading kernel scheduler perf

我有一个有两个线程的进程。

第一个线程正在执行异步工作 - 它在epoll_wait中等待描述符和计时器事件上的IO。

第二个线程正在进行大量的IO /内存工作 - 它从磁盘读取数据,在内存中处理数据,分配大量新内存,将其写入磁盘等等。

问题是epoll_wait中的第一个线程阻塞的时间要长得多,然后在epoll_wait的超时时间内被请求(例如,超时被指定为1500毫秒并实际从epoll_wait返回在10秒内。)

这种行为我可以在虚拟机中可靠地重现(VirtualBox with Ubuntu 16.04)。

来自GDB的行为示例:

Thread 2.1 "se.real" hit Breakpoint 1, boost::asio::detail::epoll_reactor::run (this=0x826ebe0, block=true, ops=...) at /opt/com/include/boost/158/boost/asio/detail/impl/epoll_reactor.ipp:392
392 in /opt/com/include/boost/158/boost/asio/detail/impl/epoll_reactor.ipp
16:36:38.986826839
$17 = 1945

Thread 2.1 "se.real" hit Catchpoint 3 (call to syscall epoll_wait), 0xf7fd8be9 in __kernel_vsyscall ()
16:36:38.992081396

<INSIDE KERNEL>


Thread 2.1 "se.real" hit Catchpoint 3 (returned from syscall epoll_wait), 0xf7fd8be9 in __kernel_vsyscall ()
16:36:54.681444938

断点1设置为call epoll_wait之前的指令,打印参数为超时参数值(1945 ms)。

打印时间是shell date +"%T.%N"命令的时间。

Catchpoint 3是epoll_wait系统调用的系统调用捕获点(第一个用于输入,第二个用于返回)。

我们可以很容易地看到我们在内核中花了大约16秒,当时请求了1945毫秒。

我收集了perf record来自其他复制品的-e 'sched:*'个事件。我完全看到了:

se.real 4277 [001] 113049.144027: sched:sched_switch: prev_comm=se.real prev_pid=4277 prev_prio=120 prev_state=t|K ==> next_comm=strace next_pid=4142 next_prio=120
se.real 4277 [001] 113056.407952: sched:sched_stat_runtime: comm=se.real pid=4277 runtime=153767 [ns] vruntime=409222246640 [ns]

对于线程4277(具有异步IO和epoll_wait的第一个线程)没有任何其他sched事件约7秒。与此同时,这些事件之间有大量的计划活动。此活动包括第二个线程(具有大量IO /内存工作的线程),swapper / kswapd以及其他用户空间进程。

问题是我能做些什么才能有机会运行第一个线程?

更新:将流程的调度策略更改为SCHED_FIFO无法解决问题 - 我仍然可以稳定地重现此问题。

0 个答案:

没有答案