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