引言 #
本文将展示如何测量和可视化 VxWorks 的实时性能,解释这些测量数据为何重要,并引导您重现这些测试。您将获得:
- 为什么实时性能至关重要的简短解释。
- 一个可重现的测试工具包(VxWorks C 语言测试程序)来测量:
- 中断延迟(Interrupt latency)
- 上下文切换时间(Context switch time)
- 定时器精度(Timer precision)
- 一个 Python 绘图脚本,将控制台日志转换为直方图和时序图。
- 在 Linux(带/不带 PREEMPT-RT)和 FreeRTOS 上运行类似测试的分步说明。
- 示例/代表性结果和可用于发表的图表,供您的实验使用。
为什么实时性能至关重要 #
- 在硬实时系统中,错过最后期限可能导致系统故障。关键指标包括:
- 中断延迟 — 从事件发生到中断服务程序(ISR)开始执行的时间。
- 上下文切换时间 — 在任务之间切换执行所需的时间。
- 定时器精度 — 周期性任务的准确性。
- 真正的 RTOS(如 VxWorks)提供具有低抖动(low jitter)的确定性行为,这对于航空电子、工业控制、机器人技术及其他安全关键领域至关重要。
测试硬件与软件(推荐) #
- 硬件目标:现代嵌入式 CPU 或 x86 目标(例如:Intel Core i7 级开发板)。
- VxWorks:VxWorks 7(支持时间戳/定时器 API)。
- 主机工具:Wind River Workbench(构建和控制台)、主机 PC 上的 Python 3 及 matplotlib。
- 可选:用于硬件级精确中断计时的逻辑分析仪 / 示波器。
VxWorks 实时性能测试工具包 #
- VxWorks C 语言测试程序(保存为 performanceTest.c)
该程序演示了中断延迟、基于信号量的上下文切换测试以及用于测量定时器精度的周期性定时器回调。
/* performanceTest.c
在 VxWorks 构建系统中编译和链接。如果需要,请根据您的 BSP 调整中断向量和
时间戳 API。
*/
#include <vxWorks.h>
#include <taskLib.h>
#include <semLib.h>
#include <intLib.h>
#include <sysLib.h>
#include <tickLib.h>
#include <timers.h>
#include <stdio.h>
#include <time.h>
#include <drv/timer/timestampDev.h>
SEM_ID sem1, sem2;
volatile UINT64 irqStartTime, irqEndTime;
volatile BOOL irqTriggered = FALSE;
/* 用于延迟测量的 ISR */
void latencyISR(void)
{
irqEndTime = vxTimestamp();
irqTriggered = TRUE;
}
/* 中断延迟测试 */
void testInterruptLatency(void)
{
UINT32 freq = sysTimestampFreq();
irqTriggered = FALSE;
/* 将 0x60 替换为适合您 BSP 的向量,或使用
硬件定时器触发外部中断。*/
intConnect(INUM_TO_IVEC(0x60), (VOIDFUNCPTR)latencyISR, 0);
intEnable(0x60);
irqStartTime = vxTimestamp();
/* 以 BSP 特定的方式触发中断;sysIntGen 仅为示例 */
sysIntGen(0x60);
while (!irqTriggered) taskDelay(1);
double latency_us = ((double)(irqEndTime - irqStartTime) / freq) * 1e6;
printf("Interrupt Latency: %.2f microseconds\n", latency_us);
}
/* 上下文切换任务 */
void highPriorityTask(void)
{
while (1)
{
semTake(sem1, WAIT_FOREVER);
UINT64 t1 = vxTimestamp();
semGive(sem2);
double switchTime = ((double)(vxTimestamp() - t1) / sysTimestampFreq()) * 1e6;
printf("Context Switch Time: %.2f microseconds\n", switchTime);
}
}
void lowPriorityTask(void)
{
while (1)
{
semGive(sem1);
semTake(sem2, WAIT_FOREVER);
}
}
/* 测量周期的定时器回调 */
void timerCallback(timer_t timerId, int arg)
{
static UINT64 lastTime = 0;
UINT64 now = vxTimestamp();
if (lastTime != 0)
{
double period_us = ((double)(now - lastTime) / sysTimestampFreq()) * 1e6;
printf("Timer Period: %.2f microseconds\n", period_us);
}
lastTime = now;
}
void testTimerPrecision(void)
{
struct sigevent evp;
timer_t tid;
struct itimerspec ts;
evp.sigev_notify = SIGEV_THREAD;
evp.sigev_value.sival_int = 0;
evp.sigev_notify_function = (void (*)(union sigval))timerCallback;
evp.sigev_notify_attributes = NULL;
timer_create(CLOCK_REALTIME, &evp, &tid);
ts.it_value.tv_sec = 0;
ts.it_value.tv_nsec = 1000000; // 1 毫秒
ts.it_interval = ts.it_value;
timer_settime(tid, 0, &ts, NULL);
}
/* 入口:运行测试 */
void vxworksPerformanceTest(void)
{
if (vxTimestampEnable() != OK)
{
printf("此平台不支持时间戳\n");
return;
}
printf("VxWorks 实时性能测试\n");
/* 1) 中断延迟(单次)*/
testInterruptLatency();
/* 2) 上下文切换测试 */
sem1 = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);
sem2 = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);
taskSpawn("tHigh", 100, 0, 4096, (FUNCPTR)highPriorityTask, 0,0,0,0,0,0,0,0,0,0);
taskSpawn("tLow", 101, 0, 4096, (FUNCPTR)lowPriorityTask, 0,0,0,0,0,0,0,0,0,0);
/* 3) 定时器精度:周期性打印 */
testTimerPrecision();
}
- Python 绘图脚本 (plot_vxworks_performance.py)
将 VxWorks 控制台输出复制到 vxworks_performance.log。然后在您的主机上运行此脚本,以生成直方图和定时器精度图。
import re
import matplotlib.pyplot as plt
LOG_FILE = "vxworks_performance.log"
interrupt_latencies = []
context_switch_times = []
timer_periods = []
re_interrupt = re.compile(r"Interrupt Latency:\s*([\d.]+)\s*microseconds")
re_context = re.compile(r"Context Switch Time:\s*([\d.]+)\s*microseconds")
re_timer = re.compile(r"Timer Period:\s*([\d.]+)\s*microseconds")
with open(LOG_FILE, "r") as f:
for line in f:
if m := re_interrupt.search(line):
interrupt_latencies.append(float(m.group(1)))
elif m := re_context.search(line):
context_switch_times.append(float(m.group(1)))
elif m := re_timer.search(line):
timer_periods.append(float(m.group(1)))
plt.figure(figsize=(8, 5))
plt.hist(interrupt_latencies, bins=20)
plt.title("中断延迟分布")
plt.xlabel("延迟 (微秒)")
plt.ylabel("频率")
plt.grid(True, linestyle="--", alpha=0.6)
plt.savefig("interrupt_latency_histogram.png", dpi=300)
plt.close()
plt.figure(figsize=(8, 5))
plt.hist(context_switch_times, bins=20)
plt.title("上下文切换时间分布")
plt.xlabel("时间 (微秒)")
plt.ylabel("频率")
plt.grid(True, linestyle="--", alpha=0.6)
plt.savefig("context_switch_histogram.png", dpi=300)
plt.close()
plt.figure(figsize=(8, 5))
plt.plot(timer_periods, marker='o', markersize=3, linewidth=1)
plt.title("定时器周期精度(目标 1 毫秒)")
plt.xlabel("样本编号")
plt.ylabel("周期 (微秒)")
plt.grid(True, linestyle="--", alpha=0.6)
plt.savefig("timer_period_plot.png", dpi=300)
plt.close()
print("绘图已保存。")
与 Linux 和 FreeRTOS 的比较
Linux (无 RT 补丁)
安装 rt-tests
并使用 cyclictest
:
sudo apt install rt-tests
sudo cyclictest -t1 -p99 -n -i1000 -l10000
- 预期偶尔会出现峰值(在重负载下为 50–200 微秒或更大)。
Linux (PREEMPT-RT)
启动 PREEMPT-RT
内核并再次运行 cyclictest
。
- 典型的改进:10–20 微秒范围,但抖动仍高于硬实时操作系统。
FreeRTOS
在裸机 MCU 上,重新实现信号量 / ISR 测试:
- 使用硬件微秒定时器。
- 使用
xSemaphoreTake/xSemaphoreGive
进行上下文切换计时。 - 典型的 FreeRTOS 数据随 MCU 时钟而异 — 通常在几微秒范围内,但在负载下更不稳定。
代表性结果
这些是在示例图和表格中使用的代表性/样本数据,旨在帮助读者比较不同系统。实际数据很大程度上取决于硬件、BSP 和系统负载。
操作系统 | 平均中断延迟 | 最大抖动 | 平均上下文切换时间 |
---|---|---|---|
VxWorks | 1.3 µs | ±0.1 µs | 3.8 µs |
FreeRTOS | 2–5 µs | ±1 µs | 4–8 µs |
Linux (no RT) | 50–200 µs | ±100 µs | 5–20 µs |
Linux RT | 10–20 µs | ±5 µs | 5–10 µs |
可视化
我为比较生成的两张图(基于代表性/模拟数据集):
-
中断延迟直方图
-
延迟与抖动箱线图
如果您希望获得精确反映您硬件的数据集,请运行 VxWorks 测试,保存 vxworks_performance.log,然后重新运行上面的 Python 绘图脚本。
可重现结果的技巧和最佳实践 #
- 在空闲系统上运行测试以获取基准数据;然后,在受控负载下重复测试以显示鲁棒性。
- 使用硬件触发器 + 逻辑分析仪以获得最准确的中断计时。
- 确保时间戳使用高分辨率硬件定时器(VxWorks 上的 vxTimestamp())。
- 记录确切的 BSP、CPU 型号、内核/固件版本以及编译标志 — 这些细节很重要。
结论 #
这个组合工具包(VxWorks C 语言测试 + Python 绘图器 + 比较指南)为您提供了测量和发布可信实时性能结果所需的一切。生成的图表可以轻松展示 VxWorks 在延迟和抖动方面与 Linux 和 FreeRTOS 的比较。