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

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

Version: ~ [ linux-5.6 ] ~ [ linux-5.5.13 ] ~ [ linux-5.4.28 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.113 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.174 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.217 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.217 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.82 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ 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 
140         tx1.modes = 0;
141         adjtimex(&tx1);
142 
143         if (tx1.offset || tx1.freq || tx1.tick != tickval) {
144                 printf("        [ERROR]\n");
145                 printf("\tUnexpected adjtimex return values, make sure ntpd is not running.\n");
146                 return -1;
147         }
148 
149         /*
150          * Here we use 100ppm difference as an error bound.
151          * We likely should see better, but some coarse clocksources
152          * cannot match the HZ tick size accurately, so we have a
153          * internal correction factor that doesn't scale exactly
154          * with the adjustment, resulting in > 10ppm error during
155          * a 10% adjustment. 100ppm also gives us more breathing
156          * room for interruptions during the measurement.
157          */
158         if (llabs(eppm - ppm) > 100) {
159                 printf("        [FAILED]\n");
160                 return -1;
161         }
162         printf("        [OK]\n");
163 
164         return  0;
165 }
166 
167 int main(int argv, char **argc)
168 {
169         struct timespec raw;
170         long tick, max, interval, err;
171         struct timex tx1;
172 
173         err = 0;
174         setbuf(stdout, NULL);
175 
176         if (clock_gettime(CLOCK_MONOTONIC_RAW, &raw)) {
177                 printf("ERR: NO CLOCK_MONOTONIC_RAW\n");
178                 return -1;
179         }
180 
181         printf("Each iteration takes about 15 seconds\n");
182 
183         systick = sysconf(_SC_CLK_TCK);
184         systick = USEC_PER_SEC/sysconf(_SC_CLK_TCK);
185         max = systick/10; /* +/- 10% */
186         interval = max/4; /* in 4 steps each side */
187 
188         for (tick = (systick - max); tick < (systick + max); tick += interval) {
189                 if (check_tick_adj(tick)) {
190                         err = 1;
191                         break;
192                 }
193         }
194 
195         /* Reset things to zero */
196         tx1.modes        = ADJ_TICK;
197         tx1.modes       |= ADJ_OFFSET;
198         tx1.modes       |= ADJ_FREQUENCY;
199 
200         tx1.offset       = 0;
201         tx1.freq         = 0;
202         tx1.tick         = systick;
203 
204         adjtimex(&tx1);
205 
206         if (err)
207                 return ksft_exit_fail();
208 
209         return ksft_exit_pass();
210 }
211 

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

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | 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.

osdn.jp