litl  0.1.8
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 
15 #define ERROR_TIMER_NOT_AVAILABLE() do { \
16  fprintf(stderr, "Trying to use timer function %s, but it is not available on this platform\n",__FUNCTION__); \
17  abort(); \
18  } while(0)
19 
20 // Choose the default timing method
21 #ifdef CLOCK_GETTIME_AVAIL
22 #ifdef CLOCK_MONOTONIC_RAW
23 #define TIMER_DEFAULT litl_get_time_monotonic_raw
24 #else
25 #define TIMER_DEFAULT litl_get_time_monotonic
26 #endif // CLOCK_MONOTONIC_RAW
27 #else // CLOCK_GETTIME_AVAIL
28 #define TIMER_DEFAULT litl_get_time_ticks
29 #endif // CLOCK_GETTIME_AVAIL
30 /*
31  * Selected timing method
32  */
34 
35 /*
36  * Benchmarks function f and returns the number of calls to f that can be done
37  * in 100 microseconds
38  */
39 static unsigned __litl_time_benchmark_generic(litl_timing_method_t f) {
40  unsigned i = 0;
41  unsigned threshold = 100000; // how many calls to f() in 100 microseconds ?
42  litl_time_t t1, t2;
43  t1 = f();
44  do {
45  t2 = f();
46  i++;
47  } while (t2 - t1 < threshold);
48 
49  return i;
50 }
51 
52 /*
53  * Selects the most efficient timing method
54  */
55 static void __litl_time_benchmark() {
56  unsigned best_score = 0;
57  unsigned cur_score;
58 
59 #define RUN_BENCHMARK(_func_) do { \
60  cur_score = __litl_time_benchmark_generic(_func_); \
61  if(cur_score > best_score) { \
62  best_score = cur_score; \
63  litl_set_timing_method(_func_); \
64  } \
65  }while(0)
66 
67 #ifdef CLOCK_GETTIME_AVAIL
68 
69 #ifdef CLOCK_MONOTONIC_RAW
71 #endif
72 
73 #ifdef CLOCK_MONOTONIC
75 #endif
76 
77 #ifdef CLOCK_REALTIME
79 #endif
80 
81 #ifdef CLOCK_PROCESS_CPUTIME_ID
83 #endif
84 
85 #ifdef CLOCK_THREAD_CPUTIME_ID
87 #endif
88 
89 #endif /* CLOCK_GETTIME_AVAIL */
90 
91 #if defined(__x86_64__) || defined(__i386)
93 #endif
94 
95  printf("[LiTL] selected timing method:");
96 #ifdef CLOCK_GETTIME_AVAIL
97 #ifdef CLOCK_MONOTONIC_RAW
99  printf("monotonic_raw\n");
100 #endif
101 
102 #ifdef CLOCK_MONOTONIC
104  printf("monotonic\n");
105 #endif
106 
107 #ifdef CLOCK_REALTIME
109  printf("realtime\n");
110 #endif
111 
112 #ifdef CLOCK_PROCESS_CPUTIME_ID
114  printf("process_cputime\n");
115 #endif
116 
117 #ifdef CLOCK_THREAD_CPUTIME_ID
119  printf("thread_cputime\n");
120 #endif
121 
122 #endif /* CLOCK_GETTIME_AVAIL */
123 
124 #if defined(__x86_64__) || defined(__i386)
126  printf("ticks\n");
127 #endif
128 }
129 
130 /*
131  * Initializes the timing mechanism
132  */
134  char* time_str = getenv("LITL_TIMING_METHOD");
135  if (time_str) {
136  if (strcmp(time_str, "monotonic_raw") == 0) {
137 #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_MONOTONIC_RAW))
139 #else
140  goto not_available;
141 #endif
142  } else if (strcmp(time_str, "monotonic") == 0) {
143 #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_MONOTONIC))
145 #else
146  goto not_available;
147 #endif
148  } else if (strcmp(time_str, "realtime") == 0) {
149 #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_REALTIME))
151 #else
152  goto not_available;
153 #endif
154  } else if (strcmp(time_str, "process_cputime") == 0) {
155 #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_PROCESS_CPUTIME_ID))
157 #else
158  goto not_available;
159 #endif
160  } else if (strcmp(time_str, "thread_cputime") == 0) {
161 #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_THREAD_CPUTIME_ID))
163 #else
164  goto not_available;
165 #endif
166  } else if (strcmp(time_str, "ticks") == 0) {
167 #if defined(__x86_64__) || defined(__i386)
169 #else
170  goto not_available;
171 #endif
172  } else if (strcmp(time_str, "best") == 0) {
173  __litl_time_benchmark();
174  } else {
175  fprintf(stderr, "Unknown timining method: '%s'\n", time_str);
176  abort();
177  }
178  }
179  return;
180  not_available: __attribute__ ((__unused__)) fprintf(stderr,
181  "Timing function '%s' not available on this system\n", time_str);
182  abort();
183 }
184 
185 /*
186  * Returns -1 if none of timings is available. Otherwise, it returns 0
187  */
189  if (!callback)
190  return -1;
191 
192  litl_get_time = callback;
193  return 0;
194 }
195 
196 #ifdef CLOCK_GETTIME_AVAIL
197 static inline litl_time_t __litl_get_time_generic(clockid_t clk_id) {
198  litl_time_t time;
199  struct timespec tp;
200  clock_gettime(clk_id, &tp);
201  time = 1000000000 * tp.tv_sec + tp.tv_nsec;
202  return time;
203 }
204 #endif
205 
206 /*
207  * Uses clock_gettime(CLOCK_MONOTONIC_RAW)
208  */
210 #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_MONOTONIC_RAW))
211  return __litl_get_time_generic(CLOCK_MONOTONIC_RAW);
212 #else
214  ;
215  return -1;
216 #endif
217 }
218 
219 /*
220  * Uses clock_gettime(CLOCK_MONOTONIC)
221  */
223 #ifdef CLOCK_GETTIME_AVAIL
224  return __litl_get_time_generic(CLOCK_MONOTONIC);
225 #else
227  ;
228  return -1;
229 #endif
230 }
231 
232 /*
233  * Uses clock_gettime(CLOCK_REALTIME)
234  */
236 #if (defined(CLOCK_GETTIME_AVAIL) && defined (CLOCK_REALTIME))
237  return __litl_get_time_generic(CLOCK_REALTIME);
238 #else
240  ;
241  return -1;
242 #endif
243 }
244 
245 /*
246  * Uses clock_gettime(CLOCK_PROCESS_CPUTIME_ID)
247  */
249 #if (defined(CLOCK_GETTIME_AVAIL) && defined (CLOCK_PROCESS_CPUTIME_ID))
250  return __litl_get_time_generic(CLOCK_PROCESS_CPUTIME_ID);
251 #else
253  ;
254  return -1;
255 #endif
256 }
257 
258 /*
259  * Uses clock_gettime(CLOCK_THREAD_CPUTIME_ID)
260  */
262 #if (defined(CLOCK_GETTIME_AVAIL) && defined(CLOCK_THREAD_CPUTIME_ID))
263  return __litl_get_time_generic(CLOCK_THREAD_CPUTIME_ID);
264 #else
266  ;
267  return -1;
268 #endif
269 }
270 
271 /*
272  * Uses CPU specific register (for instance, rdtsc for X86* processors)
273  */
275 #ifdef __x86_64__
276  // This is a copy of rdtscll function from asm/msr.h
277 #define ticks(val) do { \
278  uint32_t __a,__d; \
279  asm volatile("rdtsc" : "=a" (__a), "=d" (__d)); \
280  (val) = ((litl_time_t)__a) | (((litl_time_t)__d)<<32); \
281  } while(0)
282 
283 #elif defined(__i386)
284 
285 #define ticks(val) \
286  __asm__ volatile("rdtsc" : "=A" (val))
287 
288 #else
290 #define ticks(val) (val) = -1
291 #endif
292 
293  static int ticks_initialized = 0;
294  static litl_time_t __ticks_per_sec = -1;
295  if (!ticks_initialized) {
296  litl_time_t init_start, init_end;
297  ticks(init_start);
298  usleep(1000000);
299  ticks(init_end);
300 
301  __ticks_per_sec = init_end - init_start;
302  ticks_initialized = 1;
303  }
304 
305  litl_time_t time;
306  ticks(time);
307 
308  return time * 1e9 / __ticks_per_sec;
309 }
litl_time_t litl_get_time_process_cputime()
Uses clock_gettime(CLOCK_PROCESS_CPUTIME)
Definition: litl_timer.c:248
litl_time_t litl_get_time_realtime()
Uses clock_gettime(CLOCK_REALTIME)
Definition: litl_timer.c:235
litl_time_t litl_get_time_thread_cputime()
Uses clock_gettime(CLOCK_THREAD_CPUTIME)
Definition: litl_timer.c:261
litl_time_t litl_get_time_monotonic_raw()
Uses clock_gettime(CLOCK_MONOTONIC_RAW)
Definition: litl_timer.c:209
#define ERROR_TIMER_NOT_AVAILABLE()
Definition: litl_timer.c:15
#define ticks(val)
#define RUN_BENCHMARK(_func_)
litl_timing_method_t litl_get_time
Calls the selected timing method and get the current time in ns.
Definition: litl_timer.c:33
litl_time_t litl_get_time_ticks()
Uses CPU-specific register (for instance, rdtsc for X86* processors)
Definition: litl_timer.c:274
litl_time_t litl_get_time_monotonic()
Uses clock_gettime(CLOCK_MONOTONIC)
Definition: litl_timer.c:222
#define TIMER_DEFAULT
Definition: litl_timer.c:28
void litl_time_initialize()
Initializes the timing mechanism.
Definition: litl_timer.c:133
int litl_set_timing_method(litl_timing_method_t callback)
Selects the timing function to use.
Definition: litl_timer.c:188
uint64_t litl_time_t
A data type for storing time stamps.
Definition: litl_types.h:112
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
litl_timer Provides a set of functions for measuring time