litl  0.1.9
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 
17 static 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  */
43 static 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  */
59 static 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
211 static 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 
289 static int ticks_initialized = 0;
290 static 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 */
322 static 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:29
#define ERROR_TIMER_NOT_AVAILABLE()
Definition: litl_timer.c:19
#define ticks(val)
litl_timer Provides a set of functions for measuring time