mirror of
https://git.planet-casio.com/Lephenixnoir/libprof.git
synced 2024-12-28 04:23: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
|
# libprof Makefile
|
||||||
|
|
||||||
cflags := -m3 -mb -ffreestanding -nostdlib -fstrict-volatile-bitfields -Wall \
|
cflags := -m3 -mb -ffreestanding -nostdlib -fstrict-volatile-bitfields -Wall \
|
||||||
-Wextra -Os -std=c11
|
-Wextra -Os -I .
|
||||||
target := sh3eb-elf
|
target ?= sh3eb-elf
|
||||||
lib := libprof.a
|
lib := libprof.a
|
||||||
|
header := libprof.h
|
||||||
|
|
||||||
prefix := $(shell $(target)-gcc -print-search-dirs | grep install \
|
prefix := $(shell $(target)-gcc -print-search-dirs | grep install \
|
||||||
| sed 's/install: //')
|
| sed 's/install: //')
|
||||||
|
@ -42,3 +43,4 @@ distclean: clean
|
||||||
|
|
||||||
install:
|
install:
|
||||||
cp $(lib) $(prefix)
|
cp $(lib) $(prefix)
|
||||||
|
cp $(header) $(prefix)/include
|
||||||
|
|
71
libprof.c
71
libprof.c
|
@ -1,2 +1,73 @@
|
||||||
#include <gint/timer.h>
|
#include <gint/timer.h>
|
||||||
|
#include <gint/clock.h>
|
||||||
#include <gint/mpu/tmu.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