~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/timers/adjtick.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 #include "../kselftest.h"
 27 
 28 #define CLOCK_MONOTONIC_RAW     4
 29 
 30 #define NSEC_PER_SEC            1000000000LL
 31 #define USEC_PER_SEC            1000000
 32 
 33 #define MILLION                 1000000
 34 
 35 long systick;
 36 
 37 long long llabs(long long val)
 38 {
 39         if (val < 0)
 40                 val = -val;
 41         return val;
 42 }
 43 
 44 unsigned long long ts_to_nsec(struct timespec ts)
 45 {
 46         return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
 47 }
 48 
 49 struct timespec nsec_to_ts(long long ns)
 50 {
 51         struct timespec ts;
 52 
 53         ts.tv_sec = ns/NSEC_PER_SEC;
 54         ts.tv_nsec = ns%NSEC_PER_SEC;
 55 
 56         return ts;
 57 }
 58 
 59 long long diff_timespec(struct timespec start, struct timespec end)
 60 {
 61         long long start_ns, end_ns;
 62 
 63         start_ns = ts_to_nsec(start);
 64         end_ns = ts_to_nsec(end);
 65 
 66         return end_ns - start_ns;
 67 }
 68 
 69 void get_monotonic_and_raw(struct timespec *mon, struct timespec *raw)
 70 {
 71         struct timespec start, mid, end;
 72         long long diff = 0, tmp;
 73         int i;
 74 
 75         clock_gettime(CLOCK_MONOTONIC, mon);
 76         clock_gettime(CLOCK_MONOTONIC_RAW, raw);
 77 
 78         /* Try to get a more tightly bound pairing */
 79         for (i = 0; i < 3; i++) {
 80                 long long newdiff;
 81 
 82                 clock_gettime(CLOCK_MONOTONIC, &start);
 83                 clock_gettime(CLOCK_MONOTONIC_RAW, &mid);
 84                 clock_gettime(CLOCK_MONOTONIC, &end);
 85 
 86                 newdiff = diff_timespec(start, end);
 87                 if (diff == 0 || newdiff < diff) {
 88                         diff = newdiff;
 89                         *raw = mid;
 90                         tmp = (ts_to_nsec(start) + ts_to_nsec(end))/2;
 91                         *mon = nsec_to_ts(tmp);
 92                 }
 93         }
 94 }
 95 
 96 long long get_ppm_drift(void)
 97 {
 98         struct timespec mon_start, raw_start, mon_end, raw_end;
 99         long long delta1, delta2, eppm;
100 
101         get_monotonic_and_raw(&mon_start, &raw_start);
102 
103         sleep(15);
104 
105         get_monotonic_and_raw(&mon_end, &raw_end);
106 
107         delta1 = diff_timespec(mon_start, mon_end);
108         delta2 = diff_timespec(raw_start, raw_end);
109 
110         eppm = (delta1*MILLION)/delta2 - MILLION;
111 
112         return eppm;
113 }
114 
115 int check_tick_adj(long tickval)
116 {
117         long long eppm, ppm;
118         struct timex tx1;
119 
120         tx1.modes        = ADJ_TICK;
121         tx1.modes       |= ADJ_OFFSET;
122         tx1.modes       |= ADJ_FREQUENCY;
123         tx1.modes       |= ADJ_STATUS;
124 
125         tx1.status      = STA_PLL;
126         tx1.offset      = 0;
127         tx1.freq        = 0;
128         tx1.tick        = tickval;
129 
130         adjtimex(&tx1);
131 
132         sleep(1);
133 
134         ppm = ((long long)tickval * MILLION)/systick - MILLION;
135         printf("Estimating tick (act: %ld usec, %lld ppm): ", tickval, ppm);
136 
137         eppm = get_ppm_drift();
138         printf("%lld usec, %lld ppm", systick + (systick * eppm / MILLION), eppm);
139         fflush(stdout);
140 
141         tx1.modes = 0;
142         adjtimex(&tx1);
143 
144         if (tx1.offset || tx1.freq || tx1.tick != tickval) {
145                 printf("        [ERROR]\n");
146                 printf("\tUnexpected adjtimex return values, make sure ntpd is not running.\n");
147                 return -1;
148         }
149 
150         /*
151          * Here we use 100ppm difference as an error bound.
152          * We likely should see better, but some coarse clocksources
153          * cannot match the HZ tick size accurately, so we have a
154          * internal correction factor that doesn't scale exactly
155          * with the adjustment, resulting in > 10ppm error during
156          * a 10% adjustment. 100ppm also gives us more breathing
157          * room for interruptions during the measurement.
158          */
159         if (llabs(eppm - ppm) > 100) {
160                 printf("        [FAILED]\n");
161                 return -1;
162         }
163         printf("        [OK]\n");
164 
165         return  0;
166 }
167 
168 int main(int argc, char **argv)
169 {
170         struct timespec raw;
171         long tick, max, interval, err;
172         struct timex tx1;
173 
174         err = 0;
175         setbuf(stdout, NULL);
176 
177         if (clock_gettime(CLOCK_MONOTONIC_RAW, &raw)) {
178                 printf("ERR: NO CLOCK_MONOTONIC_RAW\n");
179                 return -1;
180         }
181 
182         printf("Each iteration takes about 15 seconds\n");
183 
184         systick = sysconf(_SC_CLK_TCK);
185         systick = USEC_PER_SEC/sysconf(_SC_CLK_TCK);
186         max = systick/10; /* +/- 10% */
187         interval = max/4; /* in 4 steps each side */
188 
189         for (tick = (systick - max); tick < (systick + max); tick += interval) {
190                 if (check_tick_adj(tick)) {
191                         err = 1;
192                         break;
193                 }
194         }
195 
196         /* Reset things to zero */
197         tx1.modes        = ADJ_TICK;
198         tx1.modes       |= ADJ_OFFSET;
199         tx1.modes       |= ADJ_FREQUENCY;
200 
201         tx1.offset       = 0;
202         tx1.freq         = 0;
203         tx1.tick         = systick;
204 
205         adjtimex(&tx1);
206 
207         if (err)
208                 ksft_exit_fail();
209 
210         ksft_exit_pass();
211 }
212 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php