90 lines
2.5 KiB
C
90 lines
2.5 KiB
C
|
//---
|
||
|
// libprof: A manual profiling library for gint
|
||
|
//
|
||
|
// THIS VERSION IS MODIFIED FOR CGDOOM/LIBFXCG.
|
||
|
//---
|
||
|
|
||
|
#ifndef LIBPROF_LIBPROF
|
||
|
#define LIBPROF_LIBPROF
|
||
|
|
||
|
#include <stdint.h>
|
||
|
|
||
|
//---
|
||
|
// Initialization
|
||
|
//---
|
||
|
|
||
|
/* prof_init(): Initialize the profiler's timer */
|
||
|
int prof_init(void);
|
||
|
|
||
|
/* prof_quit(): Free the profiler's timer */
|
||
|
void prof_quit(void);
|
||
|
|
||
|
//---
|
||
|
// Runtime time measurement
|
||
|
//---
|
||
|
|
||
|
#define TMU0_TCOR ((volatile uint32_t *)0xa4490008)
|
||
|
#define TMU0_TCNT ((volatile uint32_t *)0xa449000c)
|
||
|
#define TMU0_TCR ((volatile uint16_t *)0xa4490010)
|
||
|
#define TMU_TSTR ((volatile uint8_t *)0xa4490004)
|
||
|
|
||
|
/* Context object, has an elasped delay and a recursion level. This object can
|
||
|
be created on the stack of a function that measures its execution time,
|
||
|
except if the function is recursive, in which case it should be either
|
||
|
static or global. */
|
||
|
typedef struct prof_t
|
||
|
{
|
||
|
uint32_t rec;
|
||
|
uint32_t elapsed;
|
||
|
} prof_t;
|
||
|
|
||
|
/* prof_make(): Create a new context object
|
||
|
A context can be cleared by assigning it prof_make() again. */
|
||
|
#define prof_make() ((prof_t){ 0, 0 })
|
||
|
|
||
|
/* Timer counter */
|
||
|
#define PROF_TCNT TMU0_TCNT
|
||
|
|
||
|
/* prof_enter(): Start counting time for a function
|
||
|
This macro should be called at the start of the context scope. If the
|
||
|
function was already executing then the deepest instance in the stack is
|
||
|
used instead of creating a new counter. */
|
||
|
#define prof_enter(prof) { \
|
||
|
if(!prof.rec++) prof.elapsed += *PROF_TCNT; \
|
||
|
}
|
||
|
|
||
|
/* prof_leave(): Stop counting time for a function
|
||
|
This should be called at the end of the context scope; it only actually
|
||
|
stops if there is no deeper instance of the context in the stack. If there
|
||
|
are not as exactly as many prof_leave()'s as prof_enter()'s then the
|
||
|
resulting time measure will not be relevant at all. */
|
||
|
#define prof_leave(prof) { \
|
||
|
if(!--prof.rec) prof.elapsed -= *PROF_TCNT; \
|
||
|
}
|
||
|
|
||
|
/* prof_exec(): Measure a single block of code
|
||
|
This operation can be used when profiling is not required, and instead
|
||
|
libprof is used to measure the performance of a single bit of code. Use it
|
||
|
like this:
|
||
|
|
||
|
uint32_t elasped_us = prof_exec({
|
||
|
exec_code();
|
||
|
}); */
|
||
|
#define prof_exec(code) ({ \
|
||
|
prof_t prof = prof_make(); \
|
||
|
prof_enter(prof); \
|
||
|
code; \
|
||
|
prof_leave(prof); \
|
||
|
prof_time(prof); \
|
||
|
})
|
||
|
|
||
|
//---
|
||
|
// Post-measurement analysis
|
||
|
//---
|
||
|
|
||
|
/* prof_time(): Time spent in a given context, in microseconds
|
||
|
Should only be called when the context is not currently executing. */
|
||
|
uint32_t prof_time(prof_t prof);
|
||
|
|
||
|
#endif /* LIBPROF_LIBPROF */
|