/* * clock_test. A simple program to test the latency of the clock_gettime() call * * Compile: gcc clock_test.c -lm -o clock_test * * Written by: Gary E. Miller * This file is Copyright (c) 2018 by the GPSD project * SPDX-License-Identifier: BSD-2-clause */ #include /* for getopt() */ #include /* for LONG_MAX */ #include /* for pow(), sqrt() */ #include /* for printf() */ #include /* for qsort() */ #include /* for time_t */ #define NUM_TESTS 101 /* default samples, make it odd for a clean median */ #define DELAY 10000000 /* default delay between samples in ns, 10 ms is good */ int compare_long( const void *ap, const void *bp) { long a = *((long *)ap); long b = *((long *)bp); if ( a < b ) return -1; if ( a > b ) return 1; return 0; } int main(int argc, char **argv) { int i; int opt; /* for getopts() */ int verbose = 0; int samples = NUM_TESTS; long delay = DELAY; long *diffs = NULL; long min = LONG_MAX, max = 0, sum = 0, mean = 0, median = 0; double stddev = 0.0; while ((opt = getopt(argc, argv, "d:hvn:")) != -1) { switch (opt) { case 'd': delay = atol(optarg); break; case 'n': samples = atoi(optarg); /* make odd, for a good median */ if ( (samples & 1) == 0) { samples += 1; } break; case 'v': verbose = 1; break; case 'h': /* fall through */ default: /* '?' */ fprintf(stderr, "Usage: %s [-h] [-d nsec] [-n samples] [-v]\n\n", argv[0]); fprintf(stderr, "-d nsec : nano seconde paus between samples\n"); fprintf(stderr, "-h : help\n"); fprintf(stderr, "-n samples : Number of samples, default %d\n", NUM_TESTS); fprintf(stderr, "-v : verbose\n"); exit(EXIT_FAILURE); } } diffs = alloca( sizeof(long) * (samples + 2)); /* add 2 for off by one errors */ /* collect test data */ for ( i = 0 ; i < samples; i++ ) { struct timespec now, now1, sleep, sleep1; (void)clock_gettime(CLOCK_REALTIME, &now); (void)clock_gettime(CLOCK_REALTIME, &now1); diffs[i] = now1.tv_nsec - now.tv_nsec; if ( now1.tv_sec != now.tv_sec ) { /* clock roll over, fix it */ diffs[i] += 1000000000; /* add one second */ } /* instead of hammering, sleep between tests, let the cache get cold */ sleep.tv_sec = 0; sleep.tv_nsec = delay; /* sleep delay */ /* sleep1 unused, should not be returning early */ nanosleep(&sleep, &sleep1); } /* analyze test data */ /* print diffs, calculate min and max */ for ( i = 0 ; i < samples; i++ ) { if ( verbose > 0 ) { printf("diff %ld\n", diffs[i]); } sum += diffs[i]; if ( diffs[i] < min ) min = diffs[i]; if ( diffs[i] > max ) max = diffs[i]; } mean = sum / (samples - 1); qsort( diffs, samples, sizeof(long), compare_long); median = diffs[(samples / 2) + 1]; for ( i = 0 ; i < samples; i++ ) { stddev += pow(diffs[i] - mean, 2); } stddev = sqrt(stddev/samples); printf("samples %d, delay %ld ns\n", samples, delay); printf("min %ld ns, max %ld ns, mean %ld ns, median %ld ns, StdDev %ld ns\n", min, max, mean, median, (long)stddev); }