news 2026/6/12 4:15:41

实用:嵌入式执行时间测量常用方法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
实用:嵌入式执行时间测量常用方法

一、常用方法

常用方法:

  • CPU 周期计数器
  • 片上定时器 / SysTick
  • GPIO 翻转 + 示波器 / 逻辑分析仪
  • RTOS Trace / 运行时间统计

1.1 CPU 周期计数器

CPU 周期计数器是内核自带的调试模块,每一个 CPU 周期自增 1,具有精度最高(纳秒级)、侵入性最小的优势,是函数级测量的首选方案。

工作原理

以 Cortex-M 系列内核为例,通过使能 DWT(Data Watchpoint and Trace)模块的 CYCCNT 计数器,记录代码执行前后的计数值,计算差值后除以 CPU 频率,即可得到执行时间。

例:

#include "core_cm4.h" // 初始化周期计数器 static inline void cycle_counter_init(void) { // 1. 使能DWT模块 if (!(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; } DWT->CYCCNT = 0; // 2. 清零计数器 DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; // 3. 开启计数 } // 获取当前周期计数值 static inline uint32_t cycle_counter_get(void) { return DWT->CYCCNT; } // 测量示例 void measure_function(void) { cycle_counter_init(); // 初始化(可全局执行一次) uint32_t start = cycle_counter_get(); // 被测代码块 foo(); bar(); uint32_t end = cycle_counter_get(); uint32_t delta_cycles = end - start; // 无符号溢出自动处理 float delta_us = (float)delta_cycles / (SystemCoreClock / 1000000); // 换算为微秒 printf("[PROF] 执行时间:%lu 周期 / %.2f us\r\n", delta_cycles, delta_us); }
适用场景
  • 微秒级甚至纳秒级的高精度测量;
  • 函数、中断服务程序等小粒度代码块;
  • 无 RTOS 的裸机环境或轻量 RTOS 环境。

1.2 片上定时器 / SysTick:工程折中方案

当芯片不支持 DWT 模块,或需要与 CPU 频率解耦的时间基准时,片上通用定时器是最常用的选择。通过配置定时器为自由运行模式,以固定频率计数,适合中粒度时间测量。

工作原理

配置定时器的预分频系数和自动重装载值,使其以已知频率(如 1MHz,即 1tick=1us)递增,测量前后读取计数器值,计算差值即为时间。

例:
#include "stm32f4xx_hal.h" static TIM_HandleTypeDef htim2; // 初始化定时器(1MHz计数,1tick=1us) void timer_profiling_init(void) { __HAL_RCC_TIM2_CLK_ENABLE(); htim2.Instance = TIM2; htim2.Init.Prescaler = 83; // APB1时钟84MHz,84MHz/(83+1)=1MHz htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 0xFFFFFFFF; // 32位计数,减少溢出 htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; HAL_TIM_Base_Init(&htim2); HAL_TIM_Base_Start(&htim2); // 自由运行模式启动 } // 获取当前计数值 static inline uint32_t timer_profiling_get_ticks(void) { return __HAL_TIM_GET_COUNTER(&htim2); } // 测量示例 void measure_task(void) { timer_profiling_init(); // 全局初始化一次 uint32_t start = timer_profiling_get_ticks(); // 被测代码块 task_run(); uint32_t end = timer_profiling_get_ticks(); // 处理计数器溢出 uint32_t delta_ticks = (end >= start) ? (end - start) : (0xFFFFFFFFu - start + 1u + end); float delta_us = (float)delta_ticks; // 1tick=1us printf("[PROF] 任务执行时间:%.2f us\r\n", delta_us); }
适用场景
  • 几十微秒到秒级的中粒度代码块;
  • 需与 CPU 频率解耦的测量场景;
  • 不支持 DWT 模块的芯片。

1.3 GPIO 翻转 + 示波器:最直观的可视化方案

这种方法原理简单但实用性极强,通过 GPIO 电平翻转标记测量起止,用示波器或逻辑分析仪测量脉宽,可避免软件测量的侵入性影响,误差极小。

工作原理
  • 测量开始前:将指定 GPIO 引脚拉高;
  • 测量结束后:将该 GPIO 引脚拉低;
  • 示波器测量高电平脉宽,即为代码执行时间。
例:
#include "stm32f4xx_hal.h" // 定义测量GPIO(需提前初始化为输出模式) #define PROF_GPIO_Port GPIOA #define PROF_Pin GPIO_PIN_0 // 测量宏定义 #define MEASURE_BEGIN() HAL_GPIO_WritePin(PROF_GPIO_Port, PROF_Pin, GPIO_PIN_SET) #define MEASURE_END() HAL_GPIO_WritePin(PROF_GPIO_Port, PROF_Pin, GPIO_PIN_RESET) // 测量示例 void process_data_measure(void) { MEASURE_BEGIN(); // 被测代码块 process_sensor_data(); update_control_output(); MEASURE_END(); }
适用场景
  • 调试阶段的直观验证;
  • 需排除软件测量干扰的场景;
  • 多信号时序对齐测量(如同步观察多个代码块执行时间)。

1.4 RTOS 运行时间统计:系统级瓶颈分析

