3、CPU压力测试:满负荷运算测试、多任务并发测试、中断风暴测试

CPU压力测试,说白了就是要把处理器往死里整。你得看看它在极限状态下会不会崩,会不会偷偷降频,会不会莫名其妙死机。我做了这么多年嵌入式,见过太多“平时跑得好好的,一上量就翻车”的案例了。今天咱们就把CPU压力测试的三个核心维度掰开揉碎讲清楚。

3.1 满负荷运算测试

满负荷运算测试,就是让CPU核心以100%的占用率持续运行。目的是什么?验证散热设计是否到位,电源供电是否扛得住,以及芯片本身有没有体质缺陷。

我个人习惯用两种方式来做:

  • 纯整数运算:比如循环做加法、乘法,或者跑一些经典的算法如FFT、矩阵乘法。
  • 浮点运算:这个更狠,因为浮点单元(FPU)功耗大、发热猛,很多芯片的短板就在这里暴露。

下面是一个简单的满负荷测试代码片段,适用于ARM Cortex-M系列:

// 满负荷整数运算测试
void cpu_stress_test(void) {
    volatile uint32_t a = 0x12345678;
    volatile uint32_t b = 0x87654321;
    volatile uint32_t result = 0;
    
    while(1) {
        // 大量乘加运算,让ALU满负荷
        for(int i = 0; i < 10000; i++) {
            result = a * b + result;
            result = result ^ a;
            result = result << 3;
        }
        // 加个看门狗喂食,防止测试过程中复位
        watchdog_feed();
    }
}

⚠️ 注意:满负荷测试时,一定要监控芯片温度。我曾经在一个项目中,没加散热片就跑这个测试,结果芯片温度飙到110°C,直接触发热关断。嗯,那次差点把板子烧了。

测试时长建议:至少跑30分钟。如果条件允许,跑2小时以上更稳妥。为什么?因为热积累需要时间,有些芯片前10分钟没事,20分钟后就开始降频了。

3.2 多任务并发测试

满负荷测试测的是单核极限,但现实中的嵌入式系统往往是多任务的。你想想看,一个设备既要采集传感器数据,又要处理网络通信,还得刷新UI界面。这时候,多任务并发能力就成了关键。

多任务并发测试的核心思路:

  • 创建多个高优先级任务,让它们同时抢占CPU资源。
  • 任务之间要有数据交互,比如通过队列、信号量、共享内存。
  • 观察系统是否出现死锁、优先级反转、任务饿死等问题。

我常用的测试框架是这样的:

// 多任务并发测试 - 基于FreeRTOS
void task_high_priority(void *pvParameters) {
    while(1) {
        // 高优先级任务:密集计算
        for(int i = 0; i < 5000; i++) {
            compute_heavy_math();
        }
        vTaskDelay(pdMS_TO_TICKS(10)); // 主动让出CPU
    }
}

void task_medium_priority(void *pvParameters) {
    while(1) {
        // 中优先级任务:模拟外设通信
        simulate_uart_transfer();
        vTaskDelay(pdMS_TO_TICKS(5));
    }
}

void task_low_priority(void *pvParameters) {
    while(1) {
        // 低优先级任务:后台日志记录
        log_system_status();
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

// 创建任务时,故意让优先级设置不合理,测试调度器是否健壮
xTaskCreate(task_high_priority, "High", 256, NULL, 3, NULL);
xTaskCreate(task_medium_priority, "Med", 256, NULL, 2, NULL);
xTaskCreate(task_low_priority, "Low", 256, NULL, 1, NULL);

💡 我的经验:多任务测试时,别忘了检查堆栈溢出。我曾经遇到一个bug,某个任务堆栈只分配了128字节,结果一跑并发就栈溢出,系统随机死机。排查了整整两天才找到原因。从那以后,我每个任务都至少分配256字节起步。

测试过程中要记录的数据:

监控指标 正常范围 异常表现
任务切换时间 < 10μs 切换时间突然增大,说明调度器卡顿
任务响应延迟 < 1ms 高优先级任务响应延迟超过5ms,说明优先级反转
CPU占用率 80%-95% 占用率突然降到0%,可能系统死锁
堆栈使用率 < 80% 超过90%就有溢出风险

3.3 中断风暴测试

中断风暴测试,是CPU压力测试里最刺激的一个环节。说白了,就是模拟极端情况下,中断以极高的频率不断触发,看看系统能不能扛得住。

为什么会发生中断风暴?

  • 外设故障,比如一个传感器不停地发中断信号。
  • 软件bug,比如中断标志位没有清除,导致中断反复触发。
  • 外部干扰,比如强电磁环境下GPIO引脚产生毛刺。

我常用的中断风暴测试方法:

// 中断风暴测试 - 使用定时器产生高频中断
void timer_interrupt_handler(void) {
    // 清除中断标志
    TIM->SR = ~TIM_SR_UIF;
    
    // 模拟中断处理:做少量工作
    volatile uint32_t temp = 0;
    for(int i = 0; i < 10; i++) {
        temp += i;
    }
    
    // 记录中断次数
    interrupt_count++;
}

void start_storm_test(void) {
    // 设置定时器频率为 100kHz,即每10μs触发一次中断
    TIM->PSC = 72 - 1;  // 72MHz时钟,预分频后为1MHz
    TIM->ARR = 10 - 1;   // 自动重装值,产生100kHz中断
    TIM->DIER |= TIM_DIER_UIE; // 使能更新中断
    TIM->CR1 |= TIM_CR1_CEN;  // 启动定时器
}

🔑 关键点:中断风暴测试要关注三个指标:

  1. 中断响应时间:从中断触发到进入ISR的时间,不能超过系统要求。
  2. 中断处理时间:ISR内部执行时间,必须小于中断间隔,否则会丢失中断。
  3. 中断嵌套深度:如果支持中断嵌套,要测试最深能嵌套几层而不崩。

我记得有一次做工业控制项目,现场设备频繁死机。排查后发现是一个外部中断引脚没做硬件滤波,电机启动时的电磁干扰导致中断风暴。嗯,从那以后,我所有中断引脚都加上了RC滤波,软件里也做了去抖处理。

避坑指南:

  • 我曾经在中断服务函数里调用了printf,结果一跑中断风暴,系统直接卡死。因为printf本身是阻塞的,而且可能触发其他中断。记住:ISR里尽量只做标志位操作,复杂逻辑放到任务里处理。
  • 我曾经遇到一个芯片,中断风暴时居然把Flash里的代码都冲坏了。后来发现是电源纹波太大,导致Flash读取错误。所以,做中断风暴测试时,一定要同时监控电源质量。

最后总结一下:CPU压力测试不是走过场,它是检验系统稳定性的试金石。满负荷测试看散热和供电,多任务测试看调度和资源管理,中断风暴测试看实时性和鲁棒性。这三个维度都过了,你的系统才算真正经得起考验。