1 /* 2 * This program can be used to calibrate the clock reading jitter of a 3 * particular CPU and operating system. It first tickles every element 4 * of an array, in order to force pages into memory, then repeatedly 5 * reads the system clock and, finally, writes out the time values for 6 * later analysis. From this you can determine the jitter and if the 7 * clock ever runs backwards. 8 */ 9 10 #ifdef HAVE_CONFIG_H 11 # include <config.h> 12 #endif 13 14 #include <stdio.h> 15 #include <sys/time.h> 16 #include <stdlib.h> 17 #include "jitter.h" 18 19 #define NBUF 80002 20 #define FRAC 4294967296. /* a bbbbillion */ 21 #define JAN_1970 2208988800UL /* Unix base epoch */ 22 #define CLOCK_GETTIME /* Solaris hires clock */ 23 24 int debug; 25 char progname[10]; 26 double sys_residual; 27 double average; 28 void sys_gettime(l_fp *); 29 30 int 31 main( 32 int argc, 33 char *argv[] 34 ) 35 { 36 l_fp tr; 37 int i, j; 38 double dtemp, gtod[NBUF]; 39 40 /* 41 * Force pages into memory 42 */ 43 for (i = 0; i < NBUF; i ++) 44 gtod[i] = 0; 45 46 /* 47 * Construct gtod array 48 */ 49 for (i = 0; i < NBUF; i ++) { 50 get_systime(&tr); 51 LFPTOD(&tr, gtod[i]); 52 } 53 54 /* 55 * Write out gtod array for later processing with Matlab 56 */ 57 average = 0; 58 for (i = 0; i < NBUF - 2; i++) { 59 gtod[i] = gtod[i + 1] - gtod[i]; 60 printf("%13.9f\n", gtod[i]); 61 average += gtod[i]; 62 } 63 64 /* 65 * Sort the gtod array and display deciles 66 */ 67 for (i = 0; i < NBUF - 2; i++) { 68 for (j = 0; j <= i; j++) { 69 if (gtod[j] > gtod[i]) { 70 dtemp = gtod[j]; 71 gtod[j] = gtod[i]; 72 gtod[i] = dtemp; 73 } 74 } 75 } 76 average = average / (NBUF - 2); 77 fprintf(stderr, "Average %13.9f\n", average); 78 fprintf(stderr, "First rank\n"); 79 for (i = 0; i < 10; i++) 80 fprintf(stderr, "%2d %13.9f\n", i, gtod[i]); 81 fprintf(stderr, "Last rank\n"); 82 for (i = NBUF - 12; i < NBUF - 2; i++) 83 fprintf(stderr, "%2d %13.9f\n", i, gtod[i]); 84 exit(0); 85 } 86 87 88 /* 89 * get_systime - return system time in NTP timestamp format. 90 */ 91 void 92 get_systime( 93 l_fp *now /* system time */ 94 ) 95 { 96 double dtemp; 97 98 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 99 struct timespec ts; /* seconds and nanoseconds */ 100 101 /* 102 * Convert Unix clock from seconds and nanoseconds to seconds. 103 */ 104 # ifdef HAVE_CLOCK_GETTIME 105 clock_gettime(CLOCK_REALTIME, &ts); 106 # else 107 getclock(TIMEOFDAY, &ts); 108 # endif 109 now->l_i = ts.tv_sec + JAN_1970; 110 dtemp = ts.tv_nsec / 1e9; 111 112 #else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */ 113 struct timeval tv; /* seconds and microseconds */ 114 115 /* 116 * Convert Unix clock from seconds and microseconds to seconds. 117 */ 118 gettimeofday(&tv, NULL); 119 now->l_i = tv.tv_sec + JAN_1970; 120 dtemp = tv.tv_usec / 1e6; 121 122 #endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */ 123 124 /* 125 * Renormalize to seconds past 1900 and fraction. 126 */ 127 dtemp += sys_residual; 128 if (dtemp >= 1) { 129 dtemp -= 1; 130 now->l_i++; 131 } else if (dtemp < -1) { 132 dtemp += 1; 133 now->l_i--; 134 } 135 dtemp *= FRAC; 136 now->l_uf = (u_int32)dtemp; 137 } 138