Zephyr提供一组计时API用于测量代码执行时间,帮助分析和优化代码。这组计时API可能使用与默认内核定时器不同的定时器,其使用的定时器由架构、SoC 或板配置指定。
API 链接到标题
计时API定义在zephyr/include/zephyr/timing/timing.h
中,只有在CONFIG_TIMING_FUNCTIONS=y
的情况下这些API才会加入构建。
计时系统中所有的时间描述都是使用timing_t
,是一个64位无符号数
typedef uint64_t timing_t;
//初始化计时子系统
void timing_init(void);
//计时系统开始计时
void timing_start(void);
//计时系统停止计时
void timing_stop(void);
//返回计时数,单位为cycle
static inline timing_t timing_counter_get(void);
//计算start到end之间的计时数
static inline uint64_t timing_cycles_get(volatile timing_t *const start,
volatile timing_t *const end);
//获取所用计数器的频率,单位Hz
static inline uint64_t timing_freq_get(void);
//将 cycles 数转换为纳秒
static inline uint64_t timing_cycles_to_ns(uint64_t cycles);
//通过平均将 cycles 数转换为纳秒
static inline uint64_t timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count);
//获取所用计数器的频率(以 MHz 为单位)。
static inline uint32_t timing_freq_get_mhz(void);
使用示例
#include <zephyr/timing/timing.h>
void gather_timing(void)
{
timing_t start_time, end_time;
uint64_t total_cycles;
uint64_t total_ns;
//初始化并启动计时系统
timing_init();
timing_start();
//获取起点时间
start_time = timing_counter_get();
code_execution_to_be_measured();
//获取终点时间
end_time = timing_counter_get();
//计算代码执行的时间
total_cycles = timing_cycles_get(&start_time, &end_time);
total_ns = timing_cycles_to_ns(total_cycles);
//停止计时器
timing_stop();
}
实现 链接到标题
初始化,启动和停止实现在zephyr/subsys/timing/timing.c
和zephyr/include/zephyr/timing/timing.h
中,基本的形式如下
<ret> timing_<function>(<param list>)
{
if (has_inited) {
return;
}
#if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS)
board_timing_<function>();
#elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS)
soc_timing_<function>();
#else
arch_timing_<function>();
#endif
}
例如初始化就是
void timing_init(void)
{
if (has_inited) {
return;
}
#if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS)
board_timing_init();
#elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS)
soc_timing_init();
#else
arch_timing_init();
#endif
has_inited = true;
}
获取count就是
static inline timing_t timing_counter_get(void)
{
#if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS)
return board_timing_counter_get();
#elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS)
return soc_timing_counter_get();
#else
return arch_timing_counter_get();
#endif
}
从这里的实现可以看到计时函数的实现有board, soc, arch三个层级,当CONFIG_BOARD_HAS_TIMING_FUNCTIONS=y
时会使用board内实现的一组计时函数:
void board_timing_init(void);
void board_timing_start(void);
void board_timing_stop(void);
timing_t board_timing_counter_get(void);
uint64_t board_timing_cycles_get(volatile timing_t *const start,
volatile timing_t *const end);
uint64_t board_timing_freq_get(void);
uint64_t board_timing_cycles_to_ns(uint64_t cycles);
uint64_t board_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count);
uint32_t board_timing_freq_get_mhz(void);
当CONFIG_SOC_HAS_TIMING_FUNCTIONS=y
时会使用soc内实现的一组计时函数:
void soc_timing_init(void);
void soc_timing_start(void);
void soc_timing_stop(void);
timing_t soc_timing_counter_get(void);
uint64_t soc_timing_cycles_get(volatile timing_t *const start,
volatile timing_t *const end);
uint64_t soc_timing_freq_get(void);
uint64_t soc_timing_cycles_to_ns(uint64_t cycles);
uint64_t soc_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count);
uint32_t soc_timing_freq_get_mhz(void);
board的实现优先于soc,只有当board和soc都未实现时才会使用arch实现的计时函数. Zephyr允许针对不同的arch,soc,board使用不同的硬件定时器,这也导致会有不同的硬件实现,在v3.4.0版本下,下列soc有实现soc层级的计时函数 ./soc/arm/microchip_mec/mec1501/timing.c ./soc/arm/microchip_mec/mec172x/timing.c ./soc/arm/nordic_nrf/timing.c
下列arch有实现arch层级的计时函数 ./arch/arm/core/aarch32/cortex_m/timing.c ./arch/nios2/core/timing.c ./arch/x86/timing.c ./arch/xtensa/core/timing.c
如果没有特定层级的计时函数实现,那么将使用公共的arch计时函数实现./arch/common/timing.c
, 该实现将Zephyr内核使用的系统计时器,也就会直接包装k_cycle_get_32
等函数,细节比较简单这里不做分析,参考源文件即可。
参考 链接到标题
https://docs.zephyrproject.org/3.4.0/kernel/timing_functions/index.html