VxKernel 0.6.0-8 : Add profiling primitives in timer API

@add
<> include/vhex/timer
  | add profiling API
  | add the profiling primitives in driver interface
  | add profiling type
<> src/driver/mpu/sh/sh7305/tmu
  | add profiling primitives
  | add profiling information in driver definition
<> src/module/timer
  | add profiling driver binding
This commit is contained in:
Yann MAGNIN 2022-06-15 12:03:21 +02:00
parent 7aada07d23
commit 392925ac3e
5 changed files with 248 additions and 10 deletions

View File

@ -5,7 +5,9 @@
#include <vhex/timer/types.h>
/* timer_drv_interface - driver interface */
struct timer_drv_interface {
struct timer_drv_interface
{
/* timer API */
tid_t (*timer_configure)(uint64_t delay_us, timer_call_t callback);
int (*timer_start)(tid_t timer);
int (*timer_pause)(tid_t timer);
@ -13,6 +15,14 @@ struct timer_drv_interface {
int (*timer_wait)(tid_t timer);
int (*timer_spinwait)(tid_t timer);
int (*timer_reload)(tid_t timer, uint64_t delay);
/* profiling */
int (*timer_prof_init)(timer_prof_t *prof);
void (*timer_prof_enter)(timer_prof_t *prof);
void (*timer_prof_enter_rec)(timer_prof_t *prof);
void (*timer_prof_leave_rec)(timer_prof_t *prof);
void (*timer_prof_leave)(timer_prof_t *prof);
uint32_t (*timer_prof_time)(timer_prof_t *prof);
int (*timer_prof_quit)(timer_prof_t *prof);
};
#endif /* __VHEX_TIMER_INTERFACE__ */

View File

@ -0,0 +1,58 @@
#ifndef __VHEX_PROFILING__
# define __VHEX_PROFILING__
#include <vhex/timer/types.h>
//---
// Runtime time measurement API
//---
/* timer_prof_init(): Create a new context object */
extern int timer_prof_init(timer_prof_t *prof);
/* timer_prof_enter(): Start counting time for a function
This fucntion should be called at the start of the context scope */
extern void timer_prof_enter(timer_prof_t *prof);
/* timer_prof_leave(): Stop counting time for a function
This should be called at the end of the context scope. */
extern void timer_prof_leave(timer_prof_t *prof);
/* Variant of timer_prof_enter()/timer_prof_leave() for recursive contexts */
extern void timer_prof_enter_rec(timer_prof_t *prof);
extern void timer_prof_leave_rec(timer_prof_t *prof);
/* timer_prof_exec(): Measure a single block of (non-recurive) code
This operation can be used when profiling is not required, and instead
its 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 timer_prof_exec(code) ({ \
timer_prof_t prof; \
timer_prof_init(&prof); \
timer_prof_enter(&prof); \
code; \
timer_prof_leave(&prof); \
uint32_t time = timer_prof_time(&prof); \
timer_prof_quit(&prof); \
time; \
})
/* timer_prof_quit() : uninit timer_prof object */
extern int timer_prof_quit(timer_prof_t *prof);
//---
// Post-measurement analysis
//---
/* timer_prof_time(): Time spent in a given context, in microseconds
Should only be called when the context is not currently executing. */
extern uint32_t timer_prof_time(timer_prof_t *prof);
#endif /* __VHEX_PROFILING__ */

View File

@ -7,4 +7,15 @@
/* timer ID */
typedef int tid_t;
/* 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 timer_prof
{
uint32_t rec;
uint32_t elapsed;
} VPACKED(4) timer_prof_t;
#endif /* __VHEX_TIMER_TYPES__ */

View File

@ -257,8 +257,99 @@ int sh7305_tmu_spinwait(tid_t id)
return (0);
}
//---
// hardware primitives
// Public profiling API
//---
static uint32_t volatile *tmu_prof_tcnt = NULL;
static int tmu_prof_counter = 0;
static int tmu_prof_timer = -1;
/* sh7305_tmu_prof_make() : initialise a new */
int sh7305_tmu_prof_init(timer_prof_t *prof)
{
if (tmu_prof_tcnt == NULL) {
tmu_prof_timer = -1;
for(int t = 0; t < 2; t++)
{
if (!available(t))
continue;
tmu_prof_timer = t;
tmu_prof_tcnt = &TMU[t].TCNT;
TMU[t].TCOR = 0xffffffff;
TMU[t].TCNT = 0xffffffff;
TMU[t].TCR.TPSC = TIMER_Pphi_4;
set(TMU[t].TCR.UNF, 0);
TMU[t].TCR.UNIE = 1;
TMU[t].TCR.CKEG = 0;
*TSTR = *TSTR | (1 << t);
break;
}
if (tmu_prof_timer < 0)
return (-1);
}
prof->rec = 0;
prof->elapsed = 0;
tmu_prof_counter += 1;
return (0);
}
/* sh7305_tmu_prof_enter(): Start counting time for a function */
void sh7305_tmu_prof_enter(timer_prof_t *prof)
{
prof->elapsed += *tmu_prof_tcnt;
}
/* sh7305_tmu_prof_enter_rec(): Start counting time for a recursive function */
void sh7305_tmu_prof_enter_rec(timer_prof_t *prof)
{
if (!prof->rec++)
prof->elapsed += *tmu_prof_tcnt;
}
/* sh7305_tmu_prof_leave_rec(): Start counting time for a recursive function */
void sh7305_tmu_prof_leave_rec(timer_prof_t *prof)
{
if (!--prof->rec)
prof->elapsed -= *tmu_prof_tcnt;
}
/* sh7305_tmu_prof_leave(): Stop counting time for a function */
void sh7305_tmu_prof_leave(timer_prof_t *prof)
{
prof->elapsed -= *tmu_prof_tcnt;
}
/* sh7305_prof_time(): Time spent in a given context, in microseconds */
uint32_t sh7305_tmu_prof_time(timer_prof_t *prof)
{
struct cpg_clock_frequency cpg_freq;
cpg_clock_freq(&cpg_freq);
return ((uint64_t)prof->elapsed * 4 * 1000000) / cpg_freq.Pphi_f;
}
int sh7305_tmu_prof_quit(timer_prof_t *prof)
{
(void)prof;
if (--tmu_prof_counter)
return (0);
if(tmu_prof_timer >= 0)
sh7305_tmu_stop(tmu_prof_timer);
tmu_prof_timer = -1;
tmu_prof_tcnt = NULL;
}
//---
// hardware specification
//---
/* __tmu_configure() : configure the SH7305 TMU/ETMU module */
@ -399,13 +490,22 @@ struct vhex_driver drv_tmu = {
.UNUSED = 0
},
.module_data = &(struct timer_drv_interface){
.timer_configure = &sh7305_tmu_configure,
.timer_start = &sh7305_tmu_start,
.timer_pause = &sh7305_tmu_pause,
.timer_stop = &sh7305_tmu_stop,
.timer_wait = &sh7305_tmu_wait,
.timer_spinwait = &sh7305_tmu_spinwait,
.timer_reload = &sh7305_tmu_reload
/* timer API */
.timer_configure = &sh7305_tmu_configure,
.timer_start = &sh7305_tmu_start,
.timer_pause = &sh7305_tmu_pause,
.timer_stop = &sh7305_tmu_stop,
.timer_wait = &sh7305_tmu_wait,
.timer_spinwait = &sh7305_tmu_spinwait,
.timer_reload = &sh7305_tmu_reload,
/* profiling API*/
.timer_prof_init = &sh7305_tmu_prof_init,
.timer_prof_enter = &sh7305_tmu_prof_enter,
.timer_prof_enter_rec = &sh7305_tmu_prof_enter_rec,
.timer_prof_leave_rec = &sh7305_tmu_prof_leave_rec,
.timer_prof_leave = &sh7305_tmu_prof_leave,
.timer_prof_time = &sh7305_tmu_prof_time,
.timer_prof_quit = &sh7305_tmu_prof_quit,
}
};
VHEX_DECLARE_DRIVER(03, drv_tmu);

View File

@ -12,7 +12,7 @@ struct {
} timer_info;
//---
// user-level API
// user-level timer API
//---
/* timer_configure(): Reserve and configure a timer */
@ -72,6 +72,65 @@ int timer_reload(tid_t timer, uint64_t delay_us)
}
//---
// user-level profiling API
//---
/* timer_prof_init(): Create a new context object */
int timer_prof_init(timer_prof_t *prof)
{
if (timer_info.driver.timer_prof_init != NULL)
return (timer_info.driver.timer_prof_init(prof));
return (-1);
}
/* timer_prof_enter(): Start counting time for a function */
void timer_prof_enter(timer_prof_t *prof)
{
if (timer_info.driver.timer_prof_enter != NULL)
timer_info.driver.timer_prof_enter(prof);
}
/* timer_prof_leave(): Stop counting time for a function */
void timer_prof_leave(timer_prof_t *prof)
{
if (timer_info.driver.timer_prof_leave != NULL)
timer_info.driver.timer_prof_leave(prof);
}
/* timer_prof_enter_rec(): Start counting time for a recursive function */
void timer_prof_enter_rec(timer_prof_t *prof)
{
if (timer_info.driver.timer_prof_enter_rec != NULL)
timer_info.driver.timer_prof_enter_rec(prof);
}
/* timer_prof_leave_rec(): Stop counting time for a recursive function */
void timer_prof_leave_rec(timer_prof_t *prof)
{
if (timer_info.driver.timer_prof_leave_rec != NULL)
timer_info.driver.timer_prof_leave_rec(prof);
}
/* timer_prof_quit() : uninit timer_prof object */
int timer_prof_quit(timer_prof_t *prof)
{
if (timer_info.driver.timer_prof_quit != NULL)
return (timer_info.driver.timer_prof_quit(prof));
return (-1);
}
/* timer_prof_time(): Time spent in a given context, in microseconds */
uint32_t timer_prof_time(timer_prof_t *prof)
{
if (timer_info.driver.timer_prof_time != NULL)
return (timer_info.driver.timer_prof_time(prof));
return (-1);
}
//---
// Kernel module information
//---