jitter.c revision 267654
1240616Sjimharris/*
2240616Sjimharris * This program can be used to calibrate the clock reading jitter of a
3240616Sjimharris * particular CPU and operating system. It first tickles every element
4240616Sjimharris * of an array, in order to force pages into memory, then repeatedly
5240616Sjimharris * reads the system clock and, finally, writes out the time values for
6240616Sjimharris * later analysis. From this you can determine the jitter and if the
7240616Sjimharris * clock ever runs backwards.
8240616Sjimharris */
9240616Sjimharris
10240616Sjimharris#ifdef HAVE_CONFIG_H
11240616Sjimharris# include <config.h>
12240616Sjimharris#endif
13240616Sjimharris
14240616Sjimharris#include <stdio.h>
15240616Sjimharris#include <sys/time.h>
16240616Sjimharris#include <stdlib.h>
17240616Sjimharris#include "jitter.h"
18240616Sjimharris
19240616Sjimharris#define NBUF	80002
20240616Sjimharris#define FRAC	4294967296.		/* a bbbbillion */
21240616Sjimharris#define JAN_1970 2208988800UL		/* Unix base epoch */
22240616Sjimharris#define CLOCK_GETTIME			/* Solaris hires clock */
23240616Sjimharris
24240616Sjimharrisint debug;
25240616Sjimharrischar progname[10];
26240616Sjimharrisdouble sys_residual;
27240616Sjimharrisdouble average;
28240616Sjimharrisvoid sys_gettime(l_fp *);
29240616Sjimharris
30240616Sjimharrisint
31240616Sjimharrismain(
32240616Sjimharris	int argc,
33240616Sjimharris	char *argv[]
34240616Sjimharris	)
35240616Sjimharris{
36240616Sjimharris	l_fp tr;
37240616Sjimharris	int i, j;
38240616Sjimharris	double dtemp, gtod[NBUF];
39240616Sjimharris
40240616Sjimharris	/*
41240616Sjimharris	 * Force pages into memory
42240616Sjimharris	 */
43240616Sjimharris	for (i = 0; i < NBUF; i ++)
44240616Sjimharris	    gtod[i] = 0;
45240616Sjimharris
46240616Sjimharris	/*
47240616Sjimharris	 * Construct gtod array
48240616Sjimharris	 */
49240616Sjimharris	for (i = 0; i < NBUF; i ++) {
50240616Sjimharris		get_systime(&tr);
51240616Sjimharris		LFPTOD(&tr, gtod[i]);
52240616Sjimharris	}
53240616Sjimharris
54240616Sjimharris	/*
55240616Sjimharris	 * Write out gtod array for later processing with Matlab
56240616Sjimharris	 */
57240616Sjimharris	average = 0;
58240616Sjimharris	for (i = 0; i < NBUF - 2; i++) {
59240616Sjimharris		gtod[i] = gtod[i + 1] - gtod[i];
60240616Sjimharris		printf("%13.9f\n", gtod[i]);
61240616Sjimharris		average += gtod[i];
62240616Sjimharris	}
63240616Sjimharris
64240616Sjimharris	/*
65240616Sjimharris	 * Sort the gtod array and display deciles
66240616Sjimharris	 */
67240616Sjimharris	for (i = 0; i < NBUF - 2; i++) {
68240616Sjimharris		for (j = 0; j <= i; j++) {
69240616Sjimharris			if (gtod[j] > gtod[i]) {
70240616Sjimharris				dtemp = gtod[j];
71240616Sjimharris				gtod[j] = gtod[i];
72240616Sjimharris				gtod[i] = dtemp;
73240616Sjimharris			}
74240616Sjimharris		}
75240616Sjimharris	}
76240616Sjimharris	average = average / (NBUF - 2);
77240616Sjimharris	fprintf(stderr, "Average %13.9f\n", average);
78240616Sjimharris	fprintf(stderr, "First rank\n");
79240616Sjimharris	for (i = 0; i < 10; i++)
80240616Sjimharris		fprintf(stderr, "%2d %13.9f\n", i, gtod[i]);
81240616Sjimharris	fprintf(stderr, "Last rank\n");
82240616Sjimharris	for (i = NBUF - 12; i < NBUF - 2; i++)
83240616Sjimharris		fprintf(stderr, "%2d %13.9f\n", i, gtod[i]);
84240616Sjimharris	exit(0);
85240616Sjimharris}
86240616Sjimharris
87240616Sjimharris
88240616Sjimharris/*
89240616Sjimharris * get_systime - return system time in NTP timestamp format.
90240616Sjimharris */
91240616Sjimharrisvoid
92240616Sjimharrisget_systime(
93240616Sjimharris	l_fp *now		/* system time */
94240616Sjimharris	)
95240616Sjimharris{
96240616Sjimharris	double dtemp;
97240616Sjimharris
98240616Sjimharris#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
99240616Sjimharris	struct timespec ts;	/* seconds and nanoseconds */
100240616Sjimharris
101240616Sjimharris	/*
102240616Sjimharris	 * Convert Unix clock from seconds and nanoseconds to seconds.
103240616Sjimharris	 */
104240616Sjimharris# ifdef HAVE_CLOCK_GETTIME
105240616Sjimharris	clock_gettime(CLOCK_REALTIME, &ts);
106240616Sjimharris# else
107240616Sjimharris	getclock(TIMEOFDAY, &ts);
108240616Sjimharris# endif
109240616Sjimharris	now->l_i = ts.tv_sec + JAN_1970;
110240616Sjimharris	dtemp = ts.tv_nsec / 1e9;
111240616Sjimharris
112240616Sjimharris#else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
113240616Sjimharris	struct timeval tv;	/* seconds and microseconds */
114240616Sjimharris
115240616Sjimharris	/*
116240616Sjimharris	 * Convert Unix clock from seconds and microseconds to seconds.
117240616Sjimharris	 */
118240616Sjimharris	gettimeofday(&tv, NULL);
119240616Sjimharris	now->l_i = tv.tv_sec + JAN_1970;
120240616Sjimharris	dtemp = tv.tv_usec / 1e6;
121240616Sjimharris
122240616Sjimharris#endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
123240616Sjimharris
124240616Sjimharris	/*
125240616Sjimharris	 * Renormalize to seconds past 1900 and fraction.
126240616Sjimharris	 */
127240616Sjimharris	dtemp += sys_residual;
128240616Sjimharris	if (dtemp >= 1) {
129240616Sjimharris		dtemp -= 1;
130240616Sjimharris		now->l_i++;
131240616Sjimharris	} else if (dtemp < -1) {
132240616Sjimharris		dtemp += 1;
133240616Sjimharris		now->l_i--;
134240616Sjimharris	}
135240616Sjimharris	dtemp *= FRAC;
136240616Sjimharris	now->l_uf = (u_int32)dtemp;
137240616Sjimharris}
138240616Sjimharris