2. 任务切换时间测量
任务目标
在VxWorks中,任务切换时间直接反映系统实时性。本案例使用系统高精度计时器clock_gettime()测量两个不同优先级任务交替唤醒时的上下文切换开销,并给出可重复的测量方法与判定标准。
测量原理
任务A记录当前时间t1后释放信号量并阻塞;任务B获取信号量后立即记录时间t2。t2 - t1即为一次从A切换到B的完整开销(含调度器决策与上下文恢复)。交替测量多次取平均值,可消除单次抖动。
完整实现代码
/* task_switch_measure.c */
#include <vxWorks.h>
#include <taskLib.h>
#include <semLib.h>
#include <time.h>
#include <stdio.h>
#define MEASURE_COUNT 1000
static SEM_ID semSwitch;
static struct timespec tA, tB;
static volatile int switchCount = 0;
static double totalNsec = 0.0;
/* 高优先级任务:记录时间并释放信号量 */
static void highPrioTask(void)
{
while (switchCount < MEASURE_COUNT) {
clock_gettime(CLOCK_MONOTONIC, &tA);
semGive(semSwitch); /* 唤醒低优先级任务 */
taskDelay(0); /* 主动让出CPU,触发切换 */
}
}
/* 低优先级任务:记录接收时间,计算差值 */
static void lowPrioTask(void)
{
while (switchCount < MEASURE_COUNT) {
semTake(semSwitch, WAIT_FOREVER);
clock_gettime(CLOCK_MONOTONIC, &tB);
double diff = (double)(tB.tv_sec - tA.tv_sec) * 1e9 +
(double)(tB.tv_nsec - tA.tv_nsec);
totalNsec += diff;
switchCount++;
}
}
void measureTaskSwitch(void)
{
semSwitch = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);
if (semSwitch == NULL) {
printf("Semaphore creation failed\n");
return;
}
/* 创建低优先级任务(优先级100),先就绪但不运行 */
taskSpawn("tLow", 100, 0, 0x2000, (FUNCPTR)lowPrioTask, 0,0,0,0,0,0,0,0,0,0);
taskDelay(1); /* 确保低优先级任务已阻塞在semTake上 */
/* 创建高优先级任务(优先级50),开始测量 */
taskSpawn("tHigh", 50, 0, 0x2000, (FUNCPTR)highPrioTask, 0,0,0,0,0,0,0,0,0,0);
/* 等待测量完成 */
while (switchCount < MEASURE_COUNT)
taskDelay(1);
double avgNsec = totalNsec / MEASURE_COUNT;
printf("Task switch time: %.2f ns (avg of %d switches)\n",
avgNsec, MEASURE_COUNT);
}
运行与验证
- 将代码编译为可下载模块,在VxWorks shell中加载。
- 调用
measureTaskSwitch()启动测量。 - 观察串口输出,应显示类似:
Task switch time: 1850.00 ns (avg of 1000 switches)
(具体数值取决于CPU型号、主频与VxWorks配置)
判定通过条件:程序正常返回且打印平均切换时间;连续运行两次结果偏差小于20%,说明测量稳定。若输出为0或极大值,检查CLOCK_MONOTONIC是否被BSP支持(可用clock_getres()确认分辨率)。
关键说明
- 高优先级任务通过
taskDelay(0)让出CPU,触发调度器切换到已就绪的低优先级任务,这是测量切换的必要条件。 - 信号量采用优先级排队(
SEM_Q_PRIORITY),确保低优先级任务先阻塞等待,避免优先级反转影响测量。 - 测量值包含信号量give/take操作开销,但该开销为固定常数,不影响相对比较——如需纯切换开销,可先测量空信号量操作耗时并扣除。
- 若需分析不同优先级差的影响,可修改
taskSpawn中的优先级参数(如将高优先级改为60、70)重新测量对比。