]>
git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - tools/testing/selftests/timers/freq-step.c
2 * This test checks the response of the system clock to frequency
3 * steps made with adjtimex(). The frequency error and stability of
4 * the CLOCK_MONOTONIC clock relative to the CLOCK_MONOTONIC_RAW clock
5 * is measured in two intervals following the step. The test fails if
6 * values from the second interval exceed specified limits.
8 * Copyright (C) Miroslav Lichvar <mlichvar@redhat.com> 2017
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
22 #include <sys/timex.h>
26 #include "../kselftest.h"
29 #define SAMPLE_READINGS 10
30 #define MEAN_SAMPLE_INTERVAL 0.1
31 #define STEP_INTERVAL 1.0
32 #define MAX_PRECISION 100e-9
33 #define MAX_FREQ_ERROR 10e-6
34 #define MAX_STDDEV 1000e-9
41 static time_t mono_raw_base
;
42 static time_t mono_base
;
44 static double precision
;
45 static double mono_freq_offset
;
47 static double diff_timespec(struct timespec
*ts1
, struct timespec
*ts2
)
49 return ts1
->tv_sec
- ts2
->tv_sec
+ (ts1
->tv_nsec
- ts2
->tv_nsec
) / 1e9
;
52 static double get_sample(struct sample
*sample
)
54 double delay
, mindelay
= 0.0;
55 struct timespec ts1
, ts2
, ts3
;
58 for (i
= 0; i
< SAMPLE_READINGS
; i
++) {
59 clock_gettime(CLOCK_MONOTONIC_RAW
, &ts1
);
60 clock_gettime(CLOCK_MONOTONIC
, &ts2
);
61 clock_gettime(CLOCK_MONOTONIC_RAW
, &ts3
);
63 ts1
.tv_sec
-= mono_raw_base
;
64 ts2
.tv_sec
-= mono_base
;
65 ts3
.tv_sec
-= mono_raw_base
;
67 delay
= diff_timespec(&ts3
, &ts1
);
73 if (!i
|| delay
< mindelay
) {
74 sample
->offset
= diff_timespec(&ts2
, &ts1
);
75 sample
->offset
-= delay
/ 2.0;
76 sample
->time
= ts1
.tv_sec
+ ts1
.tv_nsec
/ 1e9
;
84 static void reset_ntp_error(void)
88 txc
.modes
= ADJ_SETOFFSET
;
92 if (adjtimex(&txc
) < 0) {
93 perror("[FAIL] adjtimex");
98 static void set_frequency(double freq
)
103 tick_offset
= 1e6
* freq
/ user_hz
;
105 txc
.modes
= ADJ_TICK
| ADJ_FREQUENCY
;
106 txc
.tick
= 1000000 / user_hz
+ tick_offset
;
107 txc
.freq
= (1e6
* freq
- user_hz
* tick_offset
) * (1 << 16);
109 if (adjtimex(&txc
) < 0) {
110 perror("[FAIL] adjtimex");
115 static void regress(struct sample
*samples
, int n
, double *intercept
,
116 double *slope
, double *r_stddev
, double *r_max
)
118 double x
, y
, r
, x_sum
, y_sum
, xy_sum
, x2_sum
, r2_sum
;
121 x_sum
= 0.0, y_sum
= 0.0, xy_sum
= 0.0, x2_sum
= 0.0;
123 for (i
= 0; i
< n
; i
++) {
125 y
= samples
[i
].offset
;
133 *slope
= (xy_sum
- x_sum
* y_sum
/ n
) / (x2_sum
- x_sum
* x_sum
/ n
);
134 *intercept
= (y_sum
- *slope
* x_sum
) / n
;
136 *r_max
= 0.0, r2_sum
= 0.0;
138 for (i
= 0; i
< n
; i
++) {
140 y
= samples
[i
].offset
;
141 r
= fabs(x
* *slope
+ *intercept
- y
);
147 *r_stddev
= sqrt(r2_sum
/ n
);
150 static int run_test(int calibration
, double freq_base
, double freq_step
)
152 struct sample samples
[SAMPLES
];
153 double intercept
, slope
, stddev1
, max1
, stddev2
, max2
;
154 double freq_error1
, freq_error2
;
157 set_frequency(freq_base
);
159 for (i
= 0; i
< 10; i
++)
160 usleep(1e6
* MEAN_SAMPLE_INTERVAL
/ 10);
164 set_frequency(freq_base
+ freq_step
);
166 for (i
= 0; i
< 10; i
++)
167 usleep(rand() % 2000000 * STEP_INTERVAL
/ 10);
169 set_frequency(freq_base
);
171 for (i
= 0; i
< SAMPLES
; i
++) {
172 usleep(rand() % 2000000 * MEAN_SAMPLE_INTERVAL
);
173 get_sample(&samples
[i
]);
177 regress(samples
, SAMPLES
, &intercept
, &slope
, &stddev1
, &max1
);
178 mono_freq_offset
= slope
;
179 printf("CLOCK_MONOTONIC_RAW frequency offset: %11.3f ppm\n",
180 1e6
* mono_freq_offset
);
184 regress(samples
, SAMPLES
/ 2, &intercept
, &slope
, &stddev1
, &max1
);
185 freq_error1
= slope
* (1.0 - mono_freq_offset
) - mono_freq_offset
-
188 regress(samples
+ SAMPLES
/ 2, SAMPLES
/ 2, &intercept
, &slope
,
190 freq_error2
= slope
* (1.0 - mono_freq_offset
) - mono_freq_offset
-
193 printf("%6.0f %+10.3f %6.0f %7.0f %+10.3f %6.0f %7.0f\t",
195 1e6
* freq_error1
, 1e9
* stddev1
, 1e9
* max1
,
196 1e6
* freq_error2
, 1e9
* stddev2
, 1e9
* max2
);
198 if (fabs(freq_error2
) > MAX_FREQ_ERROR
|| stddev2
> MAX_STDDEV
) {
207 static void init_test(void)
210 struct sample sample
;
212 if (clock_gettime(CLOCK_MONOTONIC_RAW
, &ts
)) {
213 perror("[FAIL] clock_gettime(CLOCK_MONOTONIC_RAW)");
217 mono_raw_base
= ts
.tv_sec
;
219 if (clock_gettime(CLOCK_MONOTONIC
, &ts
)) {
220 perror("[FAIL] clock_gettime(CLOCK_MONOTONIC)");
224 mono_base
= ts
.tv_sec
;
226 user_hz
= sysconf(_SC_CLK_TCK
);
228 precision
= get_sample(&sample
) / 2.0;
229 printf("CLOCK_MONOTONIC_RAW+CLOCK_MONOTONIC precision: %.0f ns\t\t",
232 if (precision
> MAX_PRECISION
) {
238 srand(ts
.tv_sec
^ ts
.tv_nsec
);
240 run_test(1, 0.0, 0.0);
243 int main(int argc
, char **argv
)
245 double freq_base
, freq_step
;
250 printf("Checking response to frequency step:\n");
251 printf(" Step 1st interval 2nd interval\n");
252 printf(" Freq Dev Max Freq Dev Max\n");
254 for (i
= 2; i
>= 0; i
--) {
255 for (j
= 0; j
< 5; j
++) {
256 freq_base
= (rand() % (1 << 24) - (1 << 23)) / 65536e6
;
257 freq_step
= 10e-6 * (1 << (6 * i
));
258 fails
+= run_test(0, freq_base
, freq_step
);