在 RTOS 环境中,可通过系统自带的运行时间统计功能,获取各任务的 CPU 占用率,适合系统级性能优化和瓶颈定位。

工作原理(以 FreeRTOS 为例)
  • 启用统计功能后,FreeRTOS 通过高精度定时器维护每个任务的运行时间计数器;
  • 任务切换时,内核计算当前任务的运行时长并累加;
  • 通过 API 函数可获取各任务的运行时间占比,生成统计报表。

例:

#define configGENERATE_RUN_TIME_STATS 1 // 启用运行时间统计 #define configUSE_STATS_FORMATTING_FUNCTIONS 1 // 启用格式化输出函数 extern void vConfigureTimerForRunTimeStats(void); // 定时器初始化钩子 extern unsigned long ulGetRunTimeCounterValue(void); // 计数值获取钩子
  1. 实现钩子函数与定时器初始化:
// 定时器初始化(复用片上定时器方案) void vConfigureTimerForRunTimeStats(void) { timer_profiling_init(); // 1MHz计数,1tick=1us } // 获取当前计数值 unsigned long ulGetRunTimeCounterValue(void) { return (unsigned long)timer_profiling_get_ticks(); }
  1. 创建统计打印任务:
#define RUNTIME_STATS_BUF_LEN 256 void vTaskPrintStats(void *pvParameters) { char buf[RUNTIME_STATS_BUF_LEN]; for (;;) { vTaskDelay(pdMS_TO_TICKS(1000)); // 每秒打印一次 memset(buf, 0, RUNTIME_STATS_BUF_LEN); vTaskGetRunTimeStats(buf); // 生成统计报表 printf("===== 任务运行时间统计 =====\r\n%s\r\n", buf); } }
  1. 典型输出结果:
===== 任务运行时间统计 ===== Task Run Time Percentage ------------------------------------ ctrlTask 350000 35% commTask 250000 25% logTask 150000 15% idle 250000 25%
适用场景
  • 多任务 RTOS 系统的全局性能分析;
  • 定位 CPU 占用率过高的任务;
  • 系统架构优化与负载均衡调整。

二、方法选型指南

测量需求推荐方法优势局限性
函数 / 中断级、微秒级精度CPU 周期计数器(DWT)精度最高、侵入性最小依赖内核支持、需 CPU 频率稳定
任务级、10μs~ 秒级片上定时器 / SysTick实现简单、与 CPU 频率解耦精度中等、需处理计数器溢出
调试阶段、直观验证GPIO 翻转 + 示波器无软件干扰、可视化强需硬件工具、不适用于生产环境
系统级、任务占比分析RTOS 运行时间统计全局视角、定位系统瓶颈仅支持 RTOS、无法测量单个函数
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/11 17:09:30

Langchain-Chatchat开源协议解读:商业使用是否受限?

Langchain-Chatchat开源协议解读:商业使用是否受限? 在企业对数据隐私和合规性要求日益严苛的今天,如何在不牺牲安全的前提下引入大模型能力,成为许多组织面临的关键挑战。通用AI服务虽然强大,但其云端处理机制让金融、…

作者头像 李华
网站建设 2026/6/11 13:08:49

基于springboot的web图书借阅规划管理系统

博主介绍:java高级开发,从事互联网行业六年,熟悉各种主流语言,精通java、python、php、爬虫、web开发,已经做了多年的设计程序开发,开发过上千套设计程序,没有什么华丽的语言,只有实…

作者头像 李华
网站建设 2026/6/10 16:15:43

【探索实战】Kurator统一流量治理深度实践:基于Istio的跨集群服务网格

【探索实战】Kurator统一流量治理深度实践:基于Istio的跨集群服务网格 摘要 在微服务架构日益复杂的今天,跨集群、跨云的流量管理成为企业面临的重大挑战。本文深入探讨了Kurator如何基于Istio构建统一的服务网格,实现金丝雀发布、A/B测试、蓝…

作者头像 李华
网站建设 2026/6/10 17:14:05

Android AAR依赖合并工具完整使用指南

Android AAR依赖合并工具完整使用指南 【免费下载链接】android-fat-aar Gradle script that allows you to merge and embed dependencies in generted aar file 项目地址: https://gitcode.com/gh_mirrors/an/android-fat-aar 在现代Android开发中,模块化已…

作者头像 李华
网站建设 2026/6/10 12:03:59

Qwen3-8B-Base:32K上下文的多语言大模型

Qwen3-8B-Base作为Qwen系列最新一代大语言模型的基础版本,凭借32K超长上下文窗口和119种语言支持,重新定义了中端参数模型的性能边界。 【免费下载链接】Qwen3-8B-Base Qwen3-8B-Base具有以下特点: 类型:因果语言模型 训练阶段&am…

作者头像 李华
网站建设 2026/6/12 3:42:14

diffusers-cd_bedroom256_l2:卧室图像秒生成

diffusers-cd_bedroom256_l2:卧室图像秒生成 【免费下载链接】diffusers-cd_bedroom256_l2 项目地址: https://ai.gitcode.com/hf_mirrors/openai/diffusers-cd_bedroom256_l2 导语:OpenAI推出的diffusers-cd_bedroom256_l2模型,基于…

作者头像 李华