*/
FIRM_API void ir_timer_stop(ir_timer_t *timer);
+/**
+ * Set currently running timer as parent to @p timer
+ */
+FIRM_API void ir_timer_init_parent(ir_timer_t *timer);
+
/**
* Push a timer of the timer stack. This automatically
* stop the previous timer on tos and start the new one.
* @param timer The timer to push on stack.
* @return non-zero on succes, zero if the timer is already on the stack.
*/
-FIRM_API int ir_timer_push(ir_timer_t *timer);
+FIRM_API void ir_timer_push(ir_timer_t *timer);
/**
* Pop the current timer. This automatically stops it and
* start the timer that is now on the stack.
* @return the popped timer
*/
-FIRM_API ir_timer_t *ir_timer_pop(void);
+FIRM_API void ir_timer_pop(ir_timer_t *timer);
/**
* Returns the number of milliseconds, the timer has elapsed.
*/
FIRM_API unsigned long ir_timer_elapsed_usec(const ir_timer_t *timer);
+/**
+ * Returns the number of seconds, the timer has elapsed.
+ */
+FIRM_API double ir_timer_elapsed_sec(const ir_timer_t *timer);
+
#include "end.h"
#endif
#include "timing.h"
#include "xmalloc.h"
+#include "error.h"
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
struct ir_timer_t {
ir_timer_val_t elapsed; /**< the elapsed time so far */
ir_timer_val_t start; /**< the start value of the timer */
- ir_timer_t *link; /**< link to the next entry in the timer stack */
+ ir_timer_t *parent; /**< parent of a timer */
+ ir_timer_t *displaced; /**< former timer in case of timer_push */
unsigned running : 1; /**< set if this timer is running */
};
ir_timer_t *ir_timer_new(void)
{
ir_timer_t *timer = XMALLOCZ(ir_timer_t);
-
_time_reset(&timer->elapsed);
_time_reset(&timer->start);
- timer->link = NULL;
- timer->running = 0;
-
return timer;
}
+ (unsigned long) elapsed->tv_usec;
}
+static inline double _time_to_sec(const ir_timer_val_t *elapsed)
+{
+ return (double)elapsed->tv_sec + (double)elapsed->tv_usec / 1000000.0;
+}
+
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)
{
LARGE_INTEGER freq;
if (!QueryPerformanceFrequency(&freq))
- return (unsigned long) elapsed->lo_prec;
+ return (unsigned long) elapsed->lo_prec * 1000;
return (unsigned long) ((elapsed->hi_prec.QuadPart * 1000000) / freq.QuadPart);
}
+static inline double _time_to_sec(const ir_timer_val_t *elapsed)
+{
+ LARGE_INTEGER freq;
+
+ if (!QueryPerformanceFrequency(&freq))
+ return (double) elapsed->lo_prec / 1000.;
+
+ return (double)elapsed->hi_prec.QuadPart / (double)freq.QuadPart;
+}
+
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)
{
LARGE_INTEGER dummy;
/* start a timer */
void ir_timer_start(ir_timer_t *timer)
{
+ if (timer->running)
+ panic("timer started twice");
+
_time_reset(&timer->start);
_time_get(&timer->start);
timer->running = 1;
+
+ if (timer->parent == NULL) {
+ timer->parent = timer_stack;
+ } else if (timer->parent != timer_stack) {
+ panic("timer used at different stack positions");
+ }
+ timer_stack = timer;
}
void ir_timer_reset_and_start(ir_timer_t *timer)
ir_timer_start(timer);
}
-/* stop a running timer */
void ir_timer_stop(ir_timer_t *timer)
{
- /* If the timer is running stop, measure the time and add it to the
- * elapsed time. */
- if (timer->running) {
- ir_timer_val_t val;
- ir_timer_val_t tgt;
+ if (!timer->running)
+ panic("attempting to stop stopped timer");
+ if (timer != timer_stack)
+ panic("timer stack error");
+ timer_stack = timer->parent;
+
+ ir_timer_val_t val;
+ ir_timer_val_t tgt;
+
+ _time_get(&val);
+ timer->running = 0;
+ _time_add(&timer->elapsed, &timer->elapsed, _time_sub(&tgt, &val, &timer->start));
+}
- _time_get(&val);
- timer->running = 0;
- _time_add(&timer->elapsed, &timer->elapsed, _time_sub(&tgt, &val, &timer->start));
- _time_reset(&timer->start);
+void ir_timer_init_parent(ir_timer_t *timer)
+{
+ if (timer == NULL)
+ return;
+ if (timer->parent != NULL && timer->parent != timer_stack)
+ panic("timer parent mismatch");
+ timer->parent = timer_stack;
+}
+
+void ir_timer_push(ir_timer_t *timer)
+{
+ if (timer->running)
+ panic("timer started twice");
+
+ ir_timer_t *parent = timer->parent;
+ if (timer->parent == NULL)
+ panic("pushing timer with unknown parent");
+
+ timer->displaced = timer_stack;
+ for (ir_timer_t *t = timer_stack; t != parent; t = t->parent) {
+ if (t == NULL)
+ panic("parent timer not on stack");
+ ir_timer_stop(t);
}
+ timer_stack = parent;
+
+ ir_timer_start(timer);
}
-/* push a timer on the stack */
-int ir_timer_push(ir_timer_t *timer)
+static void start_stack(ir_timer_t *timer, ir_timer_t *stop)
{
- if (timer->link)
- return 0;
- timer->link = timer_stack;
- if (timer_stack)
- ir_timer_stop(timer_stack);
+ if (timer == stop)
+ return;
+ start_stack(timer->parent, stop);
ir_timer_start(timer);
- timer_stack = timer;
- return 1;
}
-/* pop a timer from the stack */
-ir_timer_t *ir_timer_pop(void)
+void ir_timer_pop(ir_timer_t *timer)
{
- ir_timer_t *timer = timer_stack;
- if (timer) {
- ir_timer_stop(timer);
- timer_stack = timer->link;
- timer->link = NULL;
- if (timer_stack)
- ir_timer_start(timer_stack);
- }
- return timer;
+ if (!timer->running)
+ panic("attempting to stop stopped timer");
+ ir_timer_t *displaced = timer->displaced;
+ if (displaced == NULL)
+ panic("timer start/stop/push/pop mismatch");
+
+ ir_timer_t *parent = timer->parent;
+ timer->displaced = NULL;
+
+ ir_timer_stop(timer);
+ start_stack(displaced, parent);
}
unsigned long ir_timer_elapsed_msec(const ir_timer_t *timer)
}
return _time_to_usec(elapsed);
}
+
+double ir_timer_elapsed_sec(const ir_timer_t *timer)
+{
+ ir_timer_val_t v;
+ const ir_timer_val_t *elapsed = &timer->elapsed;
+
+ if (timer->running) {
+ elapsed = &v;
+ _time_get(&v);
+ _time_add(&v, &timer->elapsed, _time_sub(&v, &v, &timer->start));
+ }
+ return _time_to_sec(elapsed);
+}