litl 0.1.9
Loading...
Searching...
No Matches
litl_timer.c
Go to the documentation of this file.
1/* -*- c-file-style: "GNU" -*- */
2/*
3 * Copyright © Télécom SudParis.
4 * See COPYING in top-level directory.
5 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <unistd.h>
11#include <time.h>
12
13#include "litl_timer.h"
14
16
17static void __litl_time_ticks_initialize();
18
19#define ERROR_TIMER_NOT_AVAILABLE() do { \
20 fprintf(stderr, "Trying to use timer function %s, but it is not available on this platform\n",__FUNCTION__); \
21 abort(); \
22 } while(0)
23
24// Choose the default timing method
25#if CLOCK_GETTIME_AVAIL
26#ifdef CLOCK_MONOTONIC_RAW
27#define TIMER_DEFAULT litl_get_time_monotonic_raw
28#else
29#define TIMER_DEFAULT litl_get_time_monotonic
30#endif // CLOCK_MONOTONIC_RAW
31#else // CLOCK_GETTIME_AVAIL
32#define TIMER_DEFAULT litl_get_time_ticks
33#endif // CLOCK_GETTIME_AVAIL
34/*
35 * Selected timing method
36 */
38
39/*
40 * Benchmarks function f and returns the number of calls to f that can be done
41 * in 100 microseconds
42 */
43static unsigned __litl_time_benchmark_generic(litl_timing_method_t f) {
44 unsigned i = 0;
45 unsigned threshold = 100000; // how many calls to f() in 100 microseconds ?
46 litl_time_t t1, t2;
47 t1 = f();
48 do {
49 t2 = f();
50 i++;
51 } while (t2 - t1 < threshold);
52
53 return i;
54}
55
56/*
57 * Selects the most efficient timing method
58 */
59static void __litl_time_benchmark() {
60 unsigned best_score = 0;
61 unsigned cur_score;
62
63#define RUN_BENCHMARK(_func_) do { \
64 cur_score = __litl_time_benchmark_generic(_func_); \
65 if(cur_score > best_score) { \
66 best_score = cur_score; \
67 litl_set_timing_method(_func_); \
68 } \
69 }while(0)
70
71#if CLOCK_GETTIME_AVAIL
72
73#ifdef CLOCK_MONOTONIC_RAW
75#endif
76
77#ifdef CLOCK_MONOTONIC
79#endif
80
81#ifdef CLOCK_REALTIME
83#endif
84
85#ifdef CLOCK_PROCESS_CPUTIME_ID
87#endif
88
89#ifdef CLOCK_THREAD_CPUTIME_ID
91#endif
92
93#endif /* CLOCK_GETTIME_AVAIL */
94
95#if defined(__x86_64__) || defined(__i386)
96 __litl_time_ticks_initialize();
98#endif
99
100 printf("[LiTL] selected timing method:");
101#if CLOCK_GETTIME_AVAIL
102#ifdef CLOCK_MONOTONIC_RAW
104 printf("monotonic_raw\n");
105#endif
106
107#ifdef CLOCK_MONOTONIC
109 printf("monotonic\n");
110#endif
111
112#ifdef CLOCK_REALTIME
114 printf("realtime\n");
115#endif
116
117#ifdef CLOCK_PROCESS_CPUTIME_ID
119 printf("process_cputime\n");
120#endif
121
122#ifdef CLOCK_THREAD_CPUTIME_ID
124 printf("thread_cputime\n");
125#endif
126
127#endif /* CLOCK_GETTIME_AVAIL */
128
129#if defined(__x86_64__) || defined(__i386)
131 printf("ticks\n");
132#endif
133}
134
135/*
136 * Initializes the timing mechanism
137 */
139 char* time_str = getenv("LITL_TIMING_METHOD");
140 if (time_str) {
141 if (strcmp(time_str, "monotonic_raw") == 0) {
142#if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_MONOTONIC_RAW))
144#else
145 goto not_available;
146#endif
147 } else if (strcmp(time_str, "monotonic") == 0) {
148#if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_MONOTONIC))
150#else
151 goto not_available;
152#endif
153 } else if (strcmp(time_str, "realtime") == 0) {
154#if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_REALTIME))
156#else
157 goto not_available;
158#endif
159 } else if (strcmp(time_str, "process_cputime") == 0) {
160#if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_PROCESS_CPUTIME_ID))
162#else
163 goto not_available;
164#endif
165 } else if (strcmp(time_str, "thread_cputime") == 0) {
166#if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_THREAD_CPUTIME_ID))
168#else
169 goto not_available;
170#endif
171 } else if (strcmp(time_str, "ticks") == 0) {
172#if defined(__x86_64__) || defined(__i386)
174 /* dry run to make sure that the initialization process is done */
176#else
177 goto not_available;
178#endif
179 } else if (strcmp(time_str, "none") == 0) {
181 } else if (strcmp(time_str, "best") == 0) {
182 __litl_time_benchmark();
183 } else {
184 fprintf(stderr, "Unknown timining method: '%s'\n", time_str);
185 abort();
186 }
187 }
188 return;
189 not_available: __attribute__ ((__unused__)) fprintf(stderr,
190 "Timing function '%s' not available on this system\n", time_str);
191 abort();
192}
193
194/*
195 * Returns -1 if none of timings is available. Otherwise, it returns 0
196 */
198 if (!callback)
199 return -1;
200
201 litl_get_time = callback;
202
203 if(callback == litl_get_time_ticks) {
204 __litl_time_ticks_initialize();
205 }
206
207 return 0;
208}
209
210#if CLOCK_GETTIME_AVAIL
211static inline litl_time_t __litl_get_time_generic(clockid_t clk_id) {
212 litl_time_t time;
213 struct timespec tp;
214 clock_gettime(clk_id, &tp);
215 time = 1000000000 * tp.tv_sec + tp.tv_nsec;
216 return time;
217}
218#endif
219
220/*
221 * Uses clock_gettime(CLOCK_MONOTONIC_RAW)
222 */
224#if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_MONOTONIC_RAW))
225 return __litl_get_time_generic(CLOCK_MONOTONIC_RAW);
226#else
228 ;
229 return -1;
230#endif
231}
232
233/*
234 * Uses clock_gettime(CLOCK_MONOTONIC)
235 */
237#if CLOCK_GETTIME_AVAIL
238 return __litl_get_time_generic(CLOCK_MONOTONIC);
239#else
241 ;
242 return -1;
243#endif
244}
245
246/*
247 * Uses clock_gettime(CLOCK_REALTIME)
248 */
250#if (defined(CLOCK_GETTIME_AVAIL) && defined (CLOCK_REALTIME))
251 return __litl_get_time_generic(CLOCK_REALTIME);
252#else
254 ;
255 return -1;
256#endif
257}
258
259/*
260 * Uses clock_gettime(CLOCK_PROCESS_CPUTIME_ID)
261 */
263#if (defined(CLOCK_GETTIME_AVAIL) && defined (CLOCK_PROCESS_CPUTIME_ID))
264 return __litl_get_time_generic(CLOCK_PROCESS_CPUTIME_ID);
265#else
267 ;
268 return -1;
269#endif
270}
271
272/*
273 * Uses clock_gettime(CLOCK_THREAD_CPUTIME_ID)
274 */
276#if (defined(CLOCK_GETTIME_AVAIL) && defined(CLOCK_THREAD_CPUTIME_ID))
277 return __litl_get_time_generic(CLOCK_THREAD_CPUTIME_ID);
278#else
280 ;
281 return -1;
282#endif
283}
284
286 return 0;
287}
288
289static int ticks_initialized = 0;
290static litl_time_t __ticks_per_sec = 0;
291
292/*
293 * Uses CPU specific register (for instance, rdtsc for X86* processors)
294 */
296#ifdef __x86_64__
297 // This is a copy of rdtscll function from asm/msr.h
298#define ticks(val) do { \
299 uint32_t __a,__d; \
300 asm volatile("rdtsc" : "=a" (__a), "=d" (__d)); \
301 (val) = ((litl_time_t)__a) | (((litl_time_t)__d)<<32); \
302 } while(0)
303
304#elif defined(__i386)
305
306#define ticks(val) \
307 __asm__ volatile("rdtsc" : "=A" (val))
308
309#else
311#define ticks(val) (val) = -1
312#endif
313
314
315 litl_time_t time;
316 ticks(time);
317
318 return time * 1e9 / __ticks_per_sec;
319}
320
321/* initialize the ticks timer */
322static void __litl_time_ticks_initialize() {
323 if (!ticks_initialized) {
324 /* since ticks return a timestamp measured in clock cycles,
325 * we need to be able to convert it to ns
326 */
327 litl_time_t init_start, init_end;
328 /* how many cycles in 1 second ? */
329 ticks(init_start);
330 usleep(1000000);
331 ticks(init_end);
332
333 __ticks_per_sec = init_end - init_start;
334 ticks_initialized = 1;
335 }
336}
void litl_time_initialize()
Initializes the timing mechanism.
Definition litl_timer.c:138
litl_time_t(* litl_timing_method_t)()
A callback function that returns the current time in ns. It can be either a pointer to one of the tim...
Definition litl_timer.h:42
int litl_set_timing_method(litl_timing_method_t callback)
Selects the timing function to use.
Definition litl_timer.c:197
litl_time_t litl_get_time_none()
Ultra-fast measurement function.
Definition litl_timer.c:285
litl_timing_method_t litl_get_time
Calls the selected timing method and get the current time in ns.
Definition litl_timer.c:37
litl_time_t litl_get_time_ticks()
Uses CPU-specific register (for instance, rdtsc for X86* processors)
Definition litl_timer.c:295
litl_time_t litl_get_time_monotonic()
Uses clock_gettime(CLOCK_MONOTONIC)
Definition litl_timer.c:236
litl_time_t litl_get_time_monotonic_raw()
Uses clock_gettime(CLOCK_MONOTONIC_RAW)
Definition litl_timer.c:223
litl_time_t litl_get_time_realtime()
Uses clock_gettime(CLOCK_REALTIME)
Definition litl_timer.c:249
litl_time_t litl_get_time_thread_cputime()
Uses clock_gettime(CLOCK_THREAD_CPUTIME)
Definition litl_timer.c:275
litl_time_t litl_get_time_process_cputime()
Uses clock_gettime(CLOCK_PROCESS_CPUTIME)
Definition litl_timer.c:262
uint64_t litl_time_t
A data type for storing time stamps.
Definition litl_types.h:114
#define RUN_BENCHMARK(_func_)
#define TIMER_DEFAULT
Definition litl_timer.c:32
#define ERROR_TIMER_NOT_AVAILABLE()
Definition litl_timer.c:19
#define ticks(val)
litl_timer Provides a set of functions for measuring time