convert lower_mode_b to assure/confirm_irg_properties style
[libfirm] / ir / common / timing.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   platform neutral timing utilities
23  */
24 #include "config.h"
25
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "timing.h"
30 #include "xmalloc.h"
31 #include "error.h"
32
33 #ifdef _WIN32
34 #define WIN32_LEAN_AND_MEAN
35 #include <windows.h>
36 #include <mmsystem.h>
37
38 /* Win32 timer value. */
39 typedef union {
40         unsigned lo_prec;       /**< 32bit low precision time in milli seconds */
41         LARGE_INTEGER hi_prec;  /**< 64bit high precision time in micro seconds */
42 } ir_timer_val_t;
43
44 #else
45
46 #include <unistd.h>
47 #define HAVE_GETTIMEOFDAY
48
49 /*
50  * Just, if we have gettimeofday()
51  * Someday, we will have a check here.
52  */
53 #ifndef __USE_BSD
54 #define __USE_BSD
55 #endif
56 #include <sys/time.h>
57
58 /* Linux timer value. */
59 typedef struct timeval ir_timer_val_t;
60
61 #endif /* _Win32 */
62
63 #include <stddef.h>
64
65 static inline void _time_reset(ir_timer_val_t *val);
66
67 /**
68  * A timer.
69  */
70 struct ir_timer_t {
71         ir_timer_val_t elapsed;     /**< the elapsed time so far */
72         ir_timer_val_t start;       /**< the start value of the timer */
73         ir_timer_t     *parent;     /**< parent of a timer */
74         ir_timer_t     *displaced;  /**< former timer in case of timer_push */
75         unsigned       running : 1; /**< set if this timer is running */
76 };
77
78 /** The top of the timer stack */
79 static ir_timer_t *timer_stack;
80
81 ir_timer_t *ir_timer_new(void)
82 {
83         ir_timer_t *timer = XMALLOCZ(ir_timer_t);
84         _time_reset(&timer->elapsed);
85         _time_reset(&timer->start);
86         return timer;
87 }
88
89 void ir_timer_free(ir_timer_t *timer)
90 {
91         xfree(timer);
92 }
93
94 #ifdef HAVE_GETTIMEOFDAY
95
96 static inline void _time_get(ir_timer_val_t *val)
97 {
98         gettimeofday(val, NULL);
99 }
100
101 static inline void _time_reset(ir_timer_val_t *val)
102 {
103         timerclear(val);
104 }
105
106 static inline unsigned long _time_to_msec(const ir_timer_val_t *elapsed)
107 {
108         return (unsigned long) elapsed->tv_sec * 1000UL
109                 + (unsigned long) elapsed->tv_usec / 1000UL;
110 }
111
112 static inline unsigned long _time_to_usec(const ir_timer_val_t *elapsed)
113 {
114         return (unsigned long) elapsed->tv_sec * 1000000UL
115                 + (unsigned long) elapsed->tv_usec;
116 }
117
118 static inline double _time_to_sec(const ir_timer_val_t *elapsed)
119 {
120         return (double)elapsed->tv_sec + (double)elapsed->tv_usec / 1000000.0;
121 }
122
123 static inline ir_timer_val_t *_time_add(ir_timer_val_t *res,
124                 const ir_timer_val_t *lhs, const ir_timer_val_t *rhs)
125 {
126         timeradd(lhs, rhs, res);
127                 return res;
128 }
129
130 static inline ir_timer_val_t *_time_sub(ir_timer_val_t *res,
131                 const ir_timer_val_t *lhs, const ir_timer_val_t *rhs)
132 {
133         timersub(lhs, rhs, res);
134         return res;
135 }
136
137 #elif defined(_WIN32)
138
139 static inline void _time_get(ir_timer_val_t *val)
140 {
141         if (!QueryPerformanceCounter(&val->hi_prec))
142                 val->lo_prec = timeGetTime();
143 }
144
145 static inline void _time_reset(ir_timer_val_t *val)
146 {
147         memset(val, 0, sizeof(val[0]));
148 }
149
150 static inline unsigned long _time_to_msec(const ir_timer_val_t *elapsed)
151 {
152         LARGE_INTEGER freq;
153
154         if (!QueryPerformanceFrequency(&freq))
155                 return (unsigned long) elapsed->lo_prec;
156
157         return (unsigned long) ((elapsed->hi_prec.QuadPart * 1000) / freq.QuadPart);
158 }
159
160 static inline unsigned long _time_to_usec(const ir_timer_val_t *elapsed)
161 {
162         LARGE_INTEGER freq;
163
164         if (!QueryPerformanceFrequency(&freq))
165                 return (unsigned long) elapsed->lo_prec * 1000;
166
167         return (unsigned long) ((elapsed->hi_prec.QuadPart * 1000000) / freq.QuadPart);
168 }
169
170 static inline double _time_to_sec(const ir_timer_val_t *elapsed)
171 {
172         LARGE_INTEGER freq;
173
174         if (!QueryPerformanceFrequency(&freq))
175                 return (double) elapsed->lo_prec / 1000.;
176
177         return (double)elapsed->hi_prec.QuadPart / (double)freq.QuadPart;
178 }
179
180 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)
181 {
182         LARGE_INTEGER dummy;
183         if (QueryPerformanceFrequency(&dummy))
184                 res->hi_prec.QuadPart = lhs->hi_prec.QuadPart + rhs->hi_prec.QuadPart;
185         else
186                 res->lo_prec = lhs->lo_prec + rhs->lo_prec;
187
188         return res;
189 }
190
191 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)
192 {
193         LARGE_INTEGER dummy;
194         if (QueryPerformanceFrequency(&dummy))
195                 res->hi_prec.QuadPart = lhs->hi_prec.QuadPart - rhs->hi_prec.QuadPart;
196         else
197                 res->lo_prec = lhs->lo_prec - rhs->lo_prec;
198
199         return res;
200 }
201
202 #endif /* _WIN32 */
203
204 #if defined(_XOPEN_REALTIME) && _XOPEN_REALTIME != -1
205
206 #include <sys/types.h>
207 #include <sched.h>
208
209 static struct sched_param std_sched_param;
210 static int std_sched_param_init = 0;
211
212 int ir_timer_enter_high_priority(void)
213 {
214         pid_t pid = getpid();
215
216         struct sched_param p;
217         int res, max, algo;
218
219         if (!std_sched_param_init) {
220                 res = sched_getparam(pid, &std_sched_param);
221                 if (res != 0)
222                         return res;
223                 std_sched_param_init = 1;
224         }
225
226         algo = sched_getscheduler(pid);
227         max  = sched_get_priority_max(algo);
228
229         p = std_sched_param;
230         p.sched_priority = max;
231         res = sched_setparam(pid, &p);
232
233         return res;
234 }
235
236 int ir_timer_leave_high_priority(void)
237 {
238         int res   = 0;
239         pid_t pid = getpid();
240
241         if (std_sched_param_init)
242                 res = sched_setparam(pid, &std_sched_param);
243
244         return res;
245 }
246
247 #elif defined(_WIN32)
248
249 static int initial_priority = THREAD_PRIORITY_NORMAL;
250
251 int ir_timer_leave_high_priority(void)
252 {
253         int res = 0;
254         if (!SetThreadPriority(GetCurrentThread(), initial_priority)) {
255                 fprintf(stderr, "Failed to leave high priority (%d)\n", GetLastError());
256                 res = GetLastError();
257         }
258
259         return res;
260 }
261
262 int ir_timer_enter_high_priority(void)
263 {
264         int res = 0;
265         initial_priority = GetThreadPriority(GetCurrentThread());
266         if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) {
267                 fprintf(stderr, "Failed to enter high priority (%d)\n", GetLastError());
268                 res = GetLastError();
269         }
270
271         return res;
272 }
273
274
275 #else
276
277 int ir_timer_enter_high_priority(void)
278 {
279         fprintf(stderr, "POSIX scheduling API not present\n");
280         return 0;
281 }
282
283 int ir_timer_leave_high_priority(void)
284 {
285         return 0;
286 }
287
288 #endif
289
290
291 #ifdef __linux__
292
293 #include <malloc.h>
294 size_t ir_get_heap_used_bytes(void)
295 {
296         struct mallinfo mi = mallinfo();
297         return mi.uordblks;
298 }
299
300 #elif defined(_WIN32) /* __linux__ */
301
302 #include <malloc.h>
303
304 size_t ir_get_heap_used_bytes(void)
305 {
306         _HEAPINFO hinfo;
307         int heapstatus;
308         size_t res = 0;
309         hinfo._pentry = NULL;
310         while ((heapstatus = _heapwalk(&hinfo)) == _HEAPOK)
311                 res += hinfo._useflag == _USEDENTRY ? hinfo._size : 0;
312         return res;
313 }
314
315 #else
316
317 size_t ir_get_heap_used_bytes(void)
318 {
319         fprintf(stderr, "function not implemented\n");
320         return 0;
321 }
322
323 #endif
324
325 /* reset a timer */
326 void ir_timer_reset(ir_timer_t *timer)
327 {
328         _time_reset(&timer->elapsed);
329         _time_reset(&timer->start);
330         timer->running = 0;
331 }
332
333 /* start a timer */
334 void ir_timer_start(ir_timer_t *timer)
335 {
336         if (timer->running)
337                 panic("timer started twice");
338
339         _time_reset(&timer->start);
340         _time_get(&timer->start);
341         timer->running = 1;
342
343         if (timer->parent == NULL) {
344                 timer->parent = timer_stack;
345         } else if (timer->parent != timer_stack) {
346                 panic("timer used at different stack positions");
347         }
348         timer_stack = timer;
349 }
350
351 void ir_timer_reset_and_start(ir_timer_t *timer)
352 {
353   _time_reset(&timer->elapsed);
354   ir_timer_start(timer);
355 }
356
357 void ir_timer_stop(ir_timer_t *timer)
358 {
359         if (!timer->running)
360                 panic("attempting to stop stopped timer");
361         if (timer != timer_stack)
362                 panic("timer stack error");
363         timer_stack = timer->parent;
364
365         ir_timer_val_t val;
366         ir_timer_val_t tgt;
367
368         _time_get(&val);
369         timer->running = 0;
370         _time_add(&timer->elapsed, &timer->elapsed, _time_sub(&tgt, &val, &timer->start));
371 }
372
373 void ir_timer_init_parent(ir_timer_t *timer)
374 {
375         if (timer == NULL)
376                 return;
377         if (timer->parent != NULL && timer->parent != timer_stack)
378                 panic("timer parent mismatch");
379         timer->parent = timer_stack;
380 }
381
382 void ir_timer_push(ir_timer_t *timer)
383 {
384         if (timer->running)
385                 panic("timer started twice");
386
387         ir_timer_t *parent = timer->parent;
388         if (timer->parent == NULL)
389                 panic("pushing timer with unknown parent");
390
391         timer->displaced = timer_stack;
392         for (ir_timer_t *t = timer_stack; t != parent; t = t->parent) {
393                 if (t == NULL)
394                         panic("parent timer not on stack");
395                 ir_timer_stop(t);
396         }
397         timer_stack = parent;
398
399         ir_timer_start(timer);
400 }
401
402 static void start_stack(ir_timer_t *timer, ir_timer_t *stop)
403 {
404         if (timer == stop)
405                 return;
406         start_stack(timer->parent, stop);
407         ir_timer_start(timer);
408 }
409
410 void ir_timer_pop(ir_timer_t *timer)
411 {
412         if (!timer->running)
413                 panic("attempting to stop stopped timer");
414         ir_timer_t *displaced = timer->displaced;
415         if (displaced == NULL)
416                 panic("timer start/stop/push/pop mismatch");
417
418         ir_timer_t *parent = timer->parent;
419         timer->displaced = NULL;
420
421         ir_timer_stop(timer);
422         start_stack(displaced, parent);
423 }
424
425 unsigned long ir_timer_elapsed_msec(const ir_timer_t *timer)
426 {
427         ir_timer_val_t v;
428         const ir_timer_val_t *elapsed = &timer->elapsed;
429
430         if (timer->running) {
431                 elapsed = &v;
432                 _time_get(&v);
433                 _time_add(&v, &timer->elapsed, _time_sub(&v, &v, &timer->start));
434         }
435         return _time_to_msec(elapsed);
436 }
437
438 unsigned long ir_timer_elapsed_usec(const ir_timer_t *timer)
439 {
440         ir_timer_val_t v;
441         const ir_timer_val_t *elapsed = &timer->elapsed;
442
443         if (timer->running) {
444                 elapsed = &v;
445                 _time_get(&v);
446                 _time_add(&v, &timer->elapsed, _time_sub(&v, &v, &timer->start));
447         }
448         return _time_to_usec(elapsed);
449 }
450
451 double ir_timer_elapsed_sec(const ir_timer_t *timer)
452 {
453         ir_timer_val_t v;
454         const ir_timer_val_t *elapsed = &timer->elapsed;
455
456         if (timer->running) {
457                 elapsed = &v;
458                 _time_get(&v);
459                 _time_add(&v, &timer->elapsed, _time_sub(&v, &v, &timer->start));
460         }
461         return _time_to_sec(elapsed);
462 }