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;
}