mirror of
https://git.planet-casio.com/Lephenixnoir/libprof.git
synced 2024-12-26 19:43:41 +01:00
basic working implementation with manual calls
This commit is contained in:
parent
d8883da3c0
commit
2c78a2cfeb
3 changed files with 150 additions and 2 deletions
6
Makefile
6
Makefile
|
@ -2,9 +2,10 @@
|
|||
# libprof Makefile
|
||||
|
||||
cflags := -m3 -mb -ffreestanding -nostdlib -fstrict-volatile-bitfields -Wall \
|
||||
-Wextra -Os -std=c11
|
||||
target := sh3eb-elf
|
||||
-Wextra -Os -I .
|
||||
target ?= sh3eb-elf
|
||||
lib := libprof.a
|
||||
header := libprof.h
|
||||
|
||||
prefix := $(shell $(target)-gcc -print-search-dirs | grep install \
|
||||
| sed 's/install: //')
|
||||
|
@ -42,3 +43,4 @@ distclean: clean
|
|||
|
||||
install:
|
||||
cp $(lib) $(prefix)
|
||||
cp $(header) $(prefix)/include
|
||||
|
|
71
libprof.c
71
libprof.c
|
@ -1,2 +1,73 @@
|
|||
#include <gint/timer.h>
|
||||
#include <gint/clock.h>
|
||||
#include <gint/mpu/tmu.h>
|
||||
#include <gint/std/stdlib.h>
|
||||
#include <gint/hardware.h>
|
||||
|
||||
#include <libprof.h>
|
||||
|
||||
/* Recursion depth of each function currently being executed */
|
||||
uint8_t *prof_rec = NULL;
|
||||
/* Time that has elapsed within each function; the value for a given function
|
||||
is only relevant when it is not executing, due to optimizations */
|
||||
uint32_t *prof_elapsed = NULL;
|
||||
/* Timer counter */
|
||||
uint32_t volatile *prof_tcnt = NULL;
|
||||
/* Timer ID */
|
||||
static int prof_timer;
|
||||
|
||||
/* prof_init(): Initialize the profiler's data and timer */
|
||||
int prof_init(int n, int timer)
|
||||
{
|
||||
if((unsigned)timer >= 3) return 1;
|
||||
|
||||
prof_rec = malloc(n * sizeof *prof_rec);
|
||||
prof_elapsed = malloc(n * sizeof *prof_elapsed);
|
||||
|
||||
int status = timer_setup(timer, 0xffffffff, timer_Po_4, NULL, NULL);
|
||||
|
||||
if(!prof_rec || !prof_elapsed || status < 0)
|
||||
{
|
||||
prof_quit();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Fix the configuration done by gint by disabling the interrupt */
|
||||
if(isSH3())
|
||||
{
|
||||
SH7705_TMU.TMU[timer].TCR.UNIE = 0;
|
||||
prof_tcnt = &SH7705_TMU.TMU[timer].TCNT;
|
||||
}
|
||||
else
|
||||
{
|
||||
SH7305_TMU.TMU[timer].TCR.UNIE = 0;
|
||||
prof_tcnt = &SH7305_TMU.TMU[timer].TCNT;
|
||||
}
|
||||
|
||||
timer_start(timer);
|
||||
prof_timer = timer;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* prof_quit(): Free the profiler's data and timer */
|
||||
void prof_quit(void)
|
||||
{
|
||||
timer_stop(prof_timer);
|
||||
|
||||
free(prof_rec);
|
||||
free(prof_time);
|
||||
}
|
||||
|
||||
//---
|
||||
// Post-measurement analysis
|
||||
//---
|
||||
|
||||
/* prof_time(): Time spent in a given context, in microseconds */
|
||||
uint32_t prof_time(int ctx)
|
||||
{
|
||||
int Pphi = clock_freq()->Pphi_f;
|
||||
uint64_t time = prof_elapsed[ctx];
|
||||
|
||||
return (time * 4 * 1000000) / Pphi;
|
||||
}
|
||||
|
|
75
libprof.h
Normal file
75
libprof.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
//---
|
||||
// libprof: A manual profiling library for gint
|
||||
//---
|
||||
|
||||
#ifndef LIBPROF_LIBPROF
|
||||
#define LIBPROF_LIBPROF
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
//---
|
||||
// Initialization
|
||||
//---
|
||||
|
||||
/* prof_init(): Initialize the profiler's data and timer
|
||||
|
||||
Initializes [prof_rec] and [prof_time] (see below) with enough elements to
|
||||
hold all the context IDs. Context IDs should be numbered from 0 to [n-1];
|
||||
due to speed requirements array bounds are not checked so be careful.
|
||||
|
||||
Also starts a timer to count time. The timer ID must be set to 0, 1 or 2 as
|
||||
the standard TMU is the most tweakable and precise. libprof automatically
|
||||
selects an accurate timer configuration.
|
||||
|
||||
@n Number of different contexts (functions) that will be measured
|
||||
@timer Timer ID, see <gint/timer.h> to select one
|
||||
Returns non-zero if a setup error occurs. */
|
||||
int prof_init(int n, int timer);
|
||||
|
||||
/* prof_quit(): Free the profiler's data and timer */
|
||||
void prof_quit(void);
|
||||
|
||||
//---
|
||||
// Runtime time measurement
|
||||
//---
|
||||
|
||||
/* Recursion depth of each function currently being executed */
|
||||
extern uint8_t *prof_rec;
|
||||
/* Time that has elapsed within each function; the value for a given function
|
||||
is only relevant when it is not executing, due to optimizations */
|
||||
extern uint32_t *prof_elapsed;
|
||||
/* 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(ctx) { \
|
||||
if(!prof_rec[ctx]++) prof_elapsed[ctx] += *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(ctx) { \
|
||||
if(!--prof_rec[ctx]) prof_elapsed[ctx] -= *prof_tcnt; \
|
||||
}
|
||||
|
||||
/* prof_clear(): Clear a context's counter
|
||||
This operation is defined only if the context is not being profiled. */
|
||||
#define prof_clear(ctx) { \
|
||||
prof_elapsed[ctx] = 0; \
|
||||
}
|
||||
|
||||
//---
|
||||
// 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(int ctx);
|
||||
|
||||
#endif /* LIBPROF_LIBPROF */
|
Loading…
Reference in a new issue