2019-07-17 19:00:49 +02:00
|
|
|
//---
|
|
|
|
// libprof: A manual profiling library for gint
|
|
|
|
//---
|
|
|
|
|
|
|
|
#ifndef LIBPROF_LIBPROF
|
|
|
|
#define LIBPROF_LIBPROF
|
|
|
|
|
|
|
|
#include <stdint.h>
|
2020-10-13 19:30:45 +02:00
|
|
|
#include <gint/defs/attributes.h>
|
2019-07-17 19:00:49 +02:00
|
|
|
|
|
|
|
//---
|
|
|
|
// Initialization
|
|
|
|
//---
|
|
|
|
|
2020-10-13 19:30:45 +02:00
|
|
|
/* prof_init(): Initialize the profiler's timer
|
2019-07-17 19:00:49 +02:00
|
|
|
|
2020-10-13 19:30:45 +02:00
|
|
|
Starts a timer to count time. libprof automatically selects a TMU and tries
|
|
|
|
to use TMU2 before TMU1 before TMU0 so that high-priority interrupts remain
|
|
|
|
available, and sets an accurate clock configuration.
|
2019-07-17 19:00:49 +02:00
|
|
|
|
2020-10-13 19:30:45 +02:00
|
|
|
Returns non-zero if no timer is available. */
|
|
|
|
int prof_init(void);
|
2020-06-20 23:20:20 +02:00
|
|
|
|
2020-10-13 19:30:45 +02:00
|
|
|
/* prof_quit(): Free the profiler's timer */
|
2019-07-17 19:00:49 +02:00
|
|
|
void prof_quit(void);
|
|
|
|
|
|
|
|
//---
|
|
|
|
// Runtime time measurement
|
|
|
|
//---
|
|
|
|
|
2020-10-13 19:30:45 +02:00
|
|
|
/* 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;
|
|
|
|
|
|
|
|
} GPACKED(4) 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 })
|
|
|
|
|
2019-07-17 19:00:49 +02:00
|
|
|
/* Timer counter */
|
|
|
|
extern uint32_t volatile *prof_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. */
|
2020-10-13 19:30:45 +02:00
|
|
|
#define prof_enter(prof) { \
|
|
|
|
if(!prof.rec++) prof.elapsed += *prof_tcnt; \
|
2019-07-17 19:00:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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. */
|
2020-10-13 19:30:45 +02:00
|
|
|
#define prof_leave(prof) { \
|
|
|
|
if(!--prof.rec) prof.elapsed -= *prof_tcnt; \
|
2019-07-17 19:00:49 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 19:30:45 +02:00
|
|
|
/* 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); \
|
|
|
|
})
|
2019-07-17 19:00:49 +02:00
|
|
|
|
|
|
|
//---
|
|
|
|
// Post-measurement analysis
|
|
|
|
//---
|
|
|
|
|
|
|
|
/* prof_time(): Time spent in a given context, in microseconds
|
|
|
|
Should only be called when the context is not currently executing. */
|
2020-10-13 19:30:45 +02:00
|
|
|
uint32_t prof_time(prof_t prof);
|
2019-07-17 19:00:49 +02:00
|
|
|
|
|
|
|
#endif /* LIBPROF_LIBPROF */
|