2007-09-27
nanosleep精度问题分析
最近有个同学在做流量模拟,发包时需要精确控制发包间隔,即要用到高精度的延时。
首先想到的便是nanosleep系统调用,毕竟从接口上看,它可以达到纳秒级的精度(1*10^-9)。
然而实际上nanosleep的解析度远没有达到预期,把时间间隔设地再小,精度也始终只有一微秒左右。
WHY?
READ THE FUCKING MANUAM
原来,2.6内核中nanosleep实现基于内核中的普通定时器机制,最大解析度也只有1/HZs,所以nanpsleep暂停的最小单位即是1ms,考虑到进程的切换与函数调用消耗的时间,实际的最小单位可能会在10ms左右甚至更长。
如果是这样,那为何内核还要提供这样一个名不副实的函数呢?
原来在2.4内核中,当把进程调度策略设置成实时级别的,诸如SCHED_FIFO或SCHED_RR,则对于较小的延迟时间,内核将采用忙等的方式进行计时处理。由此提供的解析精度可以达到2ms以下。
尝试了一下,实际解析度的确升高了,效果不错。
#include <stdio.h> #include <time.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h> #include <sched.h> #define BILLION 1000000L void do_sleep(int looptimes,int sleeptimes){ int i,j; struct timespec tv={0,1}; struct timeval start, stop; long accum; for(i=0;i<looptimes;i++){ gettimeofday(&start,NULL); for(j=0; j<sleeptimes; j++){ nanosleep(&tv,NULL); } gettimeofday(&stop,NULL); accum = ( stop.tv_sec - start.tv_sec )*BILLION + ( stop.tv_usec - start.tv_usec ); fprintf(stderr,"%ld\t", accum/sleeptimes ); } fprintf(stderr,"\n"); } int main( int argc, char** argv ) { struct sched_param sp; sp.sched_priority=0; sched_setscheduler(0,SCHED_FIFO,&sp); fprintf(stderr,"Schedule priority: %d\n",sp.sched_priority); do_sleep(10,100); sp.sched_priority=99; sched_setscheduler(0,SCHED_FIFO,&sp); fprintf(stderr,"Schedule priority: %d\n",sp.sched_priority); do_sleep(10,100); return 0; }
实验环境:
kernel version: Linux version 2.4.20-8smp (bhcompile@stripples.devel.redhat.com) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #1 SMP Thu Mar 13 16:43:01 EST 2003
–EOF–