jitter.c revision 267654
1240616Sjimharris/* 2240616Sjimharris * This program can be used to calibrate the clock reading jitter of a 3240616Sjimharris * particular CPU and operating system. It first tickles every element 4240616Sjimharris * of an array, in order to force pages into memory, then repeatedly 5240616Sjimharris * reads the system clock and, finally, writes out the time values for 6240616Sjimharris * later analysis. From this you can determine the jitter and if the 7240616Sjimharris * clock ever runs backwards. 8240616Sjimharris */ 9240616Sjimharris 10240616Sjimharris#ifdef HAVE_CONFIG_H 11240616Sjimharris# include <config.h> 12240616Sjimharris#endif 13240616Sjimharris 14240616Sjimharris#include <stdio.h> 15240616Sjimharris#include <sys/time.h> 16240616Sjimharris#include <stdlib.h> 17240616Sjimharris#include "jitter.h" 18240616Sjimharris 19240616Sjimharris#define NBUF 80002 20240616Sjimharris#define FRAC 4294967296. /* a bbbbillion */ 21240616Sjimharris#define JAN_1970 2208988800UL /* Unix base epoch */ 22240616Sjimharris#define CLOCK_GETTIME /* Solaris hires clock */ 23240616Sjimharris 24240616Sjimharrisint debug; 25240616Sjimharrischar progname[10]; 26240616Sjimharrisdouble sys_residual; 27240616Sjimharrisdouble average; 28240616Sjimharrisvoid sys_gettime(l_fp *); 29240616Sjimharris 30240616Sjimharrisint 31240616Sjimharrismain( 32240616Sjimharris int argc, 33240616Sjimharris char *argv[] 34240616Sjimharris ) 35240616Sjimharris{ 36240616Sjimharris l_fp tr; 37240616Sjimharris int i, j; 38240616Sjimharris double dtemp, gtod[NBUF]; 39240616Sjimharris 40240616Sjimharris /* 41240616Sjimharris * Force pages into memory 42240616Sjimharris */ 43240616Sjimharris for (i = 0; i < NBUF; i ++) 44240616Sjimharris gtod[i] = 0; 45240616Sjimharris 46240616Sjimharris /* 47240616Sjimharris * Construct gtod array 48240616Sjimharris */ 49240616Sjimharris for (i = 0; i < NBUF; i ++) { 50240616Sjimharris get_systime(&tr); 51240616Sjimharris LFPTOD(&tr, gtod[i]); 52240616Sjimharris } 53240616Sjimharris 54240616Sjimharris /* 55240616Sjimharris * Write out gtod array for later processing with Matlab 56240616Sjimharris */ 57240616Sjimharris average = 0; 58240616Sjimharris for (i = 0; i < NBUF - 2; i++) { 59240616Sjimharris gtod[i] = gtod[i + 1] - gtod[i]; 60240616Sjimharris printf("%13.9f\n", gtod[i]); 61240616Sjimharris average += gtod[i]; 62240616Sjimharris } 63240616Sjimharris 64240616Sjimharris /* 65240616Sjimharris * Sort the gtod array and display deciles 66240616Sjimharris */ 67240616Sjimharris for (i = 0; i < NBUF - 2; i++) { 68240616Sjimharris for (j = 0; j <= i; j++) { 69240616Sjimharris if (gtod[j] > gtod[i]) { 70240616Sjimharris dtemp = gtod[j]; 71240616Sjimharris gtod[j] = gtod[i]; 72240616Sjimharris gtod[i] = dtemp; 73240616Sjimharris } 74240616Sjimharris } 75240616Sjimharris } 76240616Sjimharris average = average / (NBUF - 2); 77240616Sjimharris fprintf(stderr, "Average %13.9f\n", average); 78240616Sjimharris fprintf(stderr, "First rank\n"); 79240616Sjimharris for (i = 0; i < 10; i++) 80240616Sjimharris fprintf(stderr, "%2d %13.9f\n", i, gtod[i]); 81240616Sjimharris fprintf(stderr, "Last rank\n"); 82240616Sjimharris for (i = NBUF - 12; i < NBUF - 2; i++) 83240616Sjimharris fprintf(stderr, "%2d %13.9f\n", i, gtod[i]); 84240616Sjimharris exit(0); 85240616Sjimharris} 86240616Sjimharris 87240616Sjimharris 88240616Sjimharris/* 89240616Sjimharris * get_systime - return system time in NTP timestamp format. 90240616Sjimharris */ 91240616Sjimharrisvoid 92240616Sjimharrisget_systime( 93240616Sjimharris l_fp *now /* system time */ 94240616Sjimharris ) 95240616Sjimharris{ 96240616Sjimharris double dtemp; 97240616Sjimharris 98240616Sjimharris#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 99240616Sjimharris struct timespec ts; /* seconds and nanoseconds */ 100240616Sjimharris 101240616Sjimharris /* 102240616Sjimharris * Convert Unix clock from seconds and nanoseconds to seconds. 103240616Sjimharris */ 104240616Sjimharris# ifdef HAVE_CLOCK_GETTIME 105240616Sjimharris clock_gettime(CLOCK_REALTIME, &ts); 106240616Sjimharris# else 107240616Sjimharris getclock(TIMEOFDAY, &ts); 108240616Sjimharris# endif 109240616Sjimharris now->l_i = ts.tv_sec + JAN_1970; 110240616Sjimharris dtemp = ts.tv_nsec / 1e9; 111240616Sjimharris 112240616Sjimharris#else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */ 113240616Sjimharris struct timeval tv; /* seconds and microseconds */ 114240616Sjimharris 115240616Sjimharris /* 116240616Sjimharris * Convert Unix clock from seconds and microseconds to seconds. 117240616Sjimharris */ 118240616Sjimharris gettimeofday(&tv, NULL); 119240616Sjimharris now->l_i = tv.tv_sec + JAN_1970; 120240616Sjimharris dtemp = tv.tv_usec / 1e6; 121240616Sjimharris 122240616Sjimharris#endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */ 123240616Sjimharris 124240616Sjimharris /* 125240616Sjimharris * Renormalize to seconds past 1900 and fraction. 126240616Sjimharris */ 127240616Sjimharris dtemp += sys_residual; 128240616Sjimharris if (dtemp >= 1) { 129240616Sjimharris dtemp -= 1; 130240616Sjimharris now->l_i++; 131240616Sjimharris } else if (dtemp < -1) { 132240616Sjimharris dtemp += 1; 133240616Sjimharris now->l_i--; 134240616Sjimharris } 135240616Sjimharris dtemp *= FRAC; 136240616Sjimharris now->l_uf = (u_int32)dtemp; 137240616Sjimharris} 138240616Sjimharris