(十)cyclictest--(zc7045)实时性能测试及原理

cyclictest是一个高精度的测试程序,Cyclictest 是 rt-tests 下的一个测试工具,也是rt-tests 下使用最广泛的测试工具,一般主要用来测试使用内核的延迟,从而判断内核的实时性。

一、测试

将cyclictest二进制文件放到NFS共享文件夹,客户机连接主机NFS共享文件夹。执行如下命令

./cyclictest -t 5 -p 80 -n 

tips:

cyclictest 的参数介绍 

      关于cyclictest 的各个参数具体含义建议大家还是用时间具体看看 cyclictest --help 的信息,我这只介绍几个常用的。

-p  PRIO --prio=PRIO                  最高优先级线程的优先级  使用时方法为: -p 90 /  --prio=90

-m       --mlockall                         锁定当前和将来的内存分配

-c  CLOCK --clock=CLOCK        选择时钟  cyclictest -c 1

                                                    0 = CLOCK_MONOTONIC (默认)

                                                    1 = CLOCK_REALTIME

-i  INTV  --interval=INTV              基本线程间隔,默认为1000(单位为us),下面介绍原理的时候会提到

-l  LOOPS --loops=LOOPS        循环的个数,默认为0(无穷个),与 -i 间隔数结合可大致算出整个测试的时间,比如 -i 1000  -l 1000000 ,总的循环时间为1000*1000000=1000000000 us =1000s ,所以大致为16分钟多。

-n       --nanosleep                      使用 clock_nanosleep

-h  HISTNUM    --histogram=US    在执行完后在标准输出设备上画出延迟的直方图(很多线程有相同的权限)US为最大的跟踪时间限制,这个在下面介绍实例时可以用到,结合gnuplot 可以画出我们测试的结果图。

                       

-q       --quiet                              使用-q 参数运行时不打印信息,只在退出时打印概要内容,结合-h HISTNUM参数会在退出时打印HISTNUM 行统计信息以及一个总的概要信息。

-f       --ftrace          f                     trace函数跟踪(通常与-b 配套使用,其实通常使用 -b 即可,不使用 -f )

-b USEC  --breaktrace=USEC     当延时大于USEC指定的值时,发送停止跟踪。USEC,单位为谬秒(us)。

下面来个对比:

加实时补丁

(十)cyclictest--(zc7045)实时性能测试及原理_第1张图片

不加实时补丁

(十)cyclictest--(zc7045)实时性能测试及原理_第2张图片

cyclictest运行结果详解

T: 0 序号为0的线程

P: 0 线程优先级为0

C: 9397 计数器。线程的时间间隔每达到一次,计数器加1

I: 1000 时间间隔为1000微秒(us)

Min: 最小延时(us)

Act: 最近一次的延时(us)

Avg:平均延时(us)

Max: 最大延时(us)

结合详解对结果进行简单的比对,效果还是比较明显的。

二、原理

从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);

	...

}

所以我们看到在main函数中只是定义了相关的变量之类的,而具体测试是通过创建线程,在线程中进行测试以及记录,下面我们打开测试线程:


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;

	...

}

从代码中可以看出,实现计算延时的原理还是挺简单的。

总结一下,就是刚开始记录开始时间为t1,间隔时间为 l,理论值即为 t1+l,在执行完之后再次记录时间t2,延时即为 t2-(t1+l).

你可能感兴趣的:(Yocto)