replace same ds with generic one
[ana-net.git] / opt / time-warp-test.c
blob9ee59535236fd126fccdb16603c0a9cf7299f47f
1 /*
2 * Copyright (C) 2005, Ingo Molnar
4 * time-warp-test.c: check TSC synchronity on x86 CPUs. Also detects
5 * gettimeofday()-level time warps.
7 * Compile with: gcc -Wall -O2 -o time-warp-test time-warp-test.c -lrt
8 */
9 #include <stdio.h>
10 #include <stdarg.h>
11 #include <stdlib.h>
12 #include <signal.h>
13 #include <sys/wait.h>
14 #include <linux/unistd.h>
15 #include <unistd.h>
16 #include <string.h>
17 #include <pwd.h>
18 #include <grp.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/time.h>
23 #include <regex.h>
24 #include <fcntl.h>
25 #include <time.h>
26 #include <sys/mman.h>
27 #include <dlfcn.h>
28 #include <sys/socket.h>
29 #include <ctype.h>
30 #include <assert.h>
31 #include <sched.h>
32 #include <time.h>
34 #define TEST_TSC 0
35 #define TEST_TOD 1
36 #define TEST_CLOCK 0
37 #define DEBUG 0
39 #if !TEST_TSC && !TEST_TOD && !TEST_CLOCK
40 # error this setting makes no sense ...
41 #endif
43 #if DEBUG
44 # define Printf(x...) printf(x)
45 #else
46 # define Printf(x...) do { } while (0)
47 #endif
50 * Shared locks and variables between the test tasks:
52 enum {
53 SHARED_LOCK = 0,
54 SHARED_TSC = 2,
55 SHARED_TOD = 4,
56 SHARED_CLOCK = 6,
57 SHARED_WORST_TSC = 8,
58 SHARED_WORST_TOD = 10,
59 SHARED_WORST_CLOCK = 12,
60 SHARED_NR_TSC_LOOPS = 14,
61 SHARED_NR_TSC_WARPS = 16,
62 SHARED_NR_TOD_LOOPS = 18,
63 SHARED_NR_TOD_WARPS = 20,
64 SHARED_NR_CLOCK_LOOPS = 22,
65 SHARED_NR_CLOCK_WARPS = 24,
66 SHARED_END = 26,
69 #define SHARED(x) (*(shared + SHARED_##x))
70 #define SHARED_LL(x) (*(long long *)(shared + SHARED_##x))
72 #define BUG_ON(c) assert(!(c))
74 typedef unsigned long long cycles_t;
75 typedef unsigned long long usecs_t;
76 typedef unsigned long long u64;
78 #ifdef __x86_64__
79 #define DECLARE_ARGS(val, low, high) unsigned low, high
80 #define EAX_EDX_VAL(val, low, high) ((low) | ((u64)(high) << 32))
81 #define EAX_EDX_ARGS(val, low, high) "a" (low), "d" (high)
82 #define EAX_EDX_RET(val, low, high) "=a" (low), "=d" (high)
83 #else
84 #define DECLARE_ARGS(val, low, high) unsigned long long val
85 #define EAX_EDX_VAL(val, low, high) (val)
86 #define EAX_EDX_ARGS(val, low, high) "A" (val)
87 #define EAX_EDX_RET(val, low, high) "=A" (val)
88 #endif
90 static inline unsigned long long __rdtscll(void)
92 DECLARE_ARGS(val, low, high);
94 asm volatile("cpuid; rdtsc" : EAX_EDX_RET(val, low, high));
96 return EAX_EDX_VAL(val, low, high);
99 #define rdtscll(val) do { (val) = __rdtscll(); } while (0)
101 #define rdtod(val) \
102 do { \
103 struct timeval tv; \
105 gettimeofday(&tv, NULL); \
106 (val) = tv.tv_sec * 1000000ULL + tv.tv_usec; \
107 } while (0)
109 #define rdclock(val) \
110 do { \
111 struct timespec ts; \
113 clock_gettime(CLOCK_MONOTONIC, &ts); \
114 (val) = ts.tv_sec * 1000000000ULL + ts.tv_nsec; \
115 } while (0)
117 static unsigned long *setup_shared_var(void)
119 char zerobuff [4096] = { 0, };
120 int ret, fd;
121 unsigned long *buf;
123 fd = creat(".tmp_mmap", 0700);
124 BUG_ON(fd == -1);
125 close(fd);
127 fd = open(".tmp_mmap", O_RDWR|O_CREAT|O_TRUNC, 00666);
128 BUG_ON(fd == -1);
129 ret = write(fd, zerobuff, 4096);
130 BUG_ON(ret != 4096);
132 buf = (void *)mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
133 BUG_ON(buf == (void *)-1);
135 close(fd);
136 unlink(".tmp_mmap");
138 return buf;
141 static inline void lock(unsigned long *flag)
143 #if 0
144 __asm__ __volatile__(
145 "1: lock; btsl $0,%0\n"
146 "jc 1b\n"
147 : "=g"(*flag) : : "memory");
148 #else
149 __asm__ __volatile__(
150 "1: lock; btsl $0,%0\n\t"
151 "jnc 3f\n"
152 "2: testl $1,%0\n\t"
153 "je 1b\n\t"
154 "rep ; nop\n\t"
155 "jmp 2b\n"
156 "3:"
157 : "+m"(*flag) : : "memory");
158 #endif
161 static inline void unlock(unsigned long *flag)
163 #if 0
164 __asm__ __volatile__(
165 "lock; btrl $0,%0\n"
166 : "=g"(*flag) :: "memory");
167 __asm__ __volatile__("rep; nop");
168 #else
169 __asm__ __volatile__("movl $0,%0; rep; nop" : "=g"(*flag) :: "memory");
170 #endif
173 static void print_status(unsigned long *shared)
175 const char progress[] = "\\|/-";
177 static unsigned long long sum_tsc_loops, sum_tod_loops, sum_clock_loops,
178 sum_tod;
179 static unsigned int count1, count2;
180 static usecs_t prev_tod;
182 usecs_t tod;
184 if (!prev_tod)
185 rdtod(prev_tod);
187 count1++;
188 if (count1 < 1000)
189 return;
190 count1 = 0;
192 rdtod(tod);
193 if (abs(tod - prev_tod) < 100000ULL)
194 return;
196 sum_tod += tod - prev_tod;
197 sum_tsc_loops += SHARED_LL(NR_TSC_LOOPS);
198 sum_tod_loops += SHARED_LL(NR_TOD_LOOPS);
199 sum_clock_loops += SHARED_LL(NR_CLOCK_LOOPS);
200 SHARED_LL(NR_TSC_LOOPS) = 0;
201 SHARED_LL(NR_TOD_LOOPS) = 0;
202 SHARED_LL(NR_CLOCK_LOOPS) = 0;
204 if (TEST_TSC)
205 printf(" | TSC: %.2fus, fail:%ld",
206 (double)sum_tod/(double)sum_tsc_loops,
207 SHARED(NR_TSC_WARPS));
209 if (TEST_TOD)
210 printf(" | TOD: %.2fus, fail:%ld",
211 (double)sum_tod/(double)sum_tod_loops,
212 SHARED(NR_TOD_WARPS));
214 if (TEST_CLOCK)
215 printf(" | CLK: %.2fus, fail:%ld",
216 (double)sum_tod/(double)sum_clock_loops,
217 SHARED(NR_CLOCK_WARPS));
219 prev_tod = tod;
220 count2++;
221 printf(" %c\r", progress[count2 & 3]);
222 fflush(stdout);
225 static inline void test_TSC(unsigned long *shared)
227 #if TEST_TSC
228 cycles_t t0, t1;
229 long long delta;
231 lock(&SHARED(LOCK));
232 rdtscll(t1);
233 t0 = SHARED_LL(TSC);
234 SHARED_LL(TSC) = t1;
235 SHARED_LL(NR_TSC_LOOPS)++;
236 unlock(&SHARED(LOCK));
238 delta = t1-t0;
239 if (delta < 0) {
240 lock(&SHARED(LOCK));
241 SHARED(NR_TSC_WARPS)++;
242 if (delta < SHARED_LL(WORST_TSC)) {
243 SHARED_LL(WORST_TSC) = delta;
244 fprintf(stderr, "\rnew TSC-warp maximum: %9Ld cycles, %016Lx -> %016Lx\n",
245 delta, t0, t1);
247 unlock(&SHARED(LOCK));
249 if (!((unsigned long)t0 & 31))
250 asm volatile ("rep; nop");
251 #endif
254 static inline void test_TOD(unsigned long *shared)
256 #if TEST_TOD
257 usecs_t T0, T1;
258 long long delta;
260 lock(&SHARED(LOCK));
261 rdtod(T1);
262 T0 = SHARED_LL(TOD);
263 SHARED_LL(TOD) = T1;
264 SHARED_LL(NR_TOD_LOOPS)++;
265 unlock(&SHARED(LOCK));
267 delta = T1-T0;
268 if (delta < 0) {
269 lock(&SHARED(LOCK));
270 SHARED(NR_TOD_WARPS)++;
271 if (delta < SHARED_LL(WORST_TOD)) {
272 SHARED_LL(WORST_TOD) = delta;
273 fprintf(stderr, "\rnew TOD-warp maximum: %9Ld usecs, %016Lx -> %016Lx\n",
274 delta, T0, T1);
276 unlock(&SHARED(LOCK));
278 #endif
281 static inline void test_CLOCK(unsigned long *shared)
283 #if TEST_CLOCK
284 usecs_t T0, T1;
285 long long delta;
287 lock(&SHARED(LOCK));
288 rdclock(T1);
289 T0 = SHARED_LL(CLOCK);
290 SHARED_LL(CLOCK) = T1;
291 SHARED_LL(NR_CLOCK_LOOPS)++;
292 unlock(&SHARED(LOCK));
294 delta = T1-T0;
295 if (delta < 0) {
296 lock(&SHARED(LOCK));
297 SHARED(NR_CLOCK_WARPS)++;
298 if (delta < SHARED_LL(WORST_CLOCK)) {
299 SHARED_LL(WORST_CLOCK) = delta;
300 fprintf(stderr, "\rnew CLOCK-warp maximum: %9Ld nsecs, %016Lx -> %016Lx\n",
301 delta, T0, T1);
303 unlock(&SHARED(LOCK));
305 #endif
308 int main(int argc, char **argv)
310 int i, parent, me;
311 unsigned long *shared;
312 unsigned long cpus, tasks;
314 cpus = system("exit `grep ^processor /proc/cpuinfo | wc -l`");
315 cpus = WEXITSTATUS(cpus);
317 if (argc > 2) {
318 usage:
319 fprintf(stderr,
320 "usage: tsc-sync-test <threads>\n");
321 exit(-1);
323 if (argc == 2) {
324 tasks = atol(argv[1]);
325 if (!tasks)
326 goto usage;
327 } else
328 tasks = cpus;
330 printf("%ld CPUs, running %ld parallel test-tasks.\n", cpus, tasks);
331 printf("checking for time-warps via:\n"
332 #if TEST_TSC
333 "- read time stamp counter (RDTSC) instruction (cycle resolution)\n"
334 #endif
335 #if TEST_TOD
336 "- gettimeofday (TOD) syscall (usec resolution)\n"
337 #endif
338 #if TEST_CLOCK
339 "- clock_gettime(CLOCK_MONOTONIC) syscall (nsec resolution)\n"
340 #endif
341 "\n"
344 shared = setup_shared_var();
345 parent = getpid();
346 for (i = 1; i < tasks; i++) {
347 if (!fork())
348 break;
350 me = getpid();
352 while (1) {
353 int i;
355 for (i = 0; i < 10; i++)
356 test_TSC(shared);
357 for (i = 0; i < 10; i++)
358 test_TOD(shared);
359 for (i = 0; i < 10; i++)
360 test_CLOCK(shared);
362 if (me == parent)
363 print_status(shared);
366 return 0;