1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
/*
* 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 <gem@rellim.com>
* This file is Copyright (c) 2018 by the GPSD project
* SPDX-License-Identifier: BSD-2-clause
*/
#include <getopt.h> /* for getopt() */
#include <limits.h> /* for LONG_MAX */
#include <math.h> /* for pow(), sqrt() */
#include <stdio.h> /* for printf() */
#include <stdlib.h> /* for qsort() */
#include <time.h> /* 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);
}
|