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