jitter.c revision 280849
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>
17182007Sroberto#include "jitter.h"
1854359Sroberto
19280849Scy#define NBUF	800002
20182007Sroberto#define FRAC	4294967296.		/* a bbbbillion */
21182007Sroberto#define JAN_1970 2208988800UL		/* Unix base epoch */
22182007Sroberto#define CLOCK_GETTIME			/* Solaris hires clock */
2354359Sroberto
24182007Srobertochar progname[10];
25182007Srobertodouble sys_residual;
26182007Srobertodouble average;
27182007Srobertovoid sys_gettime(l_fp *);
28182007Sroberto
2954359Srobertoint
3054359Srobertomain(
3154359Sroberto	int argc,
3254359Sroberto	char *argv[]
3354359Sroberto	)
3454359Sroberto{
35182007Sroberto	l_fp tr;
36182007Sroberto	int i, j;
37182007Sroberto	double dtemp, gtod[NBUF];
3854359Sroberto
3954359Sroberto	/*
4054359Sroberto	 * Force pages into memory
4154359Sroberto	 */
4254359Sroberto	for (i = 0; i < NBUF; i ++)
4354359Sroberto	    gtod[i] = 0;
4454359Sroberto
4554359Sroberto	/*
4654359Sroberto	 * Construct gtod array
4754359Sroberto	 */
4854359Sroberto	for (i = 0; i < NBUF; i ++) {
49182007Sroberto		get_systime(&tr);
50182007Sroberto		LFPTOD(&tr, gtod[i]);
5154359Sroberto	}
5254359Sroberto
5354359Sroberto	/*
54182007Sroberto	 * Write out gtod array for later processing with Matlab
5554359Sroberto	 */
56182007Sroberto	average = 0;
5754359Sroberto	for (i = 0; i < NBUF - 2; i++) {
5854359Sroberto		gtod[i] = gtod[i + 1] - gtod[i];
59182007Sroberto		printf("%13.9f\n", gtod[i]);
60182007Sroberto		average += gtod[i];
6154359Sroberto	}
6254359Sroberto
6354359Sroberto	/*
6454359Sroberto	 * Sort the gtod array and display deciles
6554359Sroberto	 */
6654359Sroberto	for (i = 0; i < NBUF - 2; i++) {
6754359Sroberto		for (j = 0; j <= i; j++) {
6854359Sroberto			if (gtod[j] > gtod[i]) {
69182007Sroberto				dtemp = gtod[j];
7054359Sroberto				gtod[j] = gtod[i];
71182007Sroberto				gtod[i] = dtemp;
7254359Sroberto			}
7354359Sroberto		}
7454359Sroberto	}
75182007Sroberto	average = average / (NBUF - 2);
76182007Sroberto	fprintf(stderr, "Average %13.9f\n", average);
7754359Sroberto	fprintf(stderr, "First rank\n");
7854359Sroberto	for (i = 0; i < 10; i++)
79182007Sroberto		fprintf(stderr, "%2d %13.9f\n", i, gtod[i]);
8054359Sroberto	fprintf(stderr, "Last rank\n");
8154359Sroberto	for (i = NBUF - 12; i < NBUF - 2; i++)
82182007Sroberto		fprintf(stderr, "%2d %13.9f\n", i, gtod[i]);
8354359Sroberto	exit(0);
8454359Sroberto}
85182007Sroberto
86182007Sroberto
87182007Sroberto/*
88182007Sroberto * get_systime - return system time in NTP timestamp format.
89182007Sroberto */
90182007Srobertovoid
91182007Srobertoget_systime(
92182007Sroberto	l_fp *now		/* system time */
93182007Sroberto	)
94182007Sroberto{
95182007Sroberto	double dtemp;
96182007Sroberto
97182007Sroberto#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
98182007Sroberto	struct timespec ts;	/* seconds and nanoseconds */
99182007Sroberto
100182007Sroberto	/*
101182007Sroberto	 * Convert Unix clock from seconds and nanoseconds to seconds.
102182007Sroberto	 */
103182007Sroberto# ifdef HAVE_CLOCK_GETTIME
104182007Sroberto	clock_gettime(CLOCK_REALTIME, &ts);
105182007Sroberto# else
106182007Sroberto	getclock(TIMEOFDAY, &ts);
107182007Sroberto# endif
108182007Sroberto	now->l_i = ts.tv_sec + JAN_1970;
109182007Sroberto	dtemp = ts.tv_nsec / 1e9;
110182007Sroberto
111182007Sroberto#else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
112182007Sroberto	struct timeval tv;	/* seconds and microseconds */
113182007Sroberto
114182007Sroberto	/*
115182007Sroberto	 * Convert Unix clock from seconds and microseconds to seconds.
116182007Sroberto	 */
117182007Sroberto	gettimeofday(&tv, NULL);
118182007Sroberto	now->l_i = tv.tv_sec + JAN_1970;
119182007Sroberto	dtemp = tv.tv_usec / 1e6;
120182007Sroberto
121182007Sroberto#endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
122182007Sroberto
123182007Sroberto	/*
124182007Sroberto	 * Renormalize to seconds past 1900 and fraction.
125182007Sroberto	 */
126182007Sroberto	dtemp += sys_residual;
127182007Sroberto	if (dtemp >= 1) {
128182007Sroberto		dtemp -= 1;
129182007Sroberto		now->l_i++;
130182007Sroberto	} else if (dtemp < -1) {
131182007Sroberto		dtemp += 1;
132182007Sroberto		now->l_i--;
133182007Sroberto	}
134182007Sroberto	dtemp *= FRAC;
135182007Sroberto	now->l_uf = (u_int32)dtemp;
136182007Sroberto}
137