在上一篇文章中,我粗略介绍了cyclictest工具测量延时的过程。在这篇文章中,我将使用kernelshark工具,追踪cyclictest测量延时线程(timerthread)的动态。kernelshark是一款内核追踪工具,利用trace-cmd读取到Linux内核记录,并且将记录可视化。
在以下的实验中,我使用命令
trace-cmd record -e all cyclictest -t1 -p99 -i 10000 -l 1000
来生成文件trace.dat,并且用kernelshark来读取和可视化这一文件,-i代表计时线程的睡眠时间,此处的cyclictest为V2.2版本,默认为clock_nanosleep模式。在stable/V1.0版本中,应该在cyclictest后边加上选项 -n。
1.kernelshark页面粗略介绍
图1 kernelshark页面cyclictest唤醒相关事件图
在图1中,上方紫色方框中的数值代表当前事件发生的事件,如Marker A 旁边的数值“264507.431392”,则代表该事件据最近一次启动系统已经过去了264507.431392秒。注意,Marker A 和Marker B 旁边的数值均可精确到1微秒,而A,B Delta旁边的“0.000025870”该数值则精确到1纳秒(千分之一微秒级别)。蓝色方框中的CPU 0则代表该行均显示在CPU 0上的活动,不同颜色代表不同线程任务。红色方框中的cyclictest-22110则代表该线程的活动,不同颜色代表该线程在相应的CPU上活动。
以下讨论均围绕cyclictest-22110线程进行。cyclictest-22108为主线程(即上一期提到执行main()函数的线程),cyclictest-22110为计时线程(timerthread),这可以从PID号上分析,计时线程一定后于主线程产生。
2.计时线程唤醒的大致过程
cyclictest-22110行上有一个绿色边空心框,这个框代表计时线程从开始被唤醒到实际运行的过程。空心框的左边有一条绿色长竖线,该竖线代表事件(event)sched_waking,表示计时线程开始被唤醒。空心框的右边有一条青色长竖线,该竖线代表事件sched_switch,结合info信息得知在CPU 0上将线程swapper切换为cyclictest。两个事件之间还有个事件sched_wakeup,表示计时线程唤醒完毕(注意,唤醒完毕不代表线程开始运行)。线程被唤醒后,下一个事件是sys_exit_clock_nanosleep,代表计时线程退出系统调用clock_nanosleep。
计时线程唤醒全过程可以分成四个时间点sched_waking->sched_wakeup->sched_switch->sys_exit_clock_nanosleep。
3.计时线程睡眠的大致过程
图2 kernelshark页面cyclictest睡眠相关事件图
在图2的cyclictest-22110计时线程行中,绿色线代表事件sys_enter_clock_nanosleep,即计时线程进行系统调用clock_nanosleep,info中的信息展示寄存器和标识符等信息。青色线代表事件sched_switch,即计时线程让出CPU 0的占有权。CPU 0上运行的任务从cyclictest-22110转变为kworker。
4.计时线程:从睡眠到唤醒
这一部分主要总结计时线程从开始睡眠到重新工作的过程中,kernelshark记录下来的主要事件。下表表1为计时线程时间戳——事件的记录表。
表1 计时线程时间戳——事件记录表
时科(秒) | 时间差(微秒) | 事件 |
264507.421506 | 0 | syscall/sys_enter_clock_nanosleep |
264507.421531 | 25 | sched/sched_switch |
264507.431392 | 9886 | sched/sched_waking |
264507.431401 | 9895 | sched/sched_wakeup |
264507.431418 | 9912 | sched/sched_switch |
264507.431426 | 9920 | syscall/sys_exit_clock_nanosleep |
结合这一专辑的第一偏文章,睡眠时间time_sleep的记录clock_gettime()发生在sys_enter_clock_nanosleep事件之前,实际工作的时间time_work记录发生在sys_exit_clock_nanosleep事件之后,睡眠的间隔interval为10000微秒(文章开头的命令有提及)。在控制台上看到的延时latency满足
在这里,给任务的延时定义为“从任务开始被唤醒到任务开始运行的时长”。根据此定义结合上表,cyclictest计时线程的延迟应该为sched_switch(第二个)的时刻减去sched_waking的时刻,即9912-9886=26微秒。cyclictest网址对于测量得到的延迟也有解释,声称由于使用nanosleep的原因,测得的延时要比实际的延时要更低(原文用的是optimistic一次)。
恳请读者们批评指正。