libprof/libprof.h

110 lines
2.9 KiB
C
Raw Permalink Normal View History

//---
// libprof: A manual profiling library for gint
//---
#ifndef LIBPROF_LIBPROF
#define LIBPROF_LIBPROF
2022-02-27 17:27:45 +01:00
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <gint/defs/attributes.h>
/* This is substituted by CMake at compile-time */
#define PROF_VERSION "@libprof_VERSION@"
//---
// Initialization
//---
/* prof_init(): Initialize the profiler's timer
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.
Returns non-zero if no timer is available. */
int prof_init(void);
/* prof_quit(): Free the profiler's timer */
void prof_quit(void);
//---
// Runtime time measurement
//---
/* 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 })
/* 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. */
#define prof_enter(prof) { \
2022-08-16 09:07:12 +02:00
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) { \
2022-08-16 09:07:12 +02:00
if(!--(prof).rec) (prof).elapsed -= *prof_tcnt; \
}
/* Variant of prof_enter()/prof_leave() for non-recursive contexts */
#define prof_enter_norec(prof) { \
2022-08-16 09:07:12 +02:00
(prof).elapsed += *prof_tcnt; \
}
#define prof_leave_norec(prof) { \
2022-08-16 09:07:12 +02:00
(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) ({ \
2022-08-16 09:07:12 +02:00
prof_t _prof = prof_make(); \
prof_enter(_prof); \
code; \
2022-08-16 09:07:12 +02:00
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);
2022-02-27 17:27:45 +01:00
#ifdef __cplusplus
}
#endif
#endif /* LIBPROF_LIBPROF */