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
454359Sroberto * of an array, in order to force pages into memory, then repeatedly calls
554359Sroberto * gettimeofday() and, finally, writes out the time values for later
654359Sroberto * analysis. From this you can determine the jitter and if the clock ever
754359Sroberto * runs backwards.
854359Sroberto */
954359Sroberto
1054359Sroberto#ifdef HAVE_CONFIG_H
1182498Sroberto# include <config.h>
1254359Sroberto#endif
1382498Sroberto
1482498Sroberto#include "ntp_types.h"
1582498Sroberto
1654359Sroberto#include <stdio.h>
1754359Sroberto#include <stdlib.h>
1854359Sroberto
1954359Sroberto#define NBUF 100001		/* size of basic histogram */
2054359Sroberto#define NSRT 20000		/* size of overflow histogram */
2154359Sroberto#define NCNT (600 * 1000000)	/* sample interval (us) */
2254359Sroberto
23290001Sglebiusint col (const void *, const void *);
2454359Sroberto
2554359Srobertoint
2654359Srobertomain(
2754359Sroberto	int argc,
2854359Sroberto	char *argv[]
2954359Sroberto	)
3054359Sroberto{
31182007Sroberto	struct timeval ts, tr, tp;
32182007Sroberto	struct timezone tzp;
3354359Sroberto	int i, j, n;
34182007Sroberto	long t, u, v, w, gtod[NBUF], ovfl[NSRT];
3554359Sroberto
3654359Sroberto	/*
3754359Sroberto	 * Force pages into memory
3854359Sroberto	 */
3954359Sroberto	for (i = 0; i < NBUF; i++)
40290001Sglebius		gtod[i] = 0;
4154359Sroberto	for (i = 0; i < NSRT; i++)
42290001Sglebius		ovfl[i] = 0;
4354359Sroberto
4454359Sroberto	/*
4554359Sroberto	 * Construct histogram
4654359Sroberto	 */
4754359Sroberto	n = 0;
48182007Sroberto	gettimeofday(&ts, &tzp);
49182007Sroberto	t = ts.tv_sec * 1000000 + ts.tv_usec;
5054359Sroberto	v = t;
5154359Sroberto	while (1) {
52182007Sroberto		gettimeofday(&tr, &tzp);
53182007Sroberto		u = tr.tv_sec * 1000000 + tr.tv_usec;
5454359Sroberto		if (u - v > NCNT)
55290001Sglebius			break;
5654359Sroberto		w = u - t;
5754359Sroberto		if (w <= 0) {
5854359Sroberto/*
5954359Sroberto			printf("error <= 0 %ld %d %d, %d %d\n", w, ts.tv_sec,
6054359Sroberto			       ts.tv_usec, tr.tv_sec, tr.tv_usec);
6154359Sroberto*/
6254359Sroberto		} else if (w > NBUF - 1) {
6354359Sroberto			ovfl[n] = w;
6454359Sroberto			if (n < NSRT - 1)
65290001Sglebius				n++;
6654359Sroberto		} else {
6754359Sroberto			gtod[w]++;
6854359Sroberto		}
69182007Sroberto		ts = tr;
7054359Sroberto		t = u;
7154359Sroberto	}
7254359Sroberto
7354359Sroberto	/*
7454359Sroberto	 * Write out histogram
7554359Sroberto	 */
7654359Sroberto	for (i = 0; i < NBUF - 1; i++) {
7754359Sroberto		if (gtod[i] > 0)
78290001Sglebius			printf("%ld %ld\n", i, gtod[i]);
7954359Sroberto	}
8054359Sroberto	if (n == 0)
81290001Sglebius		return;
82290001Sglebius	qsort(&ovfl, (size_t)n, sizeof(ovfl[0]), col);
8354359Sroberto	w = 0;
8454359Sroberto	j = 0;
8554359Sroberto	for (i = 0; i < n; i++) {
8654359Sroberto		if (ovfl[i] != w) {
8754359Sroberto			if (j > 0)
88290001Sglebius				printf("%ld %ld\n", w, j);
8954359Sroberto			w = ovfl[i];
9054359Sroberto			j = 1;
9154359Sroberto		} else
92290001Sglebius			j++;
9354359Sroberto	}
9454359Sroberto	if (j > 0)
95290001Sglebius		printf("%ld %ld\n", w, j);
9654359Sroberto
9754359Sroberto	exit(0);
9854359Sroberto}
9954359Sroberto
10054359Srobertoint
10154359Srobertocol(
102290001Sglebius	const void *vx,
103290001Sglebius	const void *vy
10454359Sroberto	)
10554359Sroberto{
106290001Sglebius	const long *x = vx;
107290001Sglebius	const long *y = vy;
108290001Sglebius
10954359Sroberto	return (*x - *y);
11054359Sroberto}
111