2 * This file is part of libFirm.
3 * Copyright (C) 2012 University of Karlsruhe.
8 * @brief platform neutral timing utilities
20 #define WIN32_LEAN_AND_MEAN
24 /* Win32 timer value. */
26 unsigned lo_prec; /**< 32bit low precision time in milli seconds */
27 LARGE_INTEGER hi_prec; /**< 64bit high precision time in micro seconds */
33 #define HAVE_GETTIMEOFDAY
36 * Just, if we have gettimeofday()
37 * Someday, we will have a check here.
44 /* Linux timer value. */
45 typedef struct timeval ir_timer_val_t;
51 static inline void _time_reset(ir_timer_val_t *val);
57 ir_timer_val_t elapsed; /**< the elapsed time so far */
58 ir_timer_val_t start; /**< the start value of the timer */
59 ir_timer_t *parent; /**< parent of a timer */
60 ir_timer_t *displaced; /**< former timer in case of timer_push */
61 unsigned running : 1; /**< set if this timer is running */
64 /** The top of the timer stack */
65 static ir_timer_t *timer_stack;
67 ir_timer_t *ir_timer_new(void)
69 ir_timer_t *timer = XMALLOCZ(ir_timer_t);
70 _time_reset(&timer->elapsed);
71 _time_reset(&timer->start);
75 void ir_timer_free(ir_timer_t *timer)
80 #ifdef HAVE_GETTIMEOFDAY
82 static inline void _time_get(ir_timer_val_t *val)
84 gettimeofday(val, NULL);
87 static inline void _time_reset(ir_timer_val_t *val)
92 static inline unsigned long _time_to_msec(const ir_timer_val_t *elapsed)
94 return (unsigned long) elapsed->tv_sec * 1000UL
95 + (unsigned long) elapsed->tv_usec / 1000UL;
98 static inline unsigned long _time_to_usec(const ir_timer_val_t *elapsed)
100 return (unsigned long) elapsed->tv_sec * 1000000UL
101 + (unsigned long) elapsed->tv_usec;
104 static inline double _time_to_sec(const ir_timer_val_t *elapsed)
106 return (double)elapsed->tv_sec + (double)elapsed->tv_usec / 1000000.0;
109 static inline ir_timer_val_t *_time_add(ir_timer_val_t *res,
110 const ir_timer_val_t *lhs, const ir_timer_val_t *rhs)
112 timeradd(lhs, rhs, res);
116 static inline ir_timer_val_t *_time_sub(ir_timer_val_t *res,
117 const ir_timer_val_t *lhs, const ir_timer_val_t *rhs)
119 timersub(lhs, rhs, res);
123 #elif defined(_WIN32)
125 static inline void _time_get(ir_timer_val_t *val)
127 if (!QueryPerformanceCounter(&val->hi_prec))
128 val->lo_prec = timeGetTime();
131 static inline void _time_reset(ir_timer_val_t *val)
133 memset(val, 0, sizeof(val[0]));
136 static inline unsigned long _time_to_msec(const ir_timer_val_t *elapsed)
140 if (!QueryPerformanceFrequency(&freq))
141 return (unsigned long) elapsed->lo_prec;
143 return (unsigned long) ((elapsed->hi_prec.QuadPart * 1000) / freq.QuadPart);
146 static inline unsigned long _time_to_usec(const ir_timer_val_t *elapsed)
150 if (!QueryPerformanceFrequency(&freq))
151 return (unsigned long) elapsed->lo_prec * 1000;
153 return (unsigned long) ((elapsed->hi_prec.QuadPart * 1000000) / freq.QuadPart);
156 static inline double _time_to_sec(const ir_timer_val_t *elapsed)
160 if (!QueryPerformanceFrequency(&freq))
161 return (double) elapsed->lo_prec / 1000.;
163 return (double)elapsed->hi_prec.QuadPart / (double)freq.QuadPart;
166 static inline ir_timer_val_t *_time_add(ir_timer_val_t *res, const ir_timer_val_t *lhs, const ir_timer_val_t *rhs)
169 if (QueryPerformanceFrequency(&dummy))
170 res->hi_prec.QuadPart = lhs->hi_prec.QuadPart + rhs->hi_prec.QuadPart;
172 res->lo_prec = lhs->lo_prec + rhs->lo_prec;
177 static inline ir_timer_val_t *_time_sub(ir_timer_val_t *res, const ir_timer_val_t *lhs, const ir_timer_val_t *rhs)
180 if (QueryPerformanceFrequency(&dummy))
181 res->hi_prec.QuadPart = lhs->hi_prec.QuadPart - rhs->hi_prec.QuadPart;
183 res->lo_prec = lhs->lo_prec - rhs->lo_prec;
190 #if defined(_XOPEN_REALTIME) && _XOPEN_REALTIME != -1
192 #include <sys/types.h>
195 static struct sched_param std_sched_param;
196 static int std_sched_param_init = 0;
198 int ir_timer_enter_high_priority(void)
200 pid_t pid = getpid();
202 struct sched_param p;
205 if (!std_sched_param_init) {
206 res = sched_getparam(pid, &std_sched_param);
209 std_sched_param_init = 1;
212 algo = sched_getscheduler(pid);
213 max = sched_get_priority_max(algo);
216 p.sched_priority = max;
217 res = sched_setparam(pid, &p);
222 int ir_timer_leave_high_priority(void)
225 pid_t pid = getpid();
227 if (std_sched_param_init)
228 res = sched_setparam(pid, &std_sched_param);
233 #elif defined(_WIN32)
235 static int initial_priority = THREAD_PRIORITY_NORMAL;
237 int ir_timer_leave_high_priority(void)
240 if (!SetThreadPriority(GetCurrentThread(), initial_priority)) {
241 fprintf(stderr, "Failed to leave high priority (%d)\n", GetLastError());
242 res = GetLastError();
248 int ir_timer_enter_high_priority(void)
251 initial_priority = GetThreadPriority(GetCurrentThread());
252 if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) {
253 fprintf(stderr, "Failed to enter high priority (%d)\n", GetLastError());
254 res = GetLastError();
263 int ir_timer_enter_high_priority(void)
265 fprintf(stderr, "POSIX scheduling API not present\n");
269 int ir_timer_leave_high_priority(void)
280 size_t ir_get_heap_used_bytes(void)
282 struct mallinfo mi = mallinfo();
286 #elif defined(_WIN32) /* __linux__ */
290 size_t ir_get_heap_used_bytes(void)
295 hinfo._pentry = NULL;
296 while ((heapstatus = _heapwalk(&hinfo)) == _HEAPOK)
297 res += hinfo._useflag == _USEDENTRY ? hinfo._size : 0;
303 size_t ir_get_heap_used_bytes(void)
305 fprintf(stderr, "function not implemented\n");
312 void ir_timer_reset(ir_timer_t *timer)
314 _time_reset(&timer->elapsed);
315 _time_reset(&timer->start);
320 void ir_timer_start(ir_timer_t *timer)
323 panic("timer started twice");
325 _time_reset(&timer->start);
326 _time_get(&timer->start);
329 if (timer->parent == NULL) {
330 timer->parent = timer_stack;
331 } else if (timer->parent != timer_stack) {
332 panic("timer used at different stack positions");
337 void ir_timer_reset_and_start(ir_timer_t *timer)
339 _time_reset(&timer->elapsed);
340 ir_timer_start(timer);
343 void ir_timer_stop(ir_timer_t *timer)
346 panic("attempting to stop stopped timer");
347 if (timer != timer_stack)
348 panic("timer stack error");
349 timer_stack = timer->parent;
356 _time_add(&timer->elapsed, &timer->elapsed, _time_sub(&tgt, &val, &timer->start));
359 void ir_timer_init_parent(ir_timer_t *timer)
363 if (timer->parent != NULL && timer->parent != timer_stack)
364 panic("timer parent mismatch");
365 timer->parent = timer_stack;
368 void ir_timer_push(ir_timer_t *timer)
371 panic("timer started twice");
373 ir_timer_t *parent = timer->parent;
374 if (timer->parent == NULL)
375 panic("pushing timer with unknown parent");
377 timer->displaced = timer_stack;
378 for (ir_timer_t *t = timer_stack; t != parent; t = t->parent) {
380 panic("parent timer not on stack");
383 timer_stack = parent;
385 ir_timer_start(timer);
388 static void start_stack(ir_timer_t *timer, ir_timer_t *stop)
392 start_stack(timer->parent, stop);
393 ir_timer_start(timer);
396 void ir_timer_pop(ir_timer_t *timer)
399 panic("attempting to stop stopped timer");
400 ir_timer_t *displaced = timer->displaced;
401 if (displaced == NULL)
402 panic("timer start/stop/push/pop mismatch");
404 ir_timer_t *parent = timer->parent;
405 timer->displaced = NULL;
407 ir_timer_stop(timer);
408 start_stack(displaced, parent);
411 unsigned long ir_timer_elapsed_msec(const ir_timer_t *timer)
414 const ir_timer_val_t *elapsed = &timer->elapsed;
416 if (timer->running) {
419 _time_add(&v, &timer->elapsed, _time_sub(&v, &v, &timer->start));
421 return _time_to_msec(elapsed);
424 unsigned long ir_timer_elapsed_usec(const ir_timer_t *timer)
427 const ir_timer_val_t *elapsed = &timer->elapsed;
429 if (timer->running) {
432 _time_add(&v, &timer->elapsed, _time_sub(&v, &v, &timer->start));
434 return _time_to_usec(elapsed);
437 double ir_timer_elapsed_sec(const ir_timer_t *timer)
440 const ir_timer_val_t *elapsed = &timer->elapsed;
442 if (timer->running) {
445 _time_add(&v, &timer->elapsed, _time_sub(&v, &v, &timer->start));
447 return _time_to_sec(elapsed);