Measuring Real-Time Performance with VxWorks

Introduction

This article will demonstrate how to measure and visualize the real-time performance of VxWorks, explain why these measurements are important, and guide you in reproducing these tests. You will gain:

  • • A brief explanation of why real-time performance is critical.
  • • A reproducible test toolkit (VxWorks C language test program) to measure:
    • • Interrupt latency
    • • Context switch time
    • • Timer precision
  • • A Python plotting script that converts console logs into histograms and time series plots.
  • • Step-by-step instructions for running similar tests on Linux (with/without PREEMPT-RT) and FreeRTOS.
  • • Example/representative results and charts that can be used for publication in your experiments.

Why Real-Time Performance is Critical

  • • In hard real-time systems, missing deadlines can lead to system failure. Key metrics include:
    • • Interrupt latency — the time from when an event occurs to when the interrupt service routine (ISR) begins execution.
    • • Context switch time — the time required to switch execution between tasks.
    • • Timer precision — the accuracy of periodic tasks.
  • • A true RTOS (like VxWorks) provides deterministic behavior with low jitter, which is crucial for avionics, industrial control, robotics, and other safety-critical areas.

Recommended Test Hardware and Software

  • • Hardware target: modern embedded CPU or x86 target (e.g., Intel Core i7 development board).
  • • VxWorks: VxWorks 7 (supports timestamp/timer API).
  • • Host tools: Wind River Workbench (build and console), Python 3 and matplotlib on the host PC.
  • • Optional: logic analyzer/oscilloscope for hardware-level precise interrupt timing.

VxWorks Real-Time Performance Test Toolkit

  1. 1. VxWorks C language test program (save as performanceTest.c)

This program demonstrates interrupt latency, semaphore-based context switch testing, and periodic timer callbacks for measuring timer precision.

/* performanceTest.c
   Compile and link in the VxWorks build system. Adjust interrupt vectors and
   timestamp API as needed for your BSP.
*/
#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 for latency measurement */
void latencyISR(void)
{
    irqEndTime = vxTimestamp();
    irqTriggered = TRUE;
}

/* Interrupt latency test */
void testInterruptLatency(void)
{
    UINT32 freq = sysTimestampFreq();
    irqTriggered = FALSE;

    /* Replace 0x60 with the vector suitable for your BSP, or use
       a hardware timer to trigger an external interrupt.*/
    intConnect(INUM_TO_IVEC(0x60), (VOIDFUNCPTR)latencyISR, 0);
    intEnable(0x60);

    irqStartTime = vxTimestamp();
    /* Trigger interrupt in BSP specific way; sysIntGen is just an example */
    sysIntGen(0x60);

    while (!irqTriggered) taskDelay(1);

    double latency_us = ((double)(irqEndTime - irqStartTime) / freq) * 1e6;
    printf("Interrupt Latency: %.2f microseconds\n", latency_us);
}

/* Context switch task */
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);
    }
}

/* Timer callback for measuring period */
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 millisecond
    ts.it_interval = ts.it_value;

    timer_settime(tid, 0, &ts, NULL);
}

/* Entry: run tests */
void vxworksPerformanceTest(void)
{
    if (vxTimestampEnable() != OK)
    {
        printf("This platform does not support timestamps\n");
        return;
    }

    printf("VxWorks Real-Time Performance Test\n");

    /* 1) Interrupt latency (single shot)*/
    testInterruptLatency();

    /* 2) Context switch test */
    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) Timer precision: periodic print */
    testTimerPrecision();
}
  1. 2. Python plotting script (plot_vxworks_performance.py)

Copy the VxWorks console output to vxworks_performance.log. Then run this script on your host to generate histograms and timer precision plots.

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("Interrupt Latency Distribution")
plt.xlabel("Latency (microseconds)")
plt.ylabel("Frequency")
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("Context Switch Time Distribution")
plt.xlabel("Time (microseconds)")
plt.ylabel("Frequency")
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("Timer Period Precision (Target 1 millisecond)")
plt.xlabel("Sample Number")
plt.ylabel("Period (microseconds)")
plt.grid(True, linestyle="--", alpha=0.6)
plt.savefig("timer_period_plot.png", dpi=300)
plt.close()

print("Plots saved.")

Comparison with Linux and FreeRTOS

Linux (without RT patch)

Install <span>rt-tests</span> and use <span>cyclictest</span>:

sudo apt install rt-tests
sudo cyclictest -t1 -p99 -n -i1000 -l10000
  • • Peaks are expected occasionally (50–200 microseconds or more under heavy load).

Linux (PREEMPT-RT)

Boot the <span>PREEMPT-RT</span> kernel and run <span>cyclictest</span> again.

  • • Typical improvement: 10–20 microseconds range, but jitter is still higher than hard real-time operating systems.

FreeRTOS

On bare-metal MCU, re-implement semaphore/ISR tests:

  • • Use hardware microsecond timer.
  • • Use <span>xSemaphoreTake/xSemaphoreGive</span> for context switch timing.
  • • Typical FreeRTOS data varies with MCU clock — usually in the microsecond range, but more unstable under load.

Representative Results

These are representative/sample data used in the example figures and tables, intended to help readers compare different systems. Actual data largely depends on hardware, BSP, and system load.

Operating System Average Interrupt Latency Maximum Jitter Average Context Switch Time
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

Visualization

I generated two plots for comparison based on representative/simulated datasets:

  • • Interrupt Latency Histogram
    Measuring Real-Time Performance with VxWorks
    Interrupt Latency Histogram
  • • Latency and Jitter Boxplot
    Measuring Real-Time Performance with VxWorks
    Latency & Jitter Boxplot

If you want a dataset that accurately reflects your hardware, run the VxWorks tests, save vxworks_performance.log, and then rerun the above Python plotting script.

Tips and Best Practices for Reproducible Results

  • • Run tests on an idle system to obtain baseline data; then repeat tests under controlled load to demonstrate robustness.
  • • Use hardware triggers + logic analyzers for the most accurate interrupt timing.
  • • Ensure timestamps use high-resolution hardware timers (vxTimestamp() on VxWorks).
  • • Record the exact BSP, CPU model, kernel/firmware version, and compilation flags — these details are important.

Conclusion

This combined toolkit (VxWorks C language tests + Python plotter + comparison guide) provides you with everything needed to measure and publish credible real-time performance results. The generated charts can easily showcase VxWorks’ comparison in latency and jitter against Linux and FreeRTOS.

Click “Read Original” for more VxWorks articles

Leave a Comment