Browse Source

basic working implementation with manual calls

master
Lephenixnoir 2 months ago
parent
commit
2c78a2cfeb
3 changed files with 150 additions and 2 deletions
  1. 4
    2
      Makefile
  2. 71
    0
      libprof.c
  3. 75
    0
      libprof.h

+ 4
- 2
Makefile View File

@@ -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
- 0
libprof.c View File

@@ -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
- 0
libprof.h View 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…
Cancel
Save