Linux内核实时机制x - 中断响应测试Cyclitest
1 实时性测试工具 rt-test
1.1 源码下载
1.下载源码:
~/0-code/5.15$ git clone git://git.kernel.org/pub/scm/utils/rt-tests/rt-tests.git
正克隆到 'rt-tests'...
remote: Enumerating objects: 5534, done.
remote: Counting objects: 100% (7/7), done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 5534 (delta 1), reused 0 (delta 0), pack-reused 5527
接收对象中: 100% (5534/5534), 1.08 MiB | 654.00 KiB/s, 完成.
处理 delta 中: 100% (3569/3569), 完成.
1.2 源码编译
2. cd rt-tests && git checkout stable/v1.0
3. make all && make install
4. ./cyclictest -p 90 -m -n -c 0 -t 4 -D5m -b 60 --tracemark
1.3 实测图
2 Cyclitest详解
2.1 中断响应、延时概念:
- 无论系统运行在任何代码路径,当事件发生时,系统响应 该事件的时间即为延时。
- 延时在不同的上下文有不同的含义,而Cyclitest所测得的延时是中断响应延时 和 调度延时,如下图:
- 中断延时(interrupt latency),即中断发生到进入中断处理程序ISR的延时。
- 调度延时(scheduing latency),即当前任务被唤醒到任务真正获得CPU使用权中间的延时。
2.2 Cyclitest 原理
-
1、首先通过启动一个master的普通进程
-
2、然后matser进程在启动指定数量,指定优先级的实时进程,
-实时进程会设置一个timer周期性的唤醒自己
-从timer溢出触发中断并进入ISR调用 wake_up_process唤醒实时进程,到进程真正能被运行,这中间的时间即我们需要测量的延时。 -
3、并通过共享内存将该值传递给master进程进行统计,如此周而复始,最终由master进程将结果输出。
-
当造成延时的事件发生在timer溢出之前,那么这样的延时将不会被捕捉到,所以我们需要足够久的运行cyclitest才能更大概率的抓取全面的延时数据。
master线程逻辑
- 先创建num_threads个指定优先级的实时线程,然后在while循环中读取实时线程放在共享内存中的数据。
for (i = 0; i < num_threads; i++) {
pthread_attr_t attr;
int node;
struct thread_param *par;
struct thread_stat *stat;
par->prio = priority; //设置线程优先级,由-p参数指定
par->clock = clocksources[clocksel]; //由-c 设置
par->mode = mode;
//默认为static int timermode = TIMER_ABSTIME;,可由-r指定
//当使用 TIMER_ABSTIME 模式时,定时器的时间值是一个绝对时间点。
//也就是说,定时器将在指定的确切时间点触发,适用于需要定时器在特定的日期和时间点触发的场景
//当使用 TIMER_RELTIME 模式时,定时器的时间值是一个相对当前时间的偏移量。
//定时器将在从当前时间开始经过指定的时间间隔后触发。适用于需要定时器在当前时间之后的一段时间内触发的场景
par->timermode = timermode;
//默认睡眠时间为DEFAULT_INTERVAL或者 -i 10000 参数指定
par->interval = interval;
par->max_cycles = max_cycles;
par->stats = stat;
par->node = node;
par->tnum = i;
switch (setaffinity) {
case AFFINITY_UNSPECIFIED: par->cpu = -1; break;
case AFFINITY_SPECIFIED:
par->cpu = cpu_for_thread(i, max_cpus); //设置CPU亲和性
if (verbose)
printf("Thread %d using cpu %d.\n", i,
par->cpu);
break;
case AFFINITY_USEALL: par->cpu = i % max_cpus; break;
}
stat->min = 1000000;
stat->max = 0;
stat->avg = 0.0;
stat->threadstarted = 1;
stat->smi_count = 0;
status = pthread_create(&stat->thread, &attr, timerthread, par); //创建线程
- cyclictest应该是实时系统验证的领域中最常用的一个工具,主要用于测试实时系统的中断响应延时。
- 1、cyclictest首先根据参数创建若干个实时任务,每一个实时任务做同样的测试工作。
- 实时任务首先根据参数设置一个timer,在本例中,这个timer的时间为1000微秒,
- 然后通过系统调用将自己变为休眠状态,同时设置时钟寄存器,期待1000微秒后唤醒。
- 此后,该CPU开始运行其他任务。
- 2、正常情况下,1000微秒以后,时钟中断会到达CPU,CPU马上停下手里的工作,
- 进入中断上下文,开始处理这个时钟中断。
- 时钟中断例程判断cyclictest所设置的timer到时,唤醒cyclictest的测试实时任务,将其放入到rt调度器的调度队里中。
- 从中断上下文退出后,调度器发现实时任务比当前任务的优先级高,所以发生了抢占,实时任务被唤醒。
- 3、实时任务记录当前时间,然后减去开始时间和睡眠时间,得到了本次时钟中断处理的延时。
由此可见,cyclictest利用CPU的时钟中断,测试并记录了中断预计到来的时间与实际发生时间的差值,由于cyclictest工作在用户空间,所以测试结果也包括了任务抢占的时间和任务切换的时间。
- 1、获取当前时间。
- 2、设置睡眠时间。
- 3、通过clock_nanosleep将自己设置为睡眠状态,并且设置时钟中断。
- 4、唤醒后记录当前时间。
- 5、计算延时,即jitter = (end - start) - interval。
- 6、记录测试数据,包括响应延时的最大值,最小值和平均值。
- 7、设置下一个测试的睡眠时间。
- 8、如果测试达到设定循环的次数,则退出,测试结束。