之前研究过cyclictest的源码,详见:
http://blog.csdn.net/sakaue/article/details/17843761
现在再研究下signaltest的源码
signaltest的程序结构与cyclictest大致类似。不同的是,cyclictest通过检测线程睡眠时间期望与实际之间的误差来检测性能。signaltest通过起n个线程,每个线程函数开始后就循环阻塞地等待信号,由主线程向第一个线程发送post给第二个线程,第二个线程向第三个线程,这样一个线程一个线程之间互相接力发送post,到第n个线程再向第一个线程发送post。这样,各个线程之间又通过信号量组成了一个循环队列,如图:
和cyclictest一样,signaltest也有个for循环num_threads次,每次迭代中给对应的thread_param结构体初始化(Line:348),thread_param结构如下:
struct thread_param { int id; int prio; //优先级 int signal; //传入SIGUSR1,以备用户自行结束线程循环 unsigned long max_cycles; //参数-l指定的每个线程内循环次数 struct thread_stat *stats; int bufmsk; }; /* Struct for statistics */ struct thread_stat { unsigned long cycles; //计算当前迭代次数 unsigned long cyclesread; long min; //指定最小误差 long max; //指定最大误差 long act; //指定最近一次的误差 double avg; //各个误差的均值 long *values; pthread_t thread; pthread_t tothread; //指向下一个线程(1->2 , 2->3 , ... , n-1 -> n , n->1) int threadstarted; int tid; //制定本线程ID };
schedp.sched_priority = par->prio; sched_setscheduler(0, policy, &schedp);
clock_gettime(CLOCK_MONOTONIC, &before); //获取进入cycle时的时间 while (!shutdown) { struct timespec now; long diff; int sigs; if (sigwait(&sigset, &sigs) < 0) //监听信号集set中所包含的信号,并将其存在signo中,第一个线程由主线程post goto out; clock_gettime(CLOCK_MONOTONIC, &after); //获取收到信号后的时间 /* * If it is the first thread, sleep after every 16 * round trips. */ if (!par->id && !(stat->cycles & 0x0F)) //第一个线程逢16的倍数则进入 usleep(10000); /* Get current time */ clock_gettime(CLOCK_MONOTONIC, &now); pthread_kill(stat->tothread, SIGUSR1); //向下一个线程发送SIGUSR1以post掉sigwait /* Skip the first cycle */ if (first) { first = 0; before = now; //如果是第一个线程的第一个循环,则设置before为发送第一个信号 continue; } diff = calcdiff(after, before); // before 上次发送信号的时间 , after本次获得信号的时间 before = now; //每次循环后将before重新设置为发送post之前的时间 if (diff < stat->min) //如果本次迭代的误差小于记录的最小值min,则更新min值 stat->min = diff; if (diff > stat->max) //如果本次迭代的误差大于记录的最小值max,则更新max值 stat->max = diff; stat->avg += (double) diff; //记录最近一次误差值 if (!stopped && tracelimit && (diff > tracelimit)) { stopped++; if (oldtrace) gettimeofday(0,0); else prctl(0, 0); shutdown++; } stat->act = diff; stat->cycles++; if (par->bufmsk) stat->values[stat->cycles & par->bufmsk] = diff; if (par->max_cycles && par->max_cycles == stat->cycles) break; }
这些线程中的迭代计算从发送信号到下一个线程,线程接力传递信号,直到自己再次收到信号所需要的时间。
下面看看正常内核和rt内核跑signaltest的结果如何
RT-Linux:
stewart@stewart:~$ sudo signaltest -l 10000 -p 20 -t 10 sudo: unable to resolve host stewart 0.49 0.27 0.11 1/340 2422 T: 0 ( 2413) P:20 C: 10000 Min: 37 Act: 41 Avg: 45 Max: 133Normal-Linux:
stewart@stewart:~/iWork/kernel/rt-tests$ sudo signaltest -l 10000 -p 20 -t 10 sudo: unable to resolve host stewart [sudo] password for stewart: 0.01 0.02 0.05 2/325 5538 T: 0 ( 5529) P:20 C: 10000 Min: 39 Act: 47 Avg: 52 Max: 177