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:
parent
7aada07d23
commit
392925ac3e
|
@ -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__ */
|
||||
|
|
|
@ -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__ */
|
|
@ -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__ */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
//---
|
||||
|
|
Loading…
Reference in New Issue