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