diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2017-06-21 03:08:13 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2017-06-21 03:08:13 -0400 |
commit | 17d9d6875ce89c0c98bb54d4d5649efb22986bf3 (patch) | |
tree | 6029577f3145777289c32255b448bd956b2fe5a5 | |
parent | f0cd9ae5d0df8668e76359a3e0e99856aa9c53b9 (diff) | |
parent | 767392565a3e618950fe1a5ff1ba11295f6332f4 (diff) |
Merge branch 'fortglx/4.13/time' of https://git.linaro.org/people/john.stultz/linux into timers/core
Merge time(keeping) updates from John Stultz:
"Just a small set of changes, the biggest changes being the MONOTONIC_RAW
handling cleanup, and a new kselftest from Miroslav. Also a a clear
warning deprecating CONFIG_GENERIC_TIME_VSYSCALL_OLD, which affects ppc
and ia64."
-rw-r--r-- | arch/arm64/kernel/vdso.c | 6 | ||||
-rw-r--r-- | include/linux/timekeeper_internal.h | 4 | ||||
-rw-r--r-- | kernel/time/timekeeping.c | 46 | ||||
-rw-r--r-- | tools/testing/selftests/timers/Makefile | 5 | ||||
-rw-r--r-- | tools/testing/selftests/timers/freq-step.c | 268 | ||||
-rw-r--r-- | tools/testing/selftests/timers/inconsistency-check.c | 4 |
6 files changed, 303 insertions, 30 deletions
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c index d0cb007fa482..7492d9009610 100644 --- a/arch/arm64/kernel/vdso.c +++ b/arch/arm64/kernel/vdso.c | |||
@@ -220,10 +220,8 @@ void update_vsyscall(struct timekeeper *tk) | |||
220 | if (!use_syscall) { | 220 | if (!use_syscall) { |
221 | /* tkr_mono.cycle_last == tkr_raw.cycle_last */ | 221 | /* tkr_mono.cycle_last == tkr_raw.cycle_last */ |
222 | vdso_data->cs_cycle_last = tk->tkr_mono.cycle_last; | 222 | vdso_data->cs_cycle_last = tk->tkr_mono.cycle_last; |
223 | vdso_data->raw_time_sec = tk->raw_time.tv_sec; | 223 | vdso_data->raw_time_sec = tk->raw_sec; |
224 | vdso_data->raw_time_nsec = (tk->raw_time.tv_nsec << | 224 | vdso_data->raw_time_nsec = tk->tkr_raw.xtime_nsec; |
225 | tk->tkr_raw.shift) + | ||
226 | tk->tkr_raw.xtime_nsec; | ||
227 | vdso_data->xtime_clock_sec = tk->xtime_sec; | 225 | vdso_data->xtime_clock_sec = tk->xtime_sec; |
228 | vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec; | 226 | vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec; |
229 | vdso_data->cs_mono_mult = tk->tkr_mono.mult; | 227 | vdso_data->cs_mono_mult = tk->tkr_mono.mult; |
diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h index f7043ccca81c..0a0a53daf2a2 100644 --- a/include/linux/timekeeper_internal.h +++ b/include/linux/timekeeper_internal.h | |||
@@ -51,7 +51,7 @@ struct tk_read_base { | |||
51 | * @clock_was_set_seq: The sequence number of clock was set events | 51 | * @clock_was_set_seq: The sequence number of clock was set events |
52 | * @cs_was_changed_seq: The sequence number of clocksource change events | 52 | * @cs_was_changed_seq: The sequence number of clocksource change events |
53 | * @next_leap_ktime: CLOCK_MONOTONIC time value of a pending leap-second | 53 | * @next_leap_ktime: CLOCK_MONOTONIC time value of a pending leap-second |
54 | * @raw_time: Monotonic raw base time in timespec64 format | 54 | * @raw_sec: CLOCK_MONOTONIC_RAW time in seconds |
55 | * @cycle_interval: Number of clock cycles in one NTP interval | 55 | * @cycle_interval: Number of clock cycles in one NTP interval |
56 | * @xtime_interval: Number of clock shifted nano seconds in one NTP | 56 | * @xtime_interval: Number of clock shifted nano seconds in one NTP |
57 | * interval. | 57 | * interval. |
@@ -93,7 +93,7 @@ struct timekeeper { | |||
93 | unsigned int clock_was_set_seq; | 93 | unsigned int clock_was_set_seq; |
94 | u8 cs_was_changed_seq; | 94 | u8 cs_was_changed_seq; |
95 | ktime_t next_leap_ktime; | 95 | ktime_t next_leap_ktime; |
96 | struct timespec64 raw_time; | 96 | u64 raw_sec; |
97 | 97 | ||
98 | /* The following members are for timekeeping internal use */ | 98 | /* The following members are for timekeeping internal use */ |
99 | u64 cycle_interval; | 99 | u64 cycle_interval; |
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index b602c48cb841..cedafa008de5 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -72,6 +72,10 @@ static inline void tk_normalize_xtime(struct timekeeper *tk) | |||
72 | tk->tkr_mono.xtime_nsec -= (u64)NSEC_PER_SEC << tk->tkr_mono.shift; | 72 | tk->tkr_mono.xtime_nsec -= (u64)NSEC_PER_SEC << tk->tkr_mono.shift; |
73 | tk->xtime_sec++; | 73 | tk->xtime_sec++; |
74 | } | 74 | } |
75 | while (tk->tkr_raw.xtime_nsec >= ((u64)NSEC_PER_SEC << tk->tkr_raw.shift)) { | ||
76 | tk->tkr_raw.xtime_nsec -= (u64)NSEC_PER_SEC << tk->tkr_raw.shift; | ||
77 | tk->raw_sec++; | ||
78 | } | ||
75 | } | 79 | } |
76 | 80 | ||
77 | static inline struct timespec64 tk_xtime(struct timekeeper *tk) | 81 | static inline struct timespec64 tk_xtime(struct timekeeper *tk) |
@@ -285,12 +289,14 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock) | |||
285 | /* if changing clocks, convert xtime_nsec shift units */ | 289 | /* if changing clocks, convert xtime_nsec shift units */ |
286 | if (old_clock) { | 290 | if (old_clock) { |
287 | int shift_change = clock->shift - old_clock->shift; | 291 | int shift_change = clock->shift - old_clock->shift; |
288 | if (shift_change < 0) | 292 | if (shift_change < 0) { |
289 | tk->tkr_mono.xtime_nsec >>= -shift_change; | 293 | tk->tkr_mono.xtime_nsec >>= -shift_change; |
290 | else | 294 | tk->tkr_raw.xtime_nsec >>= -shift_change; |
295 | } else { | ||
291 | tk->tkr_mono.xtime_nsec <<= shift_change; | 296 | tk->tkr_mono.xtime_nsec <<= shift_change; |
297 | tk->tkr_raw.xtime_nsec <<= shift_change; | ||
298 | } | ||
292 | } | 299 | } |
293 | tk->tkr_raw.xtime_nsec = 0; | ||
294 | 300 | ||
295 | tk->tkr_mono.shift = clock->shift; | 301 | tk->tkr_mono.shift = clock->shift; |
296 | tk->tkr_raw.shift = clock->shift; | 302 | tk->tkr_raw.shift = clock->shift; |
@@ -510,6 +516,7 @@ static void halt_fast_timekeeper(struct timekeeper *tk) | |||
510 | } | 516 | } |
511 | 517 | ||
512 | #ifdef CONFIG_GENERIC_TIME_VSYSCALL_OLD | 518 | #ifdef CONFIG_GENERIC_TIME_VSYSCALL_OLD |
519 | #warning Please contact your maintainers, as GENERIC_TIME_VSYSCALL_OLD compatibity will disappear soon. | ||
513 | 520 | ||
514 | static inline void update_vsyscall(struct timekeeper *tk) | 521 | static inline void update_vsyscall(struct timekeeper *tk) |
515 | { | 522 | { |
@@ -619,9 +626,6 @@ static inline void tk_update_ktime_data(struct timekeeper *tk) | |||
619 | nsec = (u32) tk->wall_to_monotonic.tv_nsec; | 626 | nsec = (u32) tk->wall_to_monotonic.tv_nsec; |
620 | tk->tkr_mono.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec); | 627 | tk->tkr_mono.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec); |
621 | 628 | ||
622 | /* Update the monotonic raw base */ | ||
623 | tk->tkr_raw.base = timespec64_to_ktime(tk->raw_time); | ||
624 | |||
625 | /* | 629 | /* |
626 | * The sum of the nanoseconds portions of xtime and | 630 | * The sum of the nanoseconds portions of xtime and |
627 | * wall_to_monotonic can be greater/equal one second. Take | 631 | * wall_to_monotonic can be greater/equal one second. Take |
@@ -631,6 +635,11 @@ static inline void tk_update_ktime_data(struct timekeeper *tk) | |||
631 | if (nsec >= NSEC_PER_SEC) | 635 | if (nsec >= NSEC_PER_SEC) |
632 | seconds++; | 636 | seconds++; |
633 | tk->ktime_sec = seconds; | 637 | tk->ktime_sec = seconds; |
638 | |||
639 | /* Update the monotonic raw base */ | ||
640 | seconds = tk->raw_sec; | ||
641 | nsec = (u32)(tk->tkr_raw.xtime_nsec >> tk->tkr_raw.shift); | ||
642 | tk->tkr_raw.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec); | ||
634 | } | 643 | } |
635 | 644 | ||
636 | /* must hold timekeeper_lock */ | 645 | /* must hold timekeeper_lock */ |
@@ -672,7 +681,6 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action) | |||
672 | static void timekeeping_forward_now(struct timekeeper *tk) | 681 | static void timekeeping_forward_now(struct timekeeper *tk) |
673 | { | 682 | { |
674 | u64 cycle_now, delta; | 683 | u64 cycle_now, delta; |
675 | u64 nsec; | ||
676 | 684 | ||
677 | cycle_now = tk_clock_read(&tk->tkr_mono); | 685 | cycle_now = tk_clock_read(&tk->tkr_mono); |
678 | delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last, tk->tkr_mono.mask); | 686 | delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last, tk->tkr_mono.mask); |
@@ -684,10 +692,13 @@ static void timekeeping_forward_now(struct timekeeper *tk) | |||
684 | /* If arch requires, add in get_arch_timeoffset() */ | 692 | /* If arch requires, add in get_arch_timeoffset() */ |
685 | tk->tkr_mono.xtime_nsec += (u64)arch_gettimeoffset() << tk->tkr_mono.shift; | 693 | tk->tkr_mono.xtime_nsec += (u64)arch_gettimeoffset() << tk->tkr_mono.shift; |
686 | 694 | ||
687 | tk_normalize_xtime(tk); | ||
688 | 695 | ||
689 | nsec = clocksource_cyc2ns(delta, tk->tkr_raw.mult, tk->tkr_raw.shift); | 696 | tk->tkr_raw.xtime_nsec += delta * tk->tkr_raw.mult; |
690 | timespec64_add_ns(&tk->raw_time, nsec); | 697 | |
698 | /* If arch requires, add in get_arch_timeoffset() */ | ||
699 | tk->tkr_raw.xtime_nsec += (u64)arch_gettimeoffset() << tk->tkr_raw.shift; | ||
700 | |||
701 | tk_normalize_xtime(tk); | ||
691 | } | 702 | } |
692 | 703 | ||
693 | /** | 704 | /** |
@@ -1373,19 +1384,18 @@ int timekeeping_notify(struct clocksource *clock) | |||
1373 | void getrawmonotonic64(struct timespec64 *ts) | 1384 | void getrawmonotonic64(struct timespec64 *ts) |
1374 | { | 1385 | { |
1375 | struct timekeeper *tk = &tk_core.timekeeper; | 1386 | struct timekeeper *tk = &tk_core.timekeeper; |
1376 | struct timespec64 ts64; | ||
1377 | unsigned long seq; | 1387 | unsigned long seq; |
1378 | u64 nsecs; | 1388 | u64 nsecs; |
1379 | 1389 | ||
1380 | do { | 1390 | do { |
1381 | seq = read_seqcount_begin(&tk_core.seq); | 1391 | seq = read_seqcount_begin(&tk_core.seq); |
1392 | ts->tv_sec = tk->raw_sec; | ||
1382 | nsecs = timekeeping_get_ns(&tk->tkr_raw); | 1393 | nsecs = timekeeping_get_ns(&tk->tkr_raw); |
1383 | ts64 = tk->raw_time; | ||
1384 | 1394 | ||
1385 | } while (read_seqcount_retry(&tk_core.seq, seq)); | 1395 | } while (read_seqcount_retry(&tk_core.seq, seq)); |
1386 | 1396 | ||
1387 | timespec64_add_ns(&ts64, nsecs); | 1397 | ts->tv_nsec = 0; |
1388 | *ts = ts64; | 1398 | timespec64_add_ns(ts, nsecs); |
1389 | } | 1399 | } |
1390 | EXPORT_SYMBOL(getrawmonotonic64); | 1400 | EXPORT_SYMBOL(getrawmonotonic64); |
1391 | 1401 | ||
@@ -1509,8 +1519,7 @@ void __init timekeeping_init(void) | |||
1509 | tk_setup_internals(tk, clock); | 1519 | tk_setup_internals(tk, clock); |
1510 | 1520 | ||
1511 | tk_set_xtime(tk, &now); | 1521 | tk_set_xtime(tk, &now); |
1512 | tk->raw_time.tv_sec = 0; | 1522 | tk->raw_sec = 0; |
1513 | tk->raw_time.tv_nsec = 0; | ||
1514 | if (boot.tv_sec == 0 && boot.tv_nsec == 0) | 1523 | if (boot.tv_sec == 0 && boot.tv_nsec == 0) |
1515 | boot = tk_xtime(tk); | 1524 | boot = tk_xtime(tk); |
1516 | 1525 | ||
@@ -2011,15 +2020,12 @@ static u64 logarithmic_accumulation(struct timekeeper *tk, u64 offset, | |||
2011 | *clock_set |= accumulate_nsecs_to_secs(tk); | 2020 | *clock_set |= accumulate_nsecs_to_secs(tk); |
2012 | 2021 | ||
2013 | /* Accumulate raw time */ | 2022 | /* Accumulate raw time */ |
2014 | tk->tkr_raw.xtime_nsec += (u64)tk->raw_time.tv_nsec << tk->tkr_raw.shift; | ||
2015 | tk->tkr_raw.xtime_nsec += tk->raw_interval << shift; | 2023 | tk->tkr_raw.xtime_nsec += tk->raw_interval << shift; |
2016 | snsec_per_sec = (u64)NSEC_PER_SEC << tk->tkr_raw.shift; | 2024 | snsec_per_sec = (u64)NSEC_PER_SEC << tk->tkr_raw.shift; |
2017 | while (tk->tkr_raw.xtime_nsec >= snsec_per_sec) { | 2025 | while (tk->tkr_raw.xtime_nsec >= snsec_per_sec) { |
2018 | tk->tkr_raw.xtime_nsec -= snsec_per_sec; | 2026 | tk->tkr_raw.xtime_nsec -= snsec_per_sec; |
2019 | tk->raw_time.tv_sec++; | 2027 | tk->raw_sec++; |
2020 | } | 2028 | } |
2021 | tk->raw_time.tv_nsec = tk->tkr_raw.xtime_nsec >> tk->tkr_raw.shift; | ||
2022 | tk->tkr_raw.xtime_nsec -= (u64)tk->raw_time.tv_nsec << tk->tkr_raw.shift; | ||
2023 | 2029 | ||
2024 | /* Accumulate error between NTP and clock interval */ | 2030 | /* Accumulate error between NTP and clock interval */ |
2025 | tk->ntp_error += tk->ntp_tick << shift; | 2031 | tk->ntp_error += tk->ntp_tick << shift; |
diff --git a/tools/testing/selftests/timers/Makefile b/tools/testing/selftests/timers/Makefile index 5fa1d7e9a915..5801bbefbe89 100644 --- a/tools/testing/selftests/timers/Makefile +++ b/tools/testing/selftests/timers/Makefile | |||
@@ -1,6 +1,6 @@ | |||
1 | BUILD_FLAGS = -DKTEST | 1 | BUILD_FLAGS = -DKTEST |
2 | CFLAGS += -O3 -Wl,-no-as-needed -Wall $(BUILD_FLAGS) | 2 | CFLAGS += -O3 -Wl,-no-as-needed -Wall $(BUILD_FLAGS) |
3 | LDFLAGS += -lrt -lpthread | 3 | LDFLAGS += -lrt -lpthread -lm |
4 | 4 | ||
5 | # these are all "safe" tests that don't modify | 5 | # these are all "safe" tests that don't modify |
6 | # system time or require escalated privileges | 6 | # system time or require escalated privileges |
@@ -8,7 +8,7 @@ TEST_GEN_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \ | |||
8 | inconsistency-check raw_skew threadtest rtctest | 8 | inconsistency-check raw_skew threadtest rtctest |
9 | 9 | ||
10 | TEST_GEN_PROGS_EXTENDED = alarmtimer-suspend valid-adjtimex adjtick change_skew \ | 10 | TEST_GEN_PROGS_EXTENDED = alarmtimer-suspend valid-adjtimex adjtick change_skew \ |
11 | skew_consistency clocksource-switch leap-a-day \ | 11 | skew_consistency clocksource-switch freq-step leap-a-day \ |
12 | leapcrash set-tai set-2038 set-tz | 12 | leapcrash set-tai set-2038 set-tz |
13 | 13 | ||
14 | 14 | ||
@@ -24,6 +24,7 @@ run_destructive_tests: run_tests | |||
24 | ./change_skew | 24 | ./change_skew |
25 | ./skew_consistency | 25 | ./skew_consistency |
26 | ./clocksource-switch | 26 | ./clocksource-switch |
27 | ./freq-step | ||
27 | ./leap-a-day -s -i 10 | 28 | ./leap-a-day -s -i 10 |
28 | ./leapcrash | 29 | ./leapcrash |
29 | ./set-tz | 30 | ./set-tz |
diff --git a/tools/testing/selftests/timers/freq-step.c b/tools/testing/selftests/timers/freq-step.c new file mode 100644 index 000000000000..e8c61830825a --- /dev/null +++ b/tools/testing/selftests/timers/freq-step.c | |||
@@ -0,0 +1,268 @@ | |||
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 | } | ||
diff --git a/tools/testing/selftests/timers/inconsistency-check.c b/tools/testing/selftests/timers/inconsistency-check.c index caf1bc9257c4..74c60e8759a0 100644 --- a/tools/testing/selftests/timers/inconsistency-check.c +++ b/tools/testing/selftests/timers/inconsistency-check.c | |||
@@ -118,7 +118,7 @@ int consistency_test(int clock_type, unsigned long seconds) | |||
118 | start_str = ctime(&t); | 118 | start_str = ctime(&t); |
119 | 119 | ||
120 | while (seconds == -1 || now - then < seconds) { | 120 | while (seconds == -1 || now - then < seconds) { |
121 | inconsistent = 0; | 121 | inconsistent = -1; |
122 | 122 | ||
123 | /* Fill list */ | 123 | /* Fill list */ |
124 | for (i = 0; i < CALLS_PER_LOOP; i++) | 124 | for (i = 0; i < CALLS_PER_LOOP; i++) |
@@ -130,7 +130,7 @@ int consistency_test(int clock_type, unsigned long seconds) | |||
130 | inconsistent = i; | 130 | inconsistent = i; |
131 | 131 | ||
132 | /* display inconsistency */ | 132 | /* display inconsistency */ |
133 | if (inconsistent) { | 133 | if (inconsistent >= 0) { |
134 | unsigned long long delta; | 134 | unsigned long long delta; |
135 | 135 | ||
136 | printf("\%s\n", start_str); | 136 | printf("\%s\n", start_str); |