jitter.c revision 280849
154359Sroberto/* 254359Sroberto * This program can be used to calibrate the clock reading jitter of a 354359Sroberto * particular CPU and operating system. It first tickles every element 4182007Sroberto * of an array, in order to force pages into memory, then repeatedly 5182007Sroberto * reads the system clock and, finally, writes out the time values for 6182007Sroberto * later analysis. From this you can determine the jitter and if the 7182007Sroberto * clock ever runs backwards. 854359Sroberto */ 982498Sroberto 10182007Sroberto#ifdef HAVE_CONFIG_H 11182007Sroberto# include <config.h> 12182007Sroberto#endif 13182007Sroberto 1482498Sroberto#include <stdio.h> 1554359Sroberto#include <sys/time.h> 16182007Sroberto#include <stdlib.h> 17182007Sroberto#include "jitter.h" 1854359Sroberto 19280849Scy#define NBUF 800002 20182007Sroberto#define FRAC 4294967296. /* a bbbbillion */ 21182007Sroberto#define JAN_1970 2208988800UL /* Unix base epoch */ 22182007Sroberto#define CLOCK_GETTIME /* Solaris hires clock */ 2354359Sroberto 24182007Srobertochar progname[10]; 25182007Srobertodouble sys_residual; 26182007Srobertodouble average; 27182007Srobertovoid sys_gettime(l_fp *); 28182007Sroberto 2954359Srobertoint 3054359Srobertomain( 3154359Sroberto int argc, 3254359Sroberto char *argv[] 3354359Sroberto ) 3454359Sroberto{ 35182007Sroberto l_fp tr; 36182007Sroberto int i, j; 37182007Sroberto double dtemp, gtod[NBUF]; 3854359Sroberto 3954359Sroberto /* 4054359Sroberto * Force pages into memory 4154359Sroberto */ 4254359Sroberto for (i = 0; i < NBUF; i ++) 4354359Sroberto gtod[i] = 0; 4454359Sroberto 4554359Sroberto /* 4654359Sroberto * Construct gtod array 4754359Sroberto */ 4854359Sroberto for (i = 0; i < NBUF; i ++) { 49182007Sroberto get_systime(&tr); 50182007Sroberto LFPTOD(&tr, gtod[i]); 5154359Sroberto } 5254359Sroberto 5354359Sroberto /* 54182007Sroberto * Write out gtod array for later processing with Matlab 5554359Sroberto */ 56182007Sroberto average = 0; 5754359Sroberto for (i = 0; i < NBUF - 2; i++) { 5854359Sroberto gtod[i] = gtod[i + 1] - gtod[i]; 59182007Sroberto printf("%13.9f\n", gtod[i]); 60182007Sroberto average += gtod[i]; 6154359Sroberto } 6254359Sroberto 6354359Sroberto /* 6454359Sroberto * Sort the gtod array and display deciles 6554359Sroberto */ 6654359Sroberto for (i = 0; i < NBUF - 2; i++) { 6754359Sroberto for (j = 0; j <= i; j++) { 6854359Sroberto if (gtod[j] > gtod[i]) { 69182007Sroberto dtemp = gtod[j]; 7054359Sroberto gtod[j] = gtod[i]; 71182007Sroberto gtod[i] = dtemp; 7254359Sroberto } 7354359Sroberto } 7454359Sroberto } 75182007Sroberto average = average / (NBUF - 2); 76182007Sroberto fprintf(stderr, "Average %13.9f\n", average); 7754359Sroberto fprintf(stderr, "First rank\n"); 7854359Sroberto for (i = 0; i < 10; i++) 79182007Sroberto fprintf(stderr, "%2d %13.9f\n", i, gtod[i]); 8054359Sroberto fprintf(stderr, "Last rank\n"); 8154359Sroberto for (i = NBUF - 12; i < NBUF - 2; i++) 82182007Sroberto fprintf(stderr, "%2d %13.9f\n", i, gtod[i]); 8354359Sroberto exit(0); 8454359Sroberto} 85182007Sroberto 86182007Sroberto 87182007Sroberto/* 88182007Sroberto * get_systime - return system time in NTP timestamp format. 89182007Sroberto */ 90182007Srobertovoid 91182007Srobertoget_systime( 92182007Sroberto l_fp *now /* system time */ 93182007Sroberto ) 94182007Sroberto{ 95182007Sroberto double dtemp; 96182007Sroberto 97182007Sroberto#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 98182007Sroberto struct timespec ts; /* seconds and nanoseconds */ 99182007Sroberto 100182007Sroberto /* 101182007Sroberto * Convert Unix clock from seconds and nanoseconds to seconds. 102182007Sroberto */ 103182007Sroberto# ifdef HAVE_CLOCK_GETTIME 104182007Sroberto clock_gettime(CLOCK_REALTIME, &ts); 105182007Sroberto# else 106182007Sroberto getclock(TIMEOFDAY, &ts); 107182007Sroberto# endif 108182007Sroberto now->l_i = ts.tv_sec + JAN_1970; 109182007Sroberto dtemp = ts.tv_nsec / 1e9; 110182007Sroberto 111182007Sroberto#else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */ 112182007Sroberto struct timeval tv; /* seconds and microseconds */ 113182007Sroberto 114182007Sroberto /* 115182007Sroberto * Convert Unix clock from seconds and microseconds to seconds. 116182007Sroberto */ 117182007Sroberto gettimeofday(&tv, NULL); 118182007Sroberto now->l_i = tv.tv_sec + JAN_1970; 119182007Sroberto dtemp = tv.tv_usec / 1e6; 120182007Sroberto 121182007Sroberto#endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */ 122182007Sroberto 123182007Sroberto /* 124182007Sroberto * Renormalize to seconds past 1900 and fraction. 125182007Sroberto */ 126182007Sroberto dtemp += sys_residual; 127182007Sroberto if (dtemp >= 1) { 128182007Sroberto dtemp -= 1; 129182007Sroberto now->l_i++; 130182007Sroberto } else if (dtemp < -1) { 131182007Sroberto dtemp += 1; 132182007Sroberto now->l_i--; 133182007Sroberto } 134182007Sroberto dtemp *= FRAC; 135182007Sroberto now->l_uf = (u_int32)dtemp; 136182007Sroberto} 137