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