154359Sroberto/* 254359Sroberto * This program can be used to calibrate the clock reading jitter of a 354359Sroberto * particular CPU and operating system. It first tickles every element 4182007Sroberto * of an array, in order to force pages into memory, then repeatedly 5182007Sroberto * reads the system clock and, finally, writes out the time values for 6182007Sroberto * later analysis. From this you can determine the jitter and if the 7182007Sroberto * clock ever runs backwards. 854359Sroberto */ 982498Sroberto 10182007Sroberto#ifdef HAVE_CONFIG_H 11182007Sroberto# include <config.h> 12182007Sroberto#endif 13182007Sroberto 1482498Sroberto#include <stdio.h> 1554359Sroberto#include <sys/time.h> 16182007Sroberto#include <stdlib.h> 17282408Scy#include "ntp_fp.h" 1854359Sroberto 19280849Scy#define NBUF 800002 20182007Sroberto#define JAN_1970 2208988800UL /* Unix base epoch */ 21182007Sroberto#define CLOCK_GETTIME /* Solaris hires clock */ 2254359Sroberto 23182007Srobertochar progname[10]; 24182007Srobertodouble sys_residual; 25182007Srobertodouble average; 26182007Srobertovoid sys_gettime(l_fp *); 27182007Sroberto 2854359Srobertoint 2954359Srobertomain( 3054359Sroberto int argc, 3154359Sroberto char *argv[] 3254359Sroberto ) 3354359Sroberto{ 34182007Sroberto l_fp tr; 35182007Sroberto int i, j; 36182007Sroberto double dtemp, gtod[NBUF]; 3754359Sroberto 3854359Sroberto /* 3954359Sroberto * Force pages into memory 4054359Sroberto */ 4154359Sroberto for (i = 0; i < NBUF; i ++) 4254359Sroberto gtod[i] = 0; 4354359Sroberto 4454359Sroberto /* 4554359Sroberto * Construct gtod array 4654359Sroberto */ 4754359Sroberto for (i = 0; i < NBUF; i ++) { 48182007Sroberto get_systime(&tr); 49182007Sroberto LFPTOD(&tr, gtod[i]); 5054359Sroberto } 5154359Sroberto 5254359Sroberto /* 53182007Sroberto * Write out gtod array for later processing with Matlab 5454359Sroberto */ 55182007Sroberto average = 0; 5654359Sroberto for (i = 0; i < NBUF - 2; i++) { 5754359Sroberto gtod[i] = gtod[i + 1] - gtod[i]; 58182007Sroberto printf("%13.9f\n", gtod[i]); 59182007Sroberto average += gtod[i]; 6054359Sroberto } 6154359Sroberto 6254359Sroberto /* 6354359Sroberto * Sort the gtod array and display deciles 6454359Sroberto */ 6554359Sroberto for (i = 0; i < NBUF - 2; i++) { 6654359Sroberto for (j = 0; j <= i; j++) { 6754359Sroberto if (gtod[j] > gtod[i]) { 68182007Sroberto dtemp = gtod[j]; 6954359Sroberto gtod[j] = gtod[i]; 70182007Sroberto gtod[i] = dtemp; 7154359Sroberto } 7254359Sroberto } 7354359Sroberto } 74182007Sroberto average = average / (NBUF - 2); 75182007Sroberto fprintf(stderr, "Average %13.9f\n", average); 7654359Sroberto fprintf(stderr, "First rank\n"); 7754359Sroberto for (i = 0; i < 10; i++) 78182007Sroberto fprintf(stderr, "%2d %13.9f\n", i, gtod[i]); 7954359Sroberto fprintf(stderr, "Last rank\n"); 8054359Sroberto for (i = NBUF - 12; i < NBUF - 2; i++) 81182007Sroberto fprintf(stderr, "%2d %13.9f\n", i, gtod[i]); 8254359Sroberto exit(0); 8354359Sroberto} 84182007Sroberto 85182007Sroberto 86182007Sroberto/* 87182007Sroberto * get_systime - return system time in NTP timestamp format. 88182007Sroberto */ 89182007Srobertovoid 90182007Srobertoget_systime( 91182007Sroberto l_fp *now /* system time */ 92182007Sroberto ) 93182007Sroberto{ 94182007Sroberto double dtemp; 95182007Sroberto 96182007Sroberto#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 97182007Sroberto struct timespec ts; /* seconds and nanoseconds */ 98182007Sroberto 99182007Sroberto /* 100182007Sroberto * Convert Unix clock from seconds and nanoseconds to seconds. 101182007Sroberto */ 102182007Sroberto# ifdef HAVE_CLOCK_GETTIME 103182007Sroberto clock_gettime(CLOCK_REALTIME, &ts); 104182007Sroberto# else 105182007Sroberto getclock(TIMEOFDAY, &ts); 106182007Sroberto# endif 107182007Sroberto now->l_i = ts.tv_sec + JAN_1970; 108182007Sroberto dtemp = ts.tv_nsec / 1e9; 109182007Sroberto 110182007Sroberto#else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */ 111182007Sroberto struct timeval tv; /* seconds and microseconds */ 112182007Sroberto 113182007Sroberto /* 114182007Sroberto * Convert Unix clock from seconds and microseconds to seconds. 115182007Sroberto */ 116182007Sroberto gettimeofday(&tv, NULL); 117182007Sroberto now->l_i = tv.tv_sec + JAN_1970; 118182007Sroberto dtemp = tv.tv_usec / 1e6; 119182007Sroberto 120182007Sroberto#endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */ 121182007Sroberto 122182007Sroberto /* 123182007Sroberto * Renormalize to seconds past 1900 and fraction. 124182007Sroberto */ 125182007Sroberto dtemp += sys_residual; 126182007Sroberto if (dtemp >= 1) { 127182007Sroberto dtemp -= 1; 128182007Sroberto now->l_i++; 129182007Sroberto } else if (dtemp < -1) { 130182007Sroberto dtemp += 1; 131182007Sroberto now->l_i--; 132182007Sroberto } 133182007Sroberto dtemp *= FRAC; 134182007Sroberto now->l_uf = (u_int32)dtemp; 135182007Sroberto} 136