2 * Copyright (C) 2007 Jan Kiszka <jan.kiszka@web.de>.
4 * Xenomai is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * Xenomai is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Xenomai; if not, write to the Free Software Foundation,
16 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 #include <sys/syscall.h>
31 #include <nucleus/vdso.h>
33 #include <xeno_config.h>
35 #ifndef HAVE_RECENT_SETAFFINITY
36 #ifdef HAVE_OLD_SETAFFINITY
37 #define sched_setaffinity(pid, len, mask) sched_setaffinity(pid, mask)
38 #else /* !HAVE_OLD_SETAFFINITY */
39 #ifndef __cpu_set_t_defined
40 typedef unsigned long cpu_set_t
;
42 #define sched_setaffinity(pid, len, mask) do { } while (0)
44 #define CPU_ZERO(set) memset(set, 0, sizeof(*set))
45 #define CPU_SET(n, set) do { } while (0)
47 #endif /* !HAVE_OLD_SETAFFINITY */
48 #endif /* !HAVE_RECENT_SETAFFINITY */
51 * We can't really trust POSIX headers to check for features, since
52 * some archs may not implement all of the declared uClibc POSIX
53 * features (e.g. NIOS2).
55 #ifdef HAVE_PTHREAD_SPIN_LOCK
56 pthread_spinlock_t lock
;
57 #define init_lock(lock) pthread_spin_init(lock, 0)
58 #define acquire_lock(lock) pthread_spin_lock(lock)
59 #define release_lock(lock) pthread_spin_unlock(lock)
62 #define init_lock(lock) pthread_mutex_init(lock, NULL)
63 #define acquire_lock(lock) pthread_mutex_lock(lock)
64 #define release_lock(lock) pthread_mutex_unlock(lock)
66 unsigned long long last_common
= 0;
67 clockid_t clock_id
= CLOCK_REALTIME
;
70 unsigned long long first_tod
, first_clock
;
75 unsigned long long max_warp
;
79 static void show_hostrt_diagnostics(void)
81 if (!xnvdso_test_feature(XNVDSO_FEAT_HOST_REALTIME
)) {
82 printf("XNVDSO_FEAT_HOST_REALTIME not available\n");
86 if (nkvdso
->hostrt_data
.live
)
87 printf("hostrt data area is live\n");
89 printf("hostrt data area is not live\n");
93 printf("Sequence counter : %u\n",
94 nkvdso
->hostrt_data
.seqcount
.sequence
);
95 printf("wall_time_sec : %ld\n", nkvdso
->hostrt_data
.wall_time_sec
);
96 printf("wall_time_nsec : %u\n", nkvdso
->hostrt_data
.wall_time_nsec
);
97 printf("wall_to_monotonic\n");
98 printf(" tv_sec : %jd\n",
99 (intmax_t)nkvdso
->hostrt_data
.wall_to_monotonic
.tv_sec
);
100 printf(" tv_nsec : %ld\n",
101 nkvdso
->hostrt_data
.wall_to_monotonic
.tv_nsec
);
102 printf("cycle_last : %Lu\n", nkvdso
->hostrt_data
.cycle_last
);
103 printf("mask : 0x%Lx\n", nkvdso
->hostrt_data
.mask
);
104 printf("mult : %u\n", nkvdso
->hostrt_data
.mult
);
105 printf("shift : %u\n\n", nkvdso
->hostrt_data
.shift
);
108 static inline unsigned long long read_clock(clockid_t clock_id
)
113 res
= clock_gettime(clock_id
, &ts
);
115 fprintf(stderr
, "clock_gettime failed for clock id %d\n",
117 if (clock_id
== CLOCK_HOST_REALTIME
)
118 show_hostrt_diagnostics();
122 return ts
.tv_nsec
+ ts
.tv_sec
* 1000000000ULL;
125 static inline unsigned long long read_reference_clock(void)
130 * Make sure we do not pick the vsyscall variant. It won't
131 * switch us into secondary mode and can easily deadlock.
133 syscall(SYS_gettimeofday
, &tv
, NULL
);
134 return tv
.tv_usec
* 1000ULL + tv
.tv_sec
* 1000000000ULL;
137 void check_reference(struct per_cpu_data
*per_cpu_data
)
139 unsigned long long clock_val
[10], tod_val
[10];
140 long long delta
, min_delta
;
143 for (i
= 0; i
< 10; i
++) {
144 tod_val
[i
] = read_reference_clock();
145 clock_val
[i
] = read_clock(clock_id
);
148 min_delta
= tod_val
[1] - tod_val
[0];
151 for (i
= 2; i
< 10; i
++) {
152 delta
= tod_val
[i
] - tod_val
[i
-1];
153 if (delta
< min_delta
) {
159 if (per_cpu_data
->first_round
) {
160 per_cpu_data
->first_round
= 0;
162 per_cpu_data
->first_tod
= tod_val
[idx
];
163 per_cpu_data
->first_clock
= clock_val
[idx
];
165 per_cpu_data
->drift
=
166 (clock_val
[idx
] - per_cpu_data
->first_clock
) /
167 (double)(tod_val
[idx
] - per_cpu_data
->first_tod
) - 1;
169 per_cpu_data
->offset
= clock_val
[idx
] - tod_val
[idx
];
172 void check_time_warps(struct per_cpu_data
*per_cpu_data
)
175 unsigned long long last
, now
;
178 for (i
= 0; i
< 100; i
++) {
180 now
= read_clock(clock_id
);
188 per_cpu_data
->warps
++;
189 if (-incr
> per_cpu_data
->max_warp
)
190 per_cpu_data
->max_warp
= -incr
;
196 void *cpu_thread(void *arg
)
198 int cpuid
= (long)arg
;
199 struct sched_param param
= { .sched_priority
= 1 };
200 struct timespec delay
= { 0, 0 };
203 srandom(read_reference_clock());
206 CPU_SET(cpuid
, &cpu_set
);
207 sched_setaffinity(0, sizeof(cpu_set
), &cpu_set
);
208 pthread_setschedparam(pthread_self(), SCHED_FIFO
, ¶m
);
211 check_reference(&per_cpu_data
[cpuid
]);
213 check_time_warps(&per_cpu_data
[cpuid
]);
215 delay
.tv_nsec
= 1000000 + random() * (100000.0 / RAND_MAX
);
216 nanosleep(&delay
, NULL
);
220 void sighand(int signal
)
225 int main(int argc
, char *argv
[])
227 int cpus
= sysconf(_SC_NPROCESSORS_ONLN
);
232 while ((c
= getopt(argc
, argv
, "C:T:D")) != EOF
)
235 clock_id
= atoi(optarg
);
247 fprintf(stderr
, "usage: clocktest [options]\n"
248 " [-C <clock_id>] # tested clock, default=%d (CLOCK_REALTIME)\n"
249 " [-T <test_duration_seconds>] # default=0, so ^C to end\n"
250 " [-D] # print extra diagnostics for CLOCK_HOST_REALTIME\n",
255 mlockall(MCL_CURRENT
| MCL_FUTURE
);
257 signal(SIGALRM
, sighand
);
261 if (d
&& clock_id
== CLOCK_HOST_REALTIME
)
262 show_hostrt_diagnostics();
264 per_cpu_data
= malloc(sizeof(*per_cpu_data
) * cpus
);
266 fprintf(stderr
, "%s\n", strerror(ENOMEM
));
269 memset(per_cpu_data
, 0, sizeof(*per_cpu_data
) * cpus
);
271 for (i
= 0; i
< cpus
; i
++) {
272 per_cpu_data
[i
].first_round
= 1;
273 pthread_create(&per_cpu_data
[i
].thread
, NULL
, cpu_thread
,
277 printf("== Tested clock: %d (", clock_id
);
280 printf("CLOCK_REALTIME");
283 case CLOCK_MONOTONIC
:
284 printf("CLOCK_MONOTONIC");
287 case CLOCK_HOST_REALTIME
:
288 printf("CLOCK_HOST_REALTIME");
295 printf(")\nCPU ToD offset [us] ToD drift [us/s] warps max delta [us]\n"
296 "--- -------------------- ---------------- ---------- --------------\n");
299 for (i
= 0; i
< cpus
; i
++)
300 printf("%3d %20.1f %16.3f %10lu %14.1f\n",
302 per_cpu_data
[i
].offset
/1000.0,
303 per_cpu_data
[i
].drift
* 1000000.0,
304 per_cpu_data
[i
].warps
,
305 per_cpu_data
[i
].max_warp
/1000.0);
307 printf("\033[%dA", cpus
);