#include "performance_monitor.h" #include #include // 静态变量 static SystemPerfStats_t g_perf_stats = {0}; static uint32_t g_task_start_time[PERF_MON_MAX_TASKS] = {0}; static uint8_t g_task_active[PERF_MON_MAX_TASKS] = {0}; // 外部符号声明 (用于堆栈监控) extern uint32_t _estack; extern uint32_t _Min_Stack_Size; /** * @brief 初始化性能监控模块 * @param None * @retval None */ void PerformanceMonitor_Init(void) { memset(&g_perf_stats, 0, sizeof(SystemPerfStats_t)); memset(g_task_start_time, 0, sizeof(g_task_start_time)); memset(g_task_active, 0, sizeof(g_task_active)); g_perf_stats.sample_period_ms = PERF_MON_SAMPLE_PERIOD_MS; g_perf_stats.last_update_tick = HAL_GetTick(); // 初始化最小执行时间为最大值 for (int i = 0; i < PERF_MON_MAX_TASKS; i++) { g_perf_stats.tasks[i].min_time_us = UINT32_MAX; } } /** * @brief 开始任务性能监控 * @param task_id: 任务ID * @retval None */ void PerformanceMonitor_TaskStart(PerfTaskID_t task_id) { if (task_id >= PERF_MON_MAX_TASKS) return; g_task_start_time[task_id] = HAL_GetTick() * 1000; // 转换为微秒 g_task_active[task_id] = 1; } /** * @brief 结束任务性能监控 * @param task_id: 任务ID * @retval None */ void PerformanceMonitor_TaskEnd(PerfTaskID_t task_id) { if (task_id >= PERF_MON_MAX_TASKS || !g_task_active[task_id]) return; uint32_t end_time = HAL_GetTick() * 1000; // 转换为微秒 uint32_t execution_time = end_time - g_task_start_time[task_id]; TaskPerfStats_t *task_stats = &g_perf_stats.tasks[task_id]; // 更新统计信息 task_stats->total_time_us += execution_time; task_stats->call_count++; // 更新最大最小时间 if (execution_time > task_stats->max_time_us) { task_stats->max_time_us = execution_time; } if (execution_time < task_stats->min_time_us) { task_stats->min_time_us = execution_time; } // 计算平均时间 task_stats->avg_time_us = task_stats->total_time_us / task_stats->call_count; g_task_active[task_id] = 0; } /** * @brief 更新性能监控统计 * @param None * @retval None */ void PerformanceMonitor_Update(void) { uint32_t current_tick = HAL_GetTick(); // 检查是否到了更新周期 if (current_tick - g_perf_stats.last_update_tick < g_perf_stats.sample_period_ms) { return; } // 计算CPU使用率 uint32_t total_cpu_time = 0; for (int i = 0; i < PERF_MON_MAX_TASKS; i++) { if (g_perf_stats.tasks[i].call_count > 0) { // 计算每个任务的CPU使用率 uint32_t task_time_per_period = g_perf_stats.tasks[i].avg_time_us * (1000 / g_perf_stats.sample_period_ms); g_perf_stats.tasks[i].cpu_usage_percent = (float)task_time_per_period / 10000.0f; // 转换为百分比 total_cpu_time += task_time_per_period; } } // 更新总CPU使用率 g_perf_stats.total_cpu_usage_percent = total_cpu_time / 100; // 更新内存使用情况 g_perf_stats.free_heap_size = PerformanceMonitor_GetFreeHeapSize(); if (g_perf_stats.min_free_heap_size == 0 || g_perf_stats.free_heap_size < g_perf_stats.min_free_heap_size) { g_perf_stats.min_free_heap_size = g_perf_stats.free_heap_size; } // 更新栈使用率 g_perf_stats.stack_usage_percent = PerformanceMonitor_GetStackUsage(); g_perf_stats.last_update_tick = current_tick; } /** * @brief 获取性能统计信息 * @param stats: 统计信息结构体指针 * @retval None */ void PerformanceMonitor_GetStats(SystemPerfStats_t *stats) { if (stats != NULL) { memcpy(stats, &g_perf_stats, sizeof(SystemPerfStats_t)); } } /** * @brief 重置性能统计 * @param None * @retval None */ void PerformanceMonitor_ResetStats(void) { memset(&g_perf_stats, 0, sizeof(SystemPerfStats_t)); g_perf_stats.sample_period_ms = PERF_MON_SAMPLE_PERIOD_MS; g_perf_stats.last_update_tick = HAL_GetTick(); // 重新初始化最小执行时间 for (int i = 0; i < PERF_MON_MAX_TASKS; i++) { g_perf_stats.tasks[i].min_time_us = UINT32_MAX; } } /** * @brief 获取空闲堆内存大小 * @param None * @retval 空闲堆内存大小(字节) */ uint32_t PerformanceMonitor_GetFreeHeapSize(void) { // 简单的堆内存检测方法 // 在实际应用中,可能需要更复杂的内存管理 void *ptr = malloc(1); if (ptr != NULL) { free(ptr); // 这里返回一个估算值,实际项目中需要更精确的实现 return 32768; // 假设有32KB空闲堆内存 } return 0; } /** * @brief 获取栈使用率 * @param None * @retval 栈使用率百分比 */ uint32_t PerformanceMonitor_GetStackUsage(void) { // 获取当前栈指针 uint32_t current_sp; __asm volatile ("mov %0, sp" : "=r" (current_sp)); // 计算栈使用量 uint32_t stack_top = (uint32_t)&_estack; uint32_t min_stack_size = (uint32_t)&_Min_Stack_Size; uint32_t stack_used = stack_top - current_sp; // 计算使用率百分比 if (min_stack_size > 0) { return (stack_used * 100) / min_stack_size; } return 0; }