Let panic() print file, line and function.
[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
32 #ifdef _WIN32
33 #define WIN32_LEAN_AND_MEAN
34 #include <windows.h>
35 #include <mmsystem.h>
36
37 /* Win32 timer value. */
38 typedef union {
39         unsigned lo_prec;       /**< 32bit low precision time in milli seconds */
40         LARGE_INTEGER hi_prec;  /**< 64bit high precision time in micro seconds */
41 } ir_timer_val_t;
42
43 #else
44
45 #include <unistd.h>
46 #define HAVE_GETTIMEOFDAY
47
48 /*
49  * Just, if we have gettimeofday()
50  * Someday, we will have a check here.
51  */
52 #ifndef __USE_BSD
53 #define __USE_BSD
54 #endif
55 #include <sys/time.h>
56
57 /* Linux timer value. */
58 typedef struct timeval ir_timer_val_t;
59
60 #endif /* _Win32 */
61
62 #include <stddef.h>
63
64 static inline void _time_reset(ir_timer_val_t *val);
65
66 /**
67  * A timer.
68  */
69 struct ir_timer_t {
70         ir_timer_val_t elapsed;     /**< the elapsed time so far */
71         ir_timer_val_t start;       /**< the start value of the timer */
72         ir_timer_t     *link;       /**< link to the next entry in the timer stack */
73         unsigned       running : 1; /**< set if this timer is running */
74 };
75
76 /** The top of the timer stack */
77 static ir_timer_t *timer_stack;
78
79 ir_timer_t *ir_timer_new(void)
80 {
81         ir_timer_t *timer = XMALLOCZ(ir_timer_t);
82
83         _time_reset(&timer->elapsed);
84         _time_reset(&timer->start);
85         timer->link    = NULL;
86         timer->running = 0;
87
88         return timer;
89 }
90
91 void ir_timer_free(ir_timer_t *timer)
92 {
93         xfree(timer);
94 }
95
96 #ifdef HAVE_GETTIMEOFDAY
97
98 static inline void _time_get(ir_timer_val_t *val)
99 {
100         gettimeofday(val, NULL);
101 }
102
103 static inline void _time_reset(ir_timer_val_t *val)
104 {
105         timerclear(val);
106 }
107
108 static inline unsigned long _time_to_msec(const ir_timer_val_t *elapsed)
109 {
110         return (unsigned long) elapsed->tv_sec * 1000UL
111                 + (unsigned long) elapsed->tv_usec / 1000UL;
112 }
113
114 static inline unsigned long _time_to_usec(const ir_timer_val_t *elapsed)
115 {
116         return (unsigned long) elapsed->tv_sec * 1000000UL
117                 + (unsigned long) elapsed->tv_usec;
118 }
119
120 static inline ir_timer_val_t *_time_add(ir_timer_val_t *res,
121                 const ir_timer_val_t *lhs, const ir_timer_val_t *rhs)
122 {
123         timeradd(lhs, rhs, res);
124                 return res;
125 }
126
127 static inline ir_timer_val_t *_time_sub(ir_timer_val_t *res,
128                 const ir_timer_val_t *lhs, const ir_timer_val_t *rhs)
129 {
130         timersub(lhs, rhs, res);
131         return res;
132 }
133
134 #elif defined(_WIN32)
135
136 static inline void _time_get(ir_timer_val_t *val)
137 {
138         if (!QueryPerformanceCounter(&val->hi_prec))
139                 val->lo_prec = timeGetTime();
140 }
141
142 static inline void _time_reset(ir_timer_val_t *val)
143 {
144         memset(val, 0, sizeof(val[0]));
145 }
146
147 static inline unsigned long _time_to_msec(const ir_timer_val_t *elapsed)
148 {
149         LARGE_INTEGER freq;
150
151         if (!QueryPerformanceFrequency(&freq))
152                 return (unsigned long) elapsed->lo_prec;
153
154         return (unsigned long) ((elapsed->hi_prec.QuadPart * 1000) / freq.QuadPart);
155 }
156
157 static inline unsigned long _time_to_usec(const ir_timer_val_t *elapsed)
158 {
159         LARGE_INTEGER freq;
160
161         if (!QueryPerformanceFrequency(&freq))
162                 return (unsigned long) elapsed->lo_prec;
163
164         return (unsigned long) ((elapsed->hi_prec.QuadPart * 1000000) / freq.QuadPart);
165 }
166
167 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)
168 {
169         LARGE_INTEGER dummy;
170         if (QueryPerformanceFrequency(&dummy))
171                 res->hi_prec.QuadPart = lhs->hi_prec.QuadPart + rhs->hi_prec.QuadPart;
172         else
173                 res->lo_prec = lhs->lo_prec + rhs->lo_prec;
174
175         return res;
176 }
177
178 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)
179 {
180         LARGE_INTEGER dummy;
181         if (QueryPerformanceFrequency(&dummy))
182                 res->hi_prec.QuadPart = lhs->hi_prec.QuadPart - rhs->hi_prec.QuadPart;
183         else
184                 res->lo_prec = lhs->lo_prec - rhs->lo_prec;
185
186         return res;
187 }
188
189 #endif /* _WIN32 */
190
191 #if defined(_XOPEN_REALTIME) && _XOPEN_REALTIME != -1
192
193 #include <sys/types.h>
194 #include <sched.h>
195
196 static struct sched_param std_sched_param;
197 static int std_sched_param_init = 0;
198
199 int ir_timer_enter_high_priority(void)
200 {
201         pid_t pid = getpid();
202
203         struct sched_param p;
204         int res, max, algo;
205
206         if (!std_sched_param_init) {
207                 res = sched_getparam(pid, &std_sched_param);
208                 std_sched_param_init = 1;
209         }
210
211         algo = sched_getscheduler(pid);
212         max  = sched_get_priority_max(algo);
213
214         p = std_sched_param;
215         p.sched_priority = max;
216         res = sched_setparam(pid, &p);
217
218         return res;
219 }
220
221 int ir_timer_leave_high_priority(void)
222 {
223         int res   = 0;
224         pid_t pid = getpid();
225
226         if (std_sched_param_init)
227                 res = sched_setparam(pid, &std_sched_param);
228
229         return res;
230 }
231
232 #elif defined(_WIN32)
233
234 static int initial_priority = THREAD_PRIORITY_NORMAL;
235
236 int ir_timer_leave_high_priority(void)
237 {
238         int res = 0;
239         if (!SetThreadPriority(GetCurrentThread(), initial_priority)) {
240                 fprintf(stderr, "Failed to leave high priority (%d)\n", GetLastError());
241                 res = GetLastError();
242         }
243
244         return res;
245 }
246
247 int ir_timer_enter_high_priority(void)
248 {
249         int res = 0;
250         initial_priority = GetThreadPriority(GetCurrentThread());
251         if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) {
252                 fprintf(stderr, "Failed to enter high priority (%d)\n", GetLastError());
253                 res = GetLastError();
254         }
255
256         return res;
257 }
258
259
260 #else
261
262 int ir_timer_enter_high_priority(void)
263 {
264         fprintf(stderr, "POSIX scheduling API not present\n");
265         return 0;
266 }
267
268 int ir_timer_leave_high_priority(void)
269 {
270         return 0;
271 }
272
273 #endif
274
275
276 #ifdef __linux__
277
278 #include <malloc.h>
279 size_t ir_get_heap_used_bytes(void)
280 {
281         struct mallinfo mi = mallinfo();
282         return mi.uordblks;
283 }
284
285 #elif defined(_WIN32) /* __linux__ */
286
287 #include <malloc.h>
288
289 size_t ir_get_heap_used_bytes(void)
290 {
291         _HEAPINFO hinfo;
292         int heapstatus;
293         size_t res = 0;
294         hinfo._pentry = NULL;
295         while ((heapstatus = _heapwalk(&hinfo)) == _HEAPOK)
296                 res += hinfo._useflag == _USEDENTRY ? hinfo._size : 0;
297         return res;
298 }
299
300 #else
301
302 size_t ir_get_heap_used_bytes(void)
303 {
304         fprintf(stderr, "function not implemented\n");
305         return 0;
306 }
307
308 #endif
309
310 /* reset a timer */
311 void ir_timer_reset(ir_timer_t *timer)
312 {
313         _time_reset(&timer->elapsed);
314         _time_reset(&timer->start);
315         timer->running = 0;
316 }
317
318 /* start a timer */
319 void ir_timer_start(ir_timer_t *timer)
320 {
321         _time_reset(&timer->start);
322         _time_get(&timer->start);
323         timer->running = 1;
324 }
325
326 void ir_timer_reset_and_start(ir_timer_t *timer)
327 {
328   _time_reset(&timer->elapsed);
329   ir_timer_start(timer);
330 }
331
332 /* stop a running timer */
333 void ir_timer_stop(ir_timer_t *timer)
334 {
335         /* If the timer is running stop, measure the time and add it to the
336          * elapsed time. */
337         if (timer->running) {
338                 ir_timer_val_t val;
339                 ir_timer_val_t tgt;
340
341                 _time_get(&val);
342                 timer->running = 0;
343                 _time_add(&timer->elapsed, &timer->elapsed, _time_sub(&tgt, &val, &timer->start));
344                 _time_reset(&timer->start);
345         }
346 }
347
348 /* push a timer on the stack */
349 int ir_timer_push(ir_timer_t *timer)
350 {
351         if (timer->link)
352                 return 0;
353         timer->link = timer_stack;
354         if (timer_stack)
355                 ir_timer_stop(timer_stack);
356         ir_timer_start(timer);
357         timer_stack = timer;
358         return 1;
359 }
360
361 /* pop a timer from the stack */
362 ir_timer_t *ir_timer_pop(void)
363 {
364         ir_timer_t *timer = timer_stack;
365         if (timer) {
366                 ir_timer_stop(timer);
367                 timer_stack = timer->link;
368                 timer->link = NULL;
369                 if (timer_stack)
370                         ir_timer_start(timer_stack);
371         }
372         return timer;
373 }
374
375 unsigned long ir_timer_elapsed_msec(const ir_timer_t *timer)
376 {
377         ir_timer_val_t v;
378         const ir_timer_val_t *elapsed = &timer->elapsed;
379
380         if (timer->running) {
381                 elapsed = &v;
382                 _time_get(&v);
383                 _time_add(&v, &timer->elapsed, _time_sub(&v, &v, &timer->start));
384         }
385         return _time_to_msec(elapsed);
386 }
387
388 unsigned long ir_timer_elapsed_usec(const ir_timer_t *timer)
389 {
390         ir_timer_val_t v;
391         const ir_timer_val_t *elapsed = &timer->elapsed;
392
393         if (timer->running) {
394                 elapsed = &v;
395                 _time_get(&v);
396                 _time_add(&v, &timer->elapsed, _time_sub(&v, &v, &timer->start));
397         }
398         return _time_to_usec(elapsed);
399 }