diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-03 17:13:41 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-03 17:13:41 -0500 |
commit | 7b2a4306f9e7d64bb408a6df3bb419500578068a (patch) | |
tree | c8ce206194c47c8bd50ee6b5828e0c734d571200 /tools | |
parent | 316dde2fe95b33657de1fc2db54bfc16aa065790 (diff) | |
parent | 03f136a2074b2b8890da4a24df7104558ad0da48 (diff) |
Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer updates from Thomas Gleixner:
"The timer departement provides:
- More y2038 work in the area of ntp and pps.
- Optimization of posix cpu timers
- New time related selftests
- Some new clocksource drivers
- The usual pile of fixes, cleanups and improvements"
* 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (25 commits)
timeconst: Update path in comment
timers/x86/hpet: Type adjustments
clocksource/drivers/armada-370-xp: Implement ARM delay timer
clocksource/drivers/tango_xtal: Add new timer for Tango SoCs
clocksource/drivers/imx: Allow timer irq affinity change
clocksource/drivers/exynos_mct: Use container_of() instead of this_cpu_ptr()
clocksource/drivers/h8300_*: Remove unneeded memset()s
clocksource/drivers/sh_cmt: Remove unneeded memset() in sh_cmt_setup()
clocksource/drivers/em_sti: Remove unneeded memset()s
clocksource/drivers/mediatek: Use GPT as sched clock source
clockevents/drivers/mtk: Fix spurious interrupt leading to crash
posix_cpu_timer: Reduce unnecessary sighand lock contention
posix_cpu_timer: Convert cputimer->running to bool
posix_cpu_timer: Check thread timers only when there are active thread timers
posix_cpu_timer: Optimize fastpath_timer_check()
timers, kselftest: Add 'adjtick' test to validate adjtimex() tick adjustments
timers: Use __fls in apply_slack()
clocksource: Remove return statement from void functions
net: sfc: avoid using timespec
ntp/pps: use y2038 safe types in pps_event_time
...
Diffstat (limited to 'tools')
-rw-r--r-- | tools/testing/selftests/timers/Makefile | 3 | ||||
-rw-r--r-- | tools/testing/selftests/timers/adjtick.c | 221 |
2 files changed, 223 insertions, 1 deletions
diff --git a/tools/testing/selftests/timers/Makefile b/tools/testing/selftests/timers/Makefile index 89a3f44bf355..4a1be1b75a7f 100644 --- a/tools/testing/selftests/timers/Makefile +++ b/tools/testing/selftests/timers/Makefile | |||
@@ -8,7 +8,7 @@ LDFLAGS += -lrt -lpthread | |||
8 | TEST_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \ | 8 | TEST_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \ |
9 | inconsistency-check raw_skew threadtest rtctest | 9 | inconsistency-check raw_skew threadtest rtctest |
10 | 10 | ||
11 | TEST_PROGS_EXTENDED = alarmtimer-suspend valid-adjtimex change_skew \ | 11 | TEST_PROGS_EXTENDED = alarmtimer-suspend valid-adjtimex adjtick change_skew \ |
12 | skew_consistency clocksource-switch leap-a-day \ | 12 | skew_consistency clocksource-switch leap-a-day \ |
13 | leapcrash set-tai set-2038 | 13 | leapcrash set-tai set-2038 |
14 | 14 | ||
@@ -24,6 +24,7 @@ include ../lib.mk | |||
24 | run_destructive_tests: run_tests | 24 | run_destructive_tests: run_tests |
25 | ./alarmtimer-suspend | 25 | ./alarmtimer-suspend |
26 | ./valid-adjtimex | 26 | ./valid-adjtimex |
27 | ./adjtick | ||
27 | ./change_skew | 28 | ./change_skew |
28 | ./skew_consistency | 29 | ./skew_consistency |
29 | ./clocksource-switch | 30 | ./clocksource-switch |
diff --git a/tools/testing/selftests/timers/adjtick.c b/tools/testing/selftests/timers/adjtick.c new file mode 100644 index 000000000000..9887fd538fec --- /dev/null +++ b/tools/testing/selftests/timers/adjtick.c | |||
@@ -0,0 +1,221 @@ | |||
1 | /* adjtimex() tick adjustment test | ||
2 | * by: John Stultz <john.stultz@linaro.org> | ||
3 | * (C) Copyright Linaro Limited 2015 | ||
4 | * Licensed under the GPLv2 | ||
5 | * | ||
6 | * To build: | ||
7 | * $ gcc adjtick.c -o adjtick -lrt | ||
8 | * | ||
9 | * This program is free software: you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation, either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | */ | ||
19 | #include <stdio.h> | ||
20 | #include <unistd.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <sys/time.h> | ||
23 | #include <sys/timex.h> | ||
24 | #include <time.h> | ||
25 | |||
26 | #ifdef KTEST | ||
27 | #include "../kselftest.h" | ||
28 | #else | ||
29 | static inline int ksft_exit_pass(void) | ||
30 | { | ||
31 | exit(0); | ||
32 | } | ||
33 | static inline int ksft_exit_fail(void) | ||
34 | { | ||
35 | exit(1); | ||
36 | } | ||
37 | #endif | ||
38 | |||
39 | #define CLOCK_MONOTONIC_RAW 4 | ||
40 | |||
41 | #define NSEC_PER_SEC 1000000000LL | ||
42 | #define USEC_PER_SEC 1000000 | ||
43 | |||
44 | #define MILLION 1000000 | ||
45 | |||
46 | long systick; | ||
47 | |||
48 | long long llabs(long long val) | ||
49 | { | ||
50 | if (val < 0) | ||
51 | val = -val; | ||
52 | return val; | ||
53 | } | ||
54 | |||
55 | unsigned long long ts_to_nsec(struct timespec ts) | ||
56 | { | ||
57 | return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; | ||
58 | } | ||
59 | |||
60 | struct timespec nsec_to_ts(long long ns) | ||
61 | { | ||
62 | struct timespec ts; | ||
63 | |||
64 | ts.tv_sec = ns/NSEC_PER_SEC; | ||
65 | ts.tv_nsec = ns%NSEC_PER_SEC; | ||
66 | |||
67 | return ts; | ||
68 | } | ||
69 | |||
70 | long long diff_timespec(struct timespec start, struct timespec end) | ||
71 | { | ||
72 | long long start_ns, end_ns; | ||
73 | |||
74 | start_ns = ts_to_nsec(start); | ||
75 | end_ns = ts_to_nsec(end); | ||
76 | |||
77 | return end_ns - start_ns; | ||
78 | } | ||
79 | |||
80 | void get_monotonic_and_raw(struct timespec *mon, struct timespec *raw) | ||
81 | { | ||
82 | struct timespec start, mid, end; | ||
83 | long long diff = 0, tmp; | ||
84 | int i; | ||
85 | |||
86 | clock_gettime(CLOCK_MONOTONIC, mon); | ||
87 | clock_gettime(CLOCK_MONOTONIC_RAW, raw); | ||
88 | |||
89 | /* Try to get a more tightly bound pairing */ | ||
90 | for (i = 0; i < 3; i++) { | ||
91 | long long newdiff; | ||
92 | |||
93 | clock_gettime(CLOCK_MONOTONIC, &start); | ||
94 | clock_gettime(CLOCK_MONOTONIC_RAW, &mid); | ||
95 | clock_gettime(CLOCK_MONOTONIC, &end); | ||
96 | |||
97 | newdiff = diff_timespec(start, end); | ||
98 | if (diff == 0 || newdiff < diff) { | ||
99 | diff = newdiff; | ||
100 | *raw = mid; | ||
101 | tmp = (ts_to_nsec(start) + ts_to_nsec(end))/2; | ||
102 | *mon = nsec_to_ts(tmp); | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | |||
107 | long long get_ppm_drift(void) | ||
108 | { | ||
109 | struct timespec mon_start, raw_start, mon_end, raw_end; | ||
110 | long long delta1, delta2, eppm; | ||
111 | |||
112 | get_monotonic_and_raw(&mon_start, &raw_start); | ||
113 | |||
114 | sleep(15); | ||
115 | |||
116 | get_monotonic_and_raw(&mon_end, &raw_end); | ||
117 | |||
118 | delta1 = diff_timespec(mon_start, mon_end); | ||
119 | delta2 = diff_timespec(raw_start, raw_end); | ||
120 | |||
121 | eppm = (delta1*MILLION)/delta2 - MILLION; | ||
122 | |||
123 | return eppm; | ||
124 | } | ||
125 | |||
126 | int check_tick_adj(long tickval) | ||
127 | { | ||
128 | long long eppm, ppm; | ||
129 | struct timex tx1; | ||
130 | |||
131 | tx1.modes = ADJ_TICK; | ||
132 | tx1.modes |= ADJ_OFFSET; | ||
133 | tx1.modes |= ADJ_FREQUENCY; | ||
134 | tx1.modes |= ADJ_STATUS; | ||
135 | |||
136 | tx1.status = STA_PLL; | ||
137 | tx1.offset = 0; | ||
138 | tx1.freq = 0; | ||
139 | tx1.tick = tickval; | ||
140 | |||
141 | adjtimex(&tx1); | ||
142 | |||
143 | sleep(1); | ||
144 | |||
145 | ppm = ((long long)tickval * MILLION)/systick - MILLION; | ||
146 | printf("Estimating tick (act: %ld usec, %lld ppm): ", tickval, ppm); | ||
147 | |||
148 | eppm = get_ppm_drift(); | ||
149 | printf("%lld usec, %lld ppm", systick + (systick * eppm / MILLION), eppm); | ||
150 | |||
151 | tx1.modes = 0; | ||
152 | adjtimex(&tx1); | ||
153 | |||
154 | if (tx1.offset || tx1.freq || tx1.tick != tickval) { | ||
155 | printf(" [ERROR]\n"); | ||
156 | printf("\tUnexpected adjtimex return values, make sure ntpd is not running.\n"); | ||
157 | return -1; | ||
158 | } | ||
159 | |||
160 | /* | ||
161 | * Here we use 100ppm difference as an error bound. | ||
162 | * We likely should see better, but some coarse clocksources | ||
163 | * cannot match the HZ tick size accurately, so we have a | ||
164 | * internal correction factor that doesn't scale exactly | ||
165 | * with the adjustment, resulting in > 10ppm error during | ||
166 | * a 10% adjustment. 100ppm also gives us more breathing | ||
167 | * room for interruptions during the measurement. | ||
168 | */ | ||
169 | if (llabs(eppm - ppm) > 100) { | ||
170 | printf(" [FAILED]\n"); | ||
171 | return -1; | ||
172 | } | ||
173 | printf(" [OK]\n"); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | int main(int argv, char **argc) | ||
179 | { | ||
180 | struct timespec raw; | ||
181 | long tick, max, interval, err; | ||
182 | struct timex tx1; | ||
183 | |||
184 | err = 0; | ||
185 | setbuf(stdout, NULL); | ||
186 | |||
187 | if (clock_gettime(CLOCK_MONOTONIC_RAW, &raw)) { | ||
188 | printf("ERR: NO CLOCK_MONOTONIC_RAW\n"); | ||
189 | return -1; | ||
190 | } | ||
191 | |||
192 | printf("Each iteration takes about 15 seconds\n"); | ||
193 | |||
194 | systick = sysconf(_SC_CLK_TCK); | ||
195 | systick = USEC_PER_SEC/sysconf(_SC_CLK_TCK); | ||
196 | max = systick/10; /* +/- 10% */ | ||
197 | interval = max/4; /* in 4 steps each side */ | ||
198 | |||
199 | for (tick = (systick - max); tick < (systick + max); tick += interval) { | ||
200 | if (check_tick_adj(tick)) { | ||
201 | err = 1; | ||
202 | break; | ||
203 | } | ||
204 | } | ||
205 | |||
206 | /* Reset things to zero */ | ||
207 | tx1.modes = ADJ_TICK; | ||
208 | tx1.modes |= ADJ_OFFSET; | ||
209 | tx1.modes |= ADJ_FREQUENCY; | ||
210 | |||
211 | tx1.offset = 0; | ||
212 | tx1.freq = 0; | ||
213 | tx1.tick = systick; | ||
214 | |||
215 | adjtimex(&tx1); | ||
216 | |||
217 | if (err) | ||
218 | return ksft_exit_fail(); | ||
219 | |||
220 | return ksft_exit_pass(); | ||
221 | } | ||