cyclictest 是什么? 看名字应该就能大致猜出来它是一种 test 程序,Cyclictest的维基主页这么介绍它“Cyclictest is a high resolution test program, written by User:Tglx, maintained by User:Clark Williams ”,也就是它是一个高精度的测试程序,Cyclictest 是 rt-tests 下的一个测试工具,也是rt-tests 下使用最广泛的测试工具,一般主要用来测试使用内核的延迟,从而判断内核的实时性。
Debian / Ubuntu 系统下可以直接使用apt-get install rt-tests 来安装cyclictest。
使用Linux最大的好处就是我们可以下载软件的源码,学习、编译以及使用,所以如果使用上述方法直接安装使用,如果你觉得有的问题不懂或者出现问题你也没办法解决,所以从开发者的角度而言,下载安装软件还是下载源码包编译后使用比较好。
# git clone git://git.kernel.org/pub/scm/linux/kernel/git/clrkwllms/rt-tests.git
master
* testing
# make
编译时我们会遇到缺失numa.h 的错误提示,在此我建议童鞋们安装使用apt-file 来解决此类错误(有了apt-file,遇到这类错误我们就知道如何解决而不是一味的上网找别人的解决方法),主要步骤如下:
# sudo apt-get install apt-file // 安装apt-file
# apt-file update // 类似于apt-get ,apt-file也需要根据系统配的源来更新一个库
# apt-file search numa.h // 使用apt-file search 搜索我们缺失的文件
libhwloc-dev: /usr/include/hwloc/linux-libnuma.h
libnuma-dev: /usr/include/numa.h // 在搜索到的结果中,我们发现这个包叫做 libnuma-dev 应该就是我们需要安装的包
linux-headers-3.2.0-4-amd64: /usr/src/linux-headers-3.2.0-4-amd64/include/config/acpi/numa.h
linux-headers-3.2.0-4-amd64: /usr/src/linux-headers-3.2.0-4-amd64/include/config/amd/numa.h
....
# apt-get install libnuma-dev // 使用apt-get 安装libnuma-dev 包
ls查看我们编译好的rt-tests仓库,我们可以看到make 之后生成了很多可执行文件(绿色的),这些都是一个个测试工具,在以后使用中如果遇到我会再讲解。
# ls
COPYING hackbench Makefile pmqtest rt-get_cpu.o sendme sigwaittest.d
cyclictest hackbench.d pip_stress pmqtest.d rt-migrate-test sendme.d sigwaittest.o
cyclictest.d hackbench.o pip_stress.d pmqtest.o rt-migrate-test.d sendme.o src
cyclictest.o hwlatdetect pip_stress.o ptsematest rt-migrate-test.o signaltest svsematest
debug librttest.a pi_stress ptsematest.d rt-tests.spec-in signaltest.d svsematest.d
doc logfile pi_stress.d ptsematest.o rt-utils.o signaltest.o svsematest.o
error.o logfile_10000000 pi_stress.o README.markdown scripts sigwaittest testininitS
对于Cyclictest的使用我们得先了解它的各个参数的含义,所以在你开始使用之前,请你看一下 cyclictest --help 中提到的各个参数!这将对你使用有很大的帮助。
如果你只是想玩玩这个工具,那么对于维基主页上提到的tglx 使用的测试命令来测测你的电脑性能:
# sudo ./cyclictest -t1 -p 80 -n -i 10000 -l 10000
注:在rt-tests的路径下,我们可以使用 ./cyclictest 来运行cyclictest, 而在别的目录下,我们就需要指定 cyclictest的路径来使用,比如说 /home/long/rt-tests/cyclictest ,或者你也可以直接将 rt-tests的路径下的 cyclictest 拷贝到 /bin/ 下,以后就可以直接使用 cyclictest 而不需要指定路径了!!
比如在我的电脑上,我使用这个命令测试的结果如下:
# /dev/cpu_dma_latency set to 0us
policy: fifo: loadavg: 0.38 0.29 0.26 1/381 5595
T: 0 ( 5592) P:80 I:10000 C: 10000 Min: 2 Act: 15 Avg: 15 Max: 195
输出结果含义:
T: 0 序号为0的线程
P: 0 线程优先级为0
C: 9397 计数器。线程的时间间隔每达到一次,计数器加1
I: 1000 时间间隔为1000微秒(us)
Min: 最小延时(us)
Act: 最近一次的延时(us)
Avg:平均延时(us)
Max: 最大延时(us)
所以我们当前的机器上最小延时为2,平均为15,最大的为 195。
$uname -a // 我们可以使用 “ uname -a ” 看到我们系统目前使用的内核版本
Linux wheezy 3.2.51-trace #8 SMP Thu Nov 21 12:34:04 CST 2013 x86_64 GNU/Linux
$ cat /boot/config-3.2.51-trace |grep CONFIG_PREEMPT_RT // 我们再打开 /boot 下面的当前内核的config信息查看目前这个内核是否打上实时补丁,结果显示并没有。所以在一个普通的内核下测的 Min: 2 Act: 15 Avg: 15 Max: 195 这样的数据算是不错的了!
$ cat /boot/config-3.10.17-trace-rt12 |grep CONFIG_PREEMPT_RT // 而在我 /boot 目录下的另外一个打好实时补丁的内核中
CONFIG_PREEMPT_RT_BASE=y
# CONFIG_PREEMPT_RTB is not set
CONFIG_PREEMPT_RT_FULL=y // 判断一个内核是否是实时内核,请看config 下有没有此项
我得到的cyclictest 运行结果是这样的:
T: 0 ( 5592) P:80 I:10000 C: 10000 Min: 1 Act: 1 Avg: 2 Max: 9
如果看了上面第2.3 关于测试以及结果的介绍,我相信大家对 cyclictest 的测试也知道了个大概。下面我们结合源代码来学习 cyclictest 的具体运行。
从rt-tests/src/cyclictest/cyclictest.c 的 main函数入手:
int main(int argc, char **argv)
{ ...
stat->min = 1000000;
stat->max = 0;
stat->avg = 0.0;
stat->threadstarted = 1;
status = pthread_create(&stat->thread, &attr, timerthread, par);
...
}
void *timerthread(void *param)
{ ...
interval.tv_sec = par->interval // 首先将参数中的间隔数赋给函数中的间隔数
interval.tv_nsec = (par->interval % USEC_PER_SEC) * 1000;
...
/* Get current time */
clock_gettime(par->clock, &now); // 获取当前时间,存在 now 中
next = now; //\
next.tv_sec += interval.tv_sec; // = 这三行是将当前时间(now 的值)加上间隔数(interval)算出下次间隔的时间,存在next
next.tv_nsec += interval.tv_nsec; ///
tsnorm(&next);
...
/* Wait for next period */ 等到下次循环
...
if ((ret = clock_gettime(par->clock, &now))) { //下次循环中记录循环时的时间到now 中,此时now 值中存的数是真实的下次循环的值,而上面存在next 的值是上次循环加上间隔值所以是理论上的下个循环的值。
if (ret != EINTR)
warn("clock_getttime() failed. errno: %d\n", errno);
goto out;
}
if (use_nsecs)
diff = calcdiff_ns(now, next); // 上面已经说过了,now 中是下次循环的真值,而next是理论的值,所以两者的差就是延时!延时赋值给diff
else
diff = calcdiff(now, next);
if (diff < stat->min) // 假如延时比min 小,将min 改为这个更小的延时值diff
stat->min = diff;
if (diff > stat->max) { // 假如延时比max 大,将max 改为这个更大的延时值diff
stat->max = diff;
if (refresh_on_max)
pthread_cond_signal(&refresh_on_max_cond);
}
stat->avg += (double) diff; // 计算新的平均延时
...
/* Update the histogram */ // 更新histogram中存的延时统计数据
if (histogram) {
if (diff >= histogram) { // 假如延时比histogram大,添加一次溢出
stat->hist_overflow++;
if (stat->num_outliers < histogram)
stat->outliers[stat->num_outliers++] = stat->cycles;
}
else // 如果没有溢出,将histogram 中的相应值加1
stat->hist_array[diff]++;
}
stat->cycles++; // 循环加1
next.tv_sec += interval.tv_sec; // 继续计算下次循环的值 ...
next.tv_nsec += interval.tv_nsec;
...
}
从代码中,我们可以学习到cyclictest的计算延时的原理!很简单吧,o(∩∩)o...哈哈,认识到了开源软件的好处了吧!
==============================
参考资料:
【1】cyclictest 的维基主页 https://rt.wiki.kernel.org/index.php/Cyclictest
【2】我师兄翻译的cyclictest维基主页 http://blog.csdn.net/ganggexiongqi/article/details/5841347