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