Re: [chrony-dev] SOCK refclock system time resolution

[ Thread Index | Date Index | More chrony.tuxfamily.org/chrony-dev Archives ]


On Fri, Sep 08, 2023 at 09:13:24 -0700, Bill Unruh wrote:
> Are you sure there is any point in nanosecond reporting?

Am I sure?  No :)

> Ie, I would suspect that the uncertainty in those times is at best
> microsecond anyway, so nanosecond reporting is unwarrented accuracy. (Ie,
> it takes a microsecond to determine the local clock time anyway)

Correct me if I'm wrong, but getting the local clock should be constant-ish
offset and therefore regardless of how long it takes, it is not a matter of
accuracy.

I just did a quick benchmark to see how long clock_gettime() takes on my ~10
year old desktop running FreeBSD.  It collects 100k samples, each sample
being the average time for a clock_gettime in a sequence of 30 back-to-back
calls.  (I veried the disassembly, and the calls are all there.)  Code is
attached.

When I run it, I get:

	min/avg/max 38.419355/38.613522/709.741935 ns/clock_gettime

The max varies a bit between 500-ish and 700-ish ns, but the min is always
in low 38s, and the average just a hair higher than the min.  The CPU runs
at 3.1GHz, so 39ns is about 120 cycles.  That's plenty to call a function,
get the hardware TSC, convert it to time-of-day, and return.

Modern unix/linux is quite fast when it comes to calculating the time.  I
don't know how accurate clock_gettime is, but it certainly seems to have the
resolution with minimal cost.

Jeff.
#include <time.h>
#include <stdint.h>
#include <stdio.h>

#define NSAMPLES	100000
#define BAD_SAMPLE	1e6 /* ignore all samples > 1ms */

#define CLOCK		CLOCK_MONOTONIC

static double measure(void)
{
	struct timespec a,b,c;
	uint64_t start, end;
	double avg;

	asm volatile("");
	clock_gettime(CLOCK, &a);
	asm volatile("");
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);

	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);

	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);
	clock_gettime(CLOCK, &b);

	asm volatile("");
	clock_gettime(CLOCK, &c);
	asm volatile("");

	start = a.tv_sec * 1000000000 + a.tv_nsec;
	end = c.tv_sec * 1000000000 + c.tv_nsec;
	avg = (end - start) / 31.;

	//printf("%19lu - %19lu = %6ld => %f\n", start, end, end - start, avg);

	return avg;
}

int main(int argc, char **argv)
{
	double min, max, avg;
	int nsamples;
	int i;

	min = 1e9;
	max = 0;
	avg = 0;
	nsamples = 0;
	for (i = 0; i < NSAMPLES; i++) {
		double sample;

		sample = measure();
		if (sample > BAD_SAMPLE)
			continue;

		if (min > sample)
			min = sample;
		if (max < sample)
			max = sample;

		avg += sample;
		nsamples++;
	}
	avg /= nsamples;

	printf("%d samples\n", nsamples);
	printf("min/avg/max %f/%f/%f ns/clock_gettime\n", min, avg, max);
	printf("avg - min = %f ns\n", avg - min);

	return 0;
}


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/