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