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