xref: /aosp_15_r20/external/linux-kselftest/tools/testing/selftests/timers/freq-step.c (revision 053f45be4e351dfd5e965df293cd45b779f579ee)
1*053f45beSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-only
2*053f45beSAndroid Build Coastguard Worker /*
3*053f45beSAndroid Build Coastguard Worker  * This test checks the response of the system clock to frequency
4*053f45beSAndroid Build Coastguard Worker  * steps made with adjtimex(). The frequency error and stability of
5*053f45beSAndroid Build Coastguard Worker  * the CLOCK_MONOTONIC clock relative to the CLOCK_MONOTONIC_RAW clock
6*053f45beSAndroid Build Coastguard Worker  * is measured in two intervals following the step. The test fails if
7*053f45beSAndroid Build Coastguard Worker  * values from the second interval exceed specified limits.
8*053f45beSAndroid Build Coastguard Worker  *
9*053f45beSAndroid Build Coastguard Worker  * Copyright (C) Miroslav Lichvar <[email protected]>  2017
10*053f45beSAndroid Build Coastguard Worker  */
11*053f45beSAndroid Build Coastguard Worker 
12*053f45beSAndroid Build Coastguard Worker #include <math.h>
13*053f45beSAndroid Build Coastguard Worker #include <stdio.h>
14*053f45beSAndroid Build Coastguard Worker #include <sys/timex.h>
15*053f45beSAndroid Build Coastguard Worker #include <time.h>
16*053f45beSAndroid Build Coastguard Worker #include <unistd.h>
17*053f45beSAndroid Build Coastguard Worker 
18*053f45beSAndroid Build Coastguard Worker #include "../kselftest.h"
19*053f45beSAndroid Build Coastguard Worker 
20*053f45beSAndroid Build Coastguard Worker #define SAMPLES 100
21*053f45beSAndroid Build Coastguard Worker #define SAMPLE_READINGS 10
22*053f45beSAndroid Build Coastguard Worker #define MEAN_SAMPLE_INTERVAL 0.1
23*053f45beSAndroid Build Coastguard Worker #define STEP_INTERVAL 1.0
24*053f45beSAndroid Build Coastguard Worker #define MAX_PRECISION 500e-9
25*053f45beSAndroid Build Coastguard Worker #define MAX_FREQ_ERROR 0.02e-6
26*053f45beSAndroid Build Coastguard Worker #define MAX_STDDEV 50e-9
27*053f45beSAndroid Build Coastguard Worker 
28*053f45beSAndroid Build Coastguard Worker #ifndef ADJ_SETOFFSET
29*053f45beSAndroid Build Coastguard Worker   #define ADJ_SETOFFSET 0x0100
30*053f45beSAndroid Build Coastguard Worker #endif
31*053f45beSAndroid Build Coastguard Worker 
32*053f45beSAndroid Build Coastguard Worker struct sample {
33*053f45beSAndroid Build Coastguard Worker 	double offset;
34*053f45beSAndroid Build Coastguard Worker 	double time;
35*053f45beSAndroid Build Coastguard Worker };
36*053f45beSAndroid Build Coastguard Worker 
37*053f45beSAndroid Build Coastguard Worker static time_t mono_raw_base;
38*053f45beSAndroid Build Coastguard Worker static time_t mono_base;
39*053f45beSAndroid Build Coastguard Worker static long user_hz;
40*053f45beSAndroid Build Coastguard Worker static double precision;
41*053f45beSAndroid Build Coastguard Worker static double mono_freq_offset;
42*053f45beSAndroid Build Coastguard Worker 
diff_timespec(struct timespec * ts1,struct timespec * ts2)43*053f45beSAndroid Build Coastguard Worker static double diff_timespec(struct timespec *ts1, struct timespec *ts2)
44*053f45beSAndroid Build Coastguard Worker {
45*053f45beSAndroid Build Coastguard Worker 	return ts1->tv_sec - ts2->tv_sec + (ts1->tv_nsec - ts2->tv_nsec) / 1e9;
46*053f45beSAndroid Build Coastguard Worker }
47*053f45beSAndroid Build Coastguard Worker 
get_sample(struct sample * sample)48*053f45beSAndroid Build Coastguard Worker static double get_sample(struct sample *sample)
49*053f45beSAndroid Build Coastguard Worker {
50*053f45beSAndroid Build Coastguard Worker 	double delay, mindelay = 0.0;
51*053f45beSAndroid Build Coastguard Worker 	struct timespec ts1, ts2, ts3;
52*053f45beSAndroid Build Coastguard Worker 	int i;
53*053f45beSAndroid Build Coastguard Worker 
54*053f45beSAndroid Build Coastguard Worker 	for (i = 0; i < SAMPLE_READINGS; i++) {
55*053f45beSAndroid Build Coastguard Worker 		clock_gettime(CLOCK_MONOTONIC_RAW, &ts1);
56*053f45beSAndroid Build Coastguard Worker 		clock_gettime(CLOCK_MONOTONIC, &ts2);
57*053f45beSAndroid Build Coastguard Worker 		clock_gettime(CLOCK_MONOTONIC_RAW, &ts3);
58*053f45beSAndroid Build Coastguard Worker 
59*053f45beSAndroid Build Coastguard Worker 		ts1.tv_sec -= mono_raw_base;
60*053f45beSAndroid Build Coastguard Worker 		ts2.tv_sec -= mono_base;
61*053f45beSAndroid Build Coastguard Worker 		ts3.tv_sec -= mono_raw_base;
62*053f45beSAndroid Build Coastguard Worker 
63*053f45beSAndroid Build Coastguard Worker 		delay = diff_timespec(&ts3, &ts1);
64*053f45beSAndroid Build Coastguard Worker 		if (delay <= 1e-9) {
65*053f45beSAndroid Build Coastguard Worker 			i--;
66*053f45beSAndroid Build Coastguard Worker 			continue;
67*053f45beSAndroid Build Coastguard Worker 		}
68*053f45beSAndroid Build Coastguard Worker 
69*053f45beSAndroid Build Coastguard Worker 		if (!i || delay < mindelay) {
70*053f45beSAndroid Build Coastguard Worker 			sample->offset = diff_timespec(&ts2, &ts1);
71*053f45beSAndroid Build Coastguard Worker 			sample->offset -= delay / 2.0;
72*053f45beSAndroid Build Coastguard Worker 			sample->time = ts1.tv_sec + ts1.tv_nsec / 1e9;
73*053f45beSAndroid Build Coastguard Worker 			mindelay = delay;
74*053f45beSAndroid Build Coastguard Worker 		}
75*053f45beSAndroid Build Coastguard Worker 	}
76*053f45beSAndroid Build Coastguard Worker 
77*053f45beSAndroid Build Coastguard Worker 	return mindelay;
78*053f45beSAndroid Build Coastguard Worker }
79*053f45beSAndroid Build Coastguard Worker 
reset_ntp_error(void)80*053f45beSAndroid Build Coastguard Worker static void reset_ntp_error(void)
81*053f45beSAndroid Build Coastguard Worker {
82*053f45beSAndroid Build Coastguard Worker 	struct timex txc;
83*053f45beSAndroid Build Coastguard Worker 
84*053f45beSAndroid Build Coastguard Worker 	txc.modes = ADJ_SETOFFSET;
85*053f45beSAndroid Build Coastguard Worker 	txc.time.tv_sec = 0;
86*053f45beSAndroid Build Coastguard Worker 	txc.time.tv_usec = 0;
87*053f45beSAndroid Build Coastguard Worker 
88*053f45beSAndroid Build Coastguard Worker 	if (adjtimex(&txc) < 0) {
89*053f45beSAndroid Build Coastguard Worker 		perror("[FAIL] adjtimex");
90*053f45beSAndroid Build Coastguard Worker 		ksft_exit_fail();
91*053f45beSAndroid Build Coastguard Worker 	}
92*053f45beSAndroid Build Coastguard Worker }
93*053f45beSAndroid Build Coastguard Worker 
set_frequency(double freq)94*053f45beSAndroid Build Coastguard Worker static void set_frequency(double freq)
95*053f45beSAndroid Build Coastguard Worker {
96*053f45beSAndroid Build Coastguard Worker 	struct timex txc;
97*053f45beSAndroid Build Coastguard Worker 	int tick_offset;
98*053f45beSAndroid Build Coastguard Worker 
99*053f45beSAndroid Build Coastguard Worker 	tick_offset = 1e6 * freq / user_hz;
100*053f45beSAndroid Build Coastguard Worker 
101*053f45beSAndroid Build Coastguard Worker 	txc.modes = ADJ_TICK | ADJ_FREQUENCY;
102*053f45beSAndroid Build Coastguard Worker 	txc.tick = 1000000 / user_hz + tick_offset;
103*053f45beSAndroid Build Coastguard Worker 	txc.freq = (1e6 * freq - user_hz * tick_offset) * (1 << 16);
104*053f45beSAndroid Build Coastguard Worker 
105*053f45beSAndroid Build Coastguard Worker 	if (adjtimex(&txc) < 0) {
106*053f45beSAndroid Build Coastguard Worker 		perror("[FAIL] adjtimex");
107*053f45beSAndroid Build Coastguard Worker 		ksft_exit_fail();
108*053f45beSAndroid Build Coastguard Worker 	}
109*053f45beSAndroid Build Coastguard Worker }
110*053f45beSAndroid Build Coastguard Worker 
regress(struct sample * samples,int n,double * intercept,double * slope,double * r_stddev,double * r_max)111*053f45beSAndroid Build Coastguard Worker static void regress(struct sample *samples, int n, double *intercept,
112*053f45beSAndroid Build Coastguard Worker 		    double *slope, double *r_stddev, double *r_max)
113*053f45beSAndroid Build Coastguard Worker {
114*053f45beSAndroid Build Coastguard Worker 	double x, y, r, x_sum, y_sum, xy_sum, x2_sum, r2_sum;
115*053f45beSAndroid Build Coastguard Worker 	int i;
116*053f45beSAndroid Build Coastguard Worker 
117*053f45beSAndroid Build Coastguard Worker 	x_sum = 0.0, y_sum = 0.0, xy_sum = 0.0, x2_sum = 0.0;
118*053f45beSAndroid Build Coastguard Worker 
119*053f45beSAndroid Build Coastguard Worker 	for (i = 0; i < n; i++) {
120*053f45beSAndroid Build Coastguard Worker 		x = samples[i].time;
121*053f45beSAndroid Build Coastguard Worker 		y = samples[i].offset;
122*053f45beSAndroid Build Coastguard Worker 
123*053f45beSAndroid Build Coastguard Worker 		x_sum += x;
124*053f45beSAndroid Build Coastguard Worker 		y_sum += y;
125*053f45beSAndroid Build Coastguard Worker 		xy_sum += x * y;
126*053f45beSAndroid Build Coastguard Worker 		x2_sum += x * x;
127*053f45beSAndroid Build Coastguard Worker 	}
128*053f45beSAndroid Build Coastguard Worker 
129*053f45beSAndroid Build Coastguard Worker 	*slope = (xy_sum - x_sum * y_sum / n) / (x2_sum - x_sum * x_sum / n);
130*053f45beSAndroid Build Coastguard Worker 	*intercept = (y_sum - *slope * x_sum) / n;
131*053f45beSAndroid Build Coastguard Worker 
132*053f45beSAndroid Build Coastguard Worker 	*r_max = 0.0, r2_sum = 0.0;
133*053f45beSAndroid Build Coastguard Worker 
134*053f45beSAndroid Build Coastguard Worker 	for (i = 0; i < n; i++) {
135*053f45beSAndroid Build Coastguard Worker 		x = samples[i].time;
136*053f45beSAndroid Build Coastguard Worker 		y = samples[i].offset;
137*053f45beSAndroid Build Coastguard Worker 		r = fabs(x * *slope + *intercept - y);
138*053f45beSAndroid Build Coastguard Worker 		if (*r_max < r)
139*053f45beSAndroid Build Coastguard Worker 			*r_max = r;
140*053f45beSAndroid Build Coastguard Worker 		r2_sum += r * r;
141*053f45beSAndroid Build Coastguard Worker 	}
142*053f45beSAndroid Build Coastguard Worker 
143*053f45beSAndroid Build Coastguard Worker 	*r_stddev = sqrt(r2_sum / n);
144*053f45beSAndroid Build Coastguard Worker }
145*053f45beSAndroid Build Coastguard Worker 
run_test(int calibration,double freq_base,double freq_step)146*053f45beSAndroid Build Coastguard Worker static int run_test(int calibration, double freq_base, double freq_step)
147*053f45beSAndroid Build Coastguard Worker {
148*053f45beSAndroid Build Coastguard Worker 	struct sample samples[SAMPLES];
149*053f45beSAndroid Build Coastguard Worker 	double intercept, slope, stddev1, max1, stddev2, max2;
150*053f45beSAndroid Build Coastguard Worker 	double freq_error1, freq_error2;
151*053f45beSAndroid Build Coastguard Worker 	int i;
152*053f45beSAndroid Build Coastguard Worker 
153*053f45beSAndroid Build Coastguard Worker 	set_frequency(freq_base);
154*053f45beSAndroid Build Coastguard Worker 
155*053f45beSAndroid Build Coastguard Worker 	for (i = 0; i < 10; i++)
156*053f45beSAndroid Build Coastguard Worker 		usleep(1e6 * MEAN_SAMPLE_INTERVAL / 10);
157*053f45beSAndroid Build Coastguard Worker 
158*053f45beSAndroid Build Coastguard Worker 	reset_ntp_error();
159*053f45beSAndroid Build Coastguard Worker 
160*053f45beSAndroid Build Coastguard Worker 	set_frequency(freq_base + freq_step);
161*053f45beSAndroid Build Coastguard Worker 
162*053f45beSAndroid Build Coastguard Worker 	for (i = 0; i < 10; i++)
163*053f45beSAndroid Build Coastguard Worker 		usleep(rand() % 2000000 * STEP_INTERVAL / 10);
164*053f45beSAndroid Build Coastguard Worker 
165*053f45beSAndroid Build Coastguard Worker 	set_frequency(freq_base);
166*053f45beSAndroid Build Coastguard Worker 
167*053f45beSAndroid Build Coastguard Worker 	for (i = 0; i < SAMPLES; i++) {
168*053f45beSAndroid Build Coastguard Worker 		usleep(rand() % 2000000 * MEAN_SAMPLE_INTERVAL);
169*053f45beSAndroid Build Coastguard Worker 		get_sample(&samples[i]);
170*053f45beSAndroid Build Coastguard Worker 	}
171*053f45beSAndroid Build Coastguard Worker 
172*053f45beSAndroid Build Coastguard Worker 	if (calibration) {
173*053f45beSAndroid Build Coastguard Worker 		regress(samples, SAMPLES, &intercept, &slope, &stddev1, &max1);
174*053f45beSAndroid Build Coastguard Worker 		mono_freq_offset = slope;
175*053f45beSAndroid Build Coastguard Worker 		printf("CLOCK_MONOTONIC_RAW frequency offset: %11.3f ppm\n",
176*053f45beSAndroid Build Coastguard Worker 		       1e6 * mono_freq_offset);
177*053f45beSAndroid Build Coastguard Worker 		return 0;
178*053f45beSAndroid Build Coastguard Worker 	}
179*053f45beSAndroid Build Coastguard Worker 
180*053f45beSAndroid Build Coastguard Worker 	regress(samples, SAMPLES / 2, &intercept, &slope, &stddev1, &max1);
181*053f45beSAndroid Build Coastguard Worker 	freq_error1 = slope * (1.0 - mono_freq_offset) - mono_freq_offset -
182*053f45beSAndroid Build Coastguard Worker 			freq_base;
183*053f45beSAndroid Build Coastguard Worker 
184*053f45beSAndroid Build Coastguard Worker 	regress(samples + SAMPLES / 2, SAMPLES / 2, &intercept, &slope,
185*053f45beSAndroid Build Coastguard Worker 		&stddev2, &max2);
186*053f45beSAndroid Build Coastguard Worker 	freq_error2 = slope * (1.0 - mono_freq_offset) - mono_freq_offset -
187*053f45beSAndroid Build Coastguard Worker 			freq_base;
188*053f45beSAndroid Build Coastguard Worker 
189*053f45beSAndroid Build Coastguard Worker 	printf("%6.0f %+10.3f %6.0f %7.0f %+10.3f %6.0f %7.0f\t",
190*053f45beSAndroid Build Coastguard Worker 	       1e6 * freq_step,
191*053f45beSAndroid Build Coastguard Worker 	       1e6 * freq_error1, 1e9 * stddev1, 1e9 * max1,
192*053f45beSAndroid Build Coastguard Worker 	       1e6 * freq_error2, 1e9 * stddev2, 1e9 * max2);
193*053f45beSAndroid Build Coastguard Worker 
194*053f45beSAndroid Build Coastguard Worker 	if (fabs(freq_error2) > MAX_FREQ_ERROR || stddev2 > MAX_STDDEV) {
195*053f45beSAndroid Build Coastguard Worker 		printf("[FAIL]\n");
196*053f45beSAndroid Build Coastguard Worker 		return 1;
197*053f45beSAndroid Build Coastguard Worker 	}
198*053f45beSAndroid Build Coastguard Worker 
199*053f45beSAndroid Build Coastguard Worker 	printf("[OK]\n");
200*053f45beSAndroid Build Coastguard Worker 	return 0;
201*053f45beSAndroid Build Coastguard Worker }
202*053f45beSAndroid Build Coastguard Worker 
init_test(void)203*053f45beSAndroid Build Coastguard Worker static void init_test(void)
204*053f45beSAndroid Build Coastguard Worker {
205*053f45beSAndroid Build Coastguard Worker 	struct timespec ts;
206*053f45beSAndroid Build Coastguard Worker 	struct sample sample;
207*053f45beSAndroid Build Coastguard Worker 
208*053f45beSAndroid Build Coastguard Worker 	if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts)) {
209*053f45beSAndroid Build Coastguard Worker 		perror("[FAIL] clock_gettime(CLOCK_MONOTONIC_RAW)");
210*053f45beSAndroid Build Coastguard Worker 		ksft_exit_fail();
211*053f45beSAndroid Build Coastguard Worker 	}
212*053f45beSAndroid Build Coastguard Worker 
213*053f45beSAndroid Build Coastguard Worker 	mono_raw_base = ts.tv_sec;
214*053f45beSAndroid Build Coastguard Worker 
215*053f45beSAndroid Build Coastguard Worker 	if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
216*053f45beSAndroid Build Coastguard Worker 		perror("[FAIL] clock_gettime(CLOCK_MONOTONIC)");
217*053f45beSAndroid Build Coastguard Worker 		ksft_exit_fail();
218*053f45beSAndroid Build Coastguard Worker 	}
219*053f45beSAndroid Build Coastguard Worker 
220*053f45beSAndroid Build Coastguard Worker 	mono_base = ts.tv_sec;
221*053f45beSAndroid Build Coastguard Worker 
222*053f45beSAndroid Build Coastguard Worker 	user_hz = sysconf(_SC_CLK_TCK);
223*053f45beSAndroid Build Coastguard Worker 
224*053f45beSAndroid Build Coastguard Worker 	precision = get_sample(&sample) / 2.0;
225*053f45beSAndroid Build Coastguard Worker 	printf("CLOCK_MONOTONIC_RAW+CLOCK_MONOTONIC precision: %.0f ns\t\t",
226*053f45beSAndroid Build Coastguard Worker 	       1e9 * precision);
227*053f45beSAndroid Build Coastguard Worker 
228*053f45beSAndroid Build Coastguard Worker 	if (precision > MAX_PRECISION)
229*053f45beSAndroid Build Coastguard Worker 		ksft_exit_skip("precision: %.0f ns > MAX_PRECISION: %.0f ns\n",
230*053f45beSAndroid Build Coastguard Worker 				1e9 * precision, 1e9 * MAX_PRECISION);
231*053f45beSAndroid Build Coastguard Worker 
232*053f45beSAndroid Build Coastguard Worker 	printf("[OK]\n");
233*053f45beSAndroid Build Coastguard Worker 	srand(ts.tv_sec ^ ts.tv_nsec);
234*053f45beSAndroid Build Coastguard Worker 
235*053f45beSAndroid Build Coastguard Worker 	run_test(1, 0.0, 0.0);
236*053f45beSAndroid Build Coastguard Worker }
237*053f45beSAndroid Build Coastguard Worker 
main(int argc,char ** argv)238*053f45beSAndroid Build Coastguard Worker int main(int argc, char **argv)
239*053f45beSAndroid Build Coastguard Worker {
240*053f45beSAndroid Build Coastguard Worker 	double freq_base, freq_step;
241*053f45beSAndroid Build Coastguard Worker 	int i, j, fails = 0;
242*053f45beSAndroid Build Coastguard Worker 
243*053f45beSAndroid Build Coastguard Worker 	init_test();
244*053f45beSAndroid Build Coastguard Worker 
245*053f45beSAndroid Build Coastguard Worker 	printf("Checking response to frequency step:\n");
246*053f45beSAndroid Build Coastguard Worker 	printf("  Step           1st interval              2nd interval\n");
247*053f45beSAndroid Build Coastguard Worker 	printf("             Freq    Dev     Max       Freq    Dev     Max\n");
248*053f45beSAndroid Build Coastguard Worker 
249*053f45beSAndroid Build Coastguard Worker 	for (i = 2; i >= 0; i--) {
250*053f45beSAndroid Build Coastguard Worker 		for (j = 0; j < 5; j++) {
251*053f45beSAndroid Build Coastguard Worker 			freq_base = (rand() % (1 << 24) - (1 << 23)) / 65536e6;
252*053f45beSAndroid Build Coastguard Worker 			freq_step = 10e-6 * (1 << (6 * i));
253*053f45beSAndroid Build Coastguard Worker 			fails += run_test(0, freq_base, freq_step);
254*053f45beSAndroid Build Coastguard Worker 		}
255*053f45beSAndroid Build Coastguard Worker 	}
256*053f45beSAndroid Build Coastguard Worker 
257*053f45beSAndroid Build Coastguard Worker 	set_frequency(0.0);
258*053f45beSAndroid Build Coastguard Worker 
259*053f45beSAndroid Build Coastguard Worker 	if (fails)
260*053f45beSAndroid Build Coastguard Worker 		return ksft_exit_fail();
261*053f45beSAndroid Build Coastguard Worker 
262*053f45beSAndroid Build Coastguard Worker 	return ksft_exit_pass();
263*053f45beSAndroid Build Coastguard Worker }
264