Signaltest源码分析

  • 前言

之前研究过cyclictest的源码,详见:

http://blog.csdn.net/sakaue/article/details/17843761

现在再研究下signaltest的源码

  • 正文

signaltest的程序结构与cyclictest大致类似。不同的是,cyclictest通过检测线程睡眠时间期望与实际之间的误差来检测性能。signaltest通过起n个线程,每个线程函数开始后就循环阻塞地等待信号,由主线程向第一个线程发送post给第二个线程,第二个线程向第三个线程,这样一个线程一个线程之间互相接力发送post,到第n个线程再向第一个线程发送post。这样,各个线程之间又通过信号量组成了一个循环队列,如图:

Signaltest源码分析_第1张图片

和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
	};

其中,我们需要设置thread_param结构的signal = signum(即SIGUSR1 Line:315,Linux系统有两个用户自定义行为的信号量,SIGUSR1和SIGUSR2 , 这个信号量的用途稍后会提到),并设置min,max,avg等变量(line:365-368用于记录误差结果),这里和cyclictest大同小异,这里就不再复述。然后启动线程,线程函数signalthread , 在signalthread中,首先设置线程的优先级(Line:123 , 124)

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:     133
Normal-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

效果可见,在实时内核下,signaltest跑出的效率更高。


你可能感兴趣的:(Signaltest源码分析)