litl  0.1.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
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 
96 /*
97  * Initializes the timing mechanism
98  */
100  char* time_str = getenv("LITL_TIMING_METHOD");
101  if (time_str) {
102  if (strcmp(time_str, "monotonic_raw") == 0) {
103 #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_MONOTONIC_RAW))
105 #else
106  goto not_available;
107 #endif
108  } else if (strcmp(time_str, "monotonic") == 0) {
109 #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_MONOTONIC))
111 #else
112  goto not_available;
113 #endif
114  } else if (strcmp(time_str, "realtime") == 0) {
115 #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_REALTIME))
117 #else
118  goto not_available;
119 #endif
120  } else if (strcmp(time_str, "process_cputime") == 0) {
121 #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_PROCESS_CPUTIME_ID))
123 #else
124  goto not_available;
125 #endif
126  } else if (strcmp(time_str, "thread_cputime") == 0) {
127 #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_THREAD_CPUTIME_ID))
129 #else
130  goto not_available;
131 #endif
132  } else if (strcmp(time_str, "ticks") == 0) {
133 #if defined(__x86_64__) || defined(__i386)
135 #else
136  goto not_available;
137 #endif
138  } else if (strcmp(time_str, "best") == 0) {
139  __litl_time_benchmark();
140  } else {
141  fprintf(stderr, "Unknown timining method: '%s'\n", time_str);
142  abort();
143  }
144  }
145  return;
146  not_available: __attribute__ ((__unused__)) fprintf(stderr,
147  "Timing function '%s' not available on this system\n", time_str);
148  abort();
149 }
150 
151 /*
152  * Returns -1 if none of timings is available. Otherwise, it returns 0
153  */
155  if (!callback)
156  return -1;
157 
158  litl_get_time = callback;
159  return 0;
160 }
161 
162 static inline litl_time_t __litl_get_time_generic(clockid_t clk_id) {
163  litl_time_t time;
164  struct timespec tp;
165  clock_gettime(clk_id, &tp);
166  time = 1000000000 * tp.tv_sec + tp.tv_nsec;
167  return time;
168 }
169 
170 /*
171  * Uses clock_gettime(CLOCK_MONOTONIC_RAW)
172  */
174 #if(defined(CLOCK_GETTIME_AVAIL) && defined( CLOCK_MONOTONIC_RAW))
175  return __litl_get_time_generic(CLOCK_MONOTONIC_RAW);
176 #else
178  ;
179  return -1;
180 #endif
181 }
182 
183 /*
184  * Uses clock_gettime(CLOCK_MONOTONIC)
185  */
187 #ifdef CLOCK_GETTIME_AVAIL
188  return __litl_get_time_generic(CLOCK_MONOTONIC);
189 #else
191  ;
192  return -1;
193 #endif
194 }
195 
196 /*
197  * Uses clock_gettime(CLOCK_REALTIME)
198  */
200 #if (defined(CLOCK_GETTIME_AVAIL) && defined (CLOCK_REALTIME))
201  return __litl_get_time_generic(CLOCK_REALTIME);
202 #else
204  ;
205  return -1;
206 #endif
207 }
208 
209 /*
210  * Uses clock_gettime(CLOCK_PROCESS_CPUTIME_ID)
211  */
213 #if (defined(CLOCK_GETTIME_AVAIL) && defined (CLOCK_PROCESS_CPUTIME_ID))
214  return __litl_get_time_generic(CLOCK_PROCESS_CPUTIME_ID);
215 #else
217  ;
218  return -1;
219 #endif
220 }
221 
222 /*
223  * Uses clock_gettime(CLOCK_THREAD_CPUTIME_ID)
224  */
226 #if (defined(CLOCK_GETTIME_AVAIL) && defined(CLOCK_THREAD_CPUTIME_ID))
227  return __litl_get_time_generic(CLOCK_THREAD_CPUTIME_ID);
228 #else
230  ;
231  return -1;
232 #endif
233 }
234 
235 /*
236  * Uses CPU specific register (for instance, rdtsc for X86* processors)
237  */
239 #ifdef __x86_64__
240  // This is a copy of rdtscll function from asm/msr.h
241 #define ticks(val) do { \
242  uint32_t __a,__d; \
243  asm volatile("rdtsc" : "=a" (__a), "=d" (__d)); \
244  (val) = ((litl_time_t)__a) | (((litl_time_t)__d)<<32); \
245  } while(0)
246 
247 #elif defined(__i386)
248 
249 #define ticks(val) \
250  __asm__ volatile("rdtsc" : "=A" (val))
251 
252 #else
254 #define ticks(val) (val) = -1
255 #endif
256 
257  static int ticks_initialized = 0;
258  static litl_time_t __ticks_per_sec = -1;
259  if (!ticks_initialized) {
260  litl_time_t init_start, init_end;
261  ticks(init_start);
262  usleep(1000000);
263  ticks(init_end);
264 
265  __ticks_per_sec = init_end - init_start;
266  ticks_initialized = 1;
267  }
268 
269  litl_time_t time;
270  ticks(time);
271 
272  return time * 1e9 / __ticks_per_sec;
273 }
litl_time_t litl_get_time_process_cputime()
Uses clock_gettime(CLOCK_PROCESS_CPUTIME)
Definition: litl_timer.c:212
litl_time_t litl_get_time_realtime()
Uses clock_gettime(CLOCK_REALTIME)
Definition: litl_timer.c:199
litl_time_t litl_get_time_thread_cputime()
Uses clock_gettime(CLOCK_THREAD_CPUTIME)
Definition: litl_timer.c:225
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_time_t litl_get_time_monotonic_raw()
Uses clock_gettime(CLOCK_MONOTONIC_RAW)
Definition: litl_timer.c:173
#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:238
litl_time_t litl_get_time_monotonic()
Uses clock_gettime(CLOCK_MONOTONIC)
Definition: litl_timer.c:186
#define TIMER_DEFAULT
Definition: litl_timer.c:28
void litl_time_initialize()
Initializes the timing mechanism.
Definition: litl_timer.c:99
int litl_set_timing_method(litl_timing_method_t callback)
Selects the timing function to use.
Definition: litl_timer.c:154
uint64_t litl_time_t
A data type for storing time stamps.
Definition: litl_types.h:112
litl_timer Provides a set of functions for measuring time