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.czephyr/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