1 /* 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. 7 * 8 * Copyright (C) Miroslav Lichvar <mlichvar@redhat.com> 2017 9 * 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. 13 * 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. 18 */ 19 20 #include <math.h> 21 #include <stdio.h> 22 #include <sys/timex.h> 23 #include <time.h> 24 #include <unistd.h> 25 26 #include "../kselftest.h" 27 28 #define SAMPLES 100 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 35 36 struct sample { 37 double offset; 38 double time; 39 }; 40 41 static time_t mono_raw_base; 42 static time_t mono_base; 43 static long user_hz; 44 static double precision; 45 static double mono_freq_offset; 46 47 static double diff_timespec(struct timespec *ts1, struct timespec *ts2) 48 { 49 return ts1->tv_sec - ts2->tv_sec + (ts1->tv_nsec - ts2->tv_nsec) / 1e9; 50 } 51 52 static double get_sample(struct sample *sample) 53 { 54 double delay, mindelay = 0.0; 55 struct timespec ts1, ts2, ts3; 56 int i; 57 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); 62 63 ts1.tv_sec -= mono_raw_base; 64 ts2.tv_sec -= mono_base; 65 ts3.tv_sec -= mono_raw_base; 66 67 delay = diff_timespec(&ts3, &ts1); 68 if (delay <= 1e-9) { 69 i--; 70 continue; 71 } 72 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; 77 mindelay = delay; 78 } 79 } 80 81 return mindelay; 82 } 83 84 static void reset_ntp_error(void) 85 { 86 struct timex txc; 87 88 txc.modes = ADJ_SETOFFSET; 89 txc.time.tv_sec = 0; 90 txc.time.tv_usec = 0; 91 92 if (adjtimex(&txc) < 0) { 93 perror("[FAIL] adjtimex"); 94 ksft_exit_fail(); 95 } 96 } 97 98 static void set_frequency(double freq) 99 { 100 struct timex txc; 101 int tick_offset; 102 103 tick_offset = 1e6 * freq / user_hz; 104 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); 108 109 if (adjtimex(&txc) < 0) { 110 perror("[FAIL] adjtimex"); 111 ksft_exit_fail(); 112 } 113 } 114 115 static void regress(struct sample *samples, int n, double *intercept, 116 double *slope, double *r_stddev, double *r_max) 117 { 118 double x, y, r, x_sum, y_sum, xy_sum, x2_sum, r2_sum; 119 int i; 120 121 x_sum = 0.0, y_sum = 0.0, xy_sum = 0.0, x2_sum = 0.0; 122 123 for (i = 0; i < n; i++) { 124 x = samples[i].time; 125 y = samples[i].offset; 126 127 x_sum += x; 128 y_sum += y; 129 xy_sum += x * y; 130 x2_sum += x * x; 131 } 132 133 *slope = (xy_sum - x_sum * y_sum / n) / (x2_sum - x_sum * x_sum / n); 134 *intercept = (y_sum - *slope * x_sum) / n; 135 136 *r_max = 0.0, r2_sum = 0.0; 137 138 for (i = 0; i < n; i++) { 139 x = samples[i].time; 140 y = samples[i].offset; 141 r = fabs(x * *slope + *intercept - y); 142 if (*r_max < r) 143 *r_max = r; 144 r2_sum += r * r; 145 } 146 147 *r_stddev = sqrt(r2_sum / n); 148 } 149 150 static int run_test(int calibration, double freq_base, double freq_step) 151 { 152 struct sample samples[SAMPLES]; 153 double intercept, slope, stddev1, max1, stddev2, max2; 154 double freq_error1, freq_error2; 155 int i; 156 157 set_frequency(freq_base); 158 159 for (i = 0; i < 10; i++) 160 usleep(1e6 * MEAN_SAMPLE_INTERVAL / 10); 161 162 reset_ntp_error(); 163 164 set_frequency(freq_base + freq_step); 165 166 for (i = 0; i < 10; i++) 167 usleep(rand() % 2000000 * STEP_INTERVAL / 10); 168 169 set_frequency(freq_base); 170 171 for (i = 0; i < SAMPLES; i++) { 172 usleep(rand() % 2000000 * MEAN_SAMPLE_INTERVAL); 173 get_sample(&samples[i]); 174 } 175 176 if (calibration) { 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); 181 return 0; 182 } 183 184 regress(samples, SAMPLES / 2, &intercept, &slope, &stddev1, &max1); 185 freq_error1 = slope * (1.0 - mono_freq_offset) - mono_freq_offset - 186 freq_base; 187 188 regress(samples + SAMPLES / 2, SAMPLES / 2, &intercept, &slope, 189 &stddev2, &max2); 190 freq_error2 = slope * (1.0 - mono_freq_offset) - mono_freq_offset - 191 freq_base; 192 193 printf("%6.0f %+10.3f %6.0f %7.0f %+10.3f %6.0f %7.0f\t", 194 1e6 * freq_step, 195 1e6 * freq_error1, 1e9 * stddev1, 1e9 * max1, 196 1e6 * freq_error2, 1e9 * stddev2, 1e9 * max2); 197 198 if (fabs(freq_error2) > MAX_FREQ_ERROR || stddev2 > MAX_STDDEV) { 199 printf("[FAIL]\n"); 200 return 1; 201 } 202 203 printf("[OK]\n"); 204 return 0; 205 } 206 207 static void init_test(void) 208 { 209 struct timespec ts; 210 struct sample sample; 211 212 if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts)) { 213 perror("[FAIL] clock_gettime(CLOCK_MONOTONIC_RAW)"); 214 ksft_exit_fail(); 215 } 216 217 mono_raw_base = ts.tv_sec; 218 219 if (clock_gettime(CLOCK_MONOTONIC, &ts)) { 220 perror("[FAIL] clock_gettime(CLOCK_MONOTONIC)"); 221 ksft_exit_fail(); 222 } 223 224 mono_base = ts.tv_sec; 225 226 user_hz = sysconf(_SC_CLK_TCK); 227 228 precision = get_sample(&sample) / 2.0; 229 printf("CLOCK_MONOTONIC_RAW+CLOCK_MONOTONIC precision: %.0f ns\t\t", 230 1e9 * precision); 231 232 if (precision > MAX_PRECISION) { 233 printf("[SKIP]\n"); 234 ksft_exit_skip(); 235 } 236 237 printf("[OK]\n"); 238 srand(ts.tv_sec ^ ts.tv_nsec); 239 240 run_test(1, 0.0, 0.0); 241 } 242 243 int main(int argc, char **argv) 244 { 245 double freq_base, freq_step; 246 int i, j, fails = 0; 247 248 init_test(); 249 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"); 253 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); 259 } 260 } 261 262 set_frequency(0.0); 263 264 if (fails) 265 ksft_exit_fail(); 266 267 ksft_exit_pass(); 268 } 269