APIC – Getting start - (Advanced Concepts)

Sim Engine – Getting Started Advanced Concepts Guide

CPU Affinity

CPU affinity determines which physical CPU core(s) the Sim Engine is allowed to run on. Real-time applications use affinity to avoid context switching and prevent the OS from moving the thread between cores.

Why CPU Pinning Matters

Recommended Setup

For high-performance simulations:

Windows

Set the simulation loop thread to:

Linux

Use low latency or RT kernel

Pin using sched_setaffinity() and set a real-time scheduling policy like SCHED_FIFO.

Dedicated Core Strategy

Ideal setup for a 4-core CPU:

Core Role
0 OS services (avoid)
1 User applications
2 Simulation loop (pinned)
3 Recording / async tasks

This eliminates interference and minimizes jitter.

Real-Time OS Tuning

Real-time performance can be heavily improved by tuning the OS behavior.

Windows Tuning

Enable HPET/Disable HPET (depending on your CPU)

Different CPUs benefit from different timer modes. Always benchmark:

Use MMCSS for soft real-time

Use the Multimedia Class Scheduler Service to achieve lower jitter:

Disable core parking

Prevents Windows from migrating your thread to a waking core.

Disable dynamic frequency scaling

Use High Performance power plan. Enable 100% minimum CPU frequency.

Linux Tuning

Use PREEMPT_RT kernel

This gives OS-level deterministic execution.

Disable power-saving features

Disable:

bash
    sudo cpupower frequency-set -g performance
            
Disable IRQs on your dedicated core

Offload interrupts to non-critical cores:

bash
    /proc/irq/*/smp_affinity
            
Isolate the core

Boot parameters:

ini file
    isolcpus=2 nohz_full=2 rcu_nocbs=2
            
Lock memory

Avoid page faults:

CPP
    mlockall(MCL_CURRENT | MCL_FUTURE);
            

These strategies together dramatically reduce jitter and increase determinism.

Lockless Pipeline

A lockless design minimizes thread stalls and avoids unpredictable mutex behavior.

Why lockless?

Common Lockless Patterns

Sim Engine Recording Example

The optimal recording pipeline is:

JAVA
Frame Loop (Producer)
   → Lockless ring buffer
        → Recording Thread (Consumer)
            

Producer writes one frame worth of data at a time. Consumer flushes data whenever possible.

Double Buffer Technique

Use two buffers:

Every frame, swap pointers atomically:

CPP
    if (!busy.load()) {
        swapBuffers();
        busy.store(true);
    }
            

Zero locks. Zero stalls.

Memory Management Rules

Real-time systems must avoid operations that can cause unpredictable delays.

DO NOT inside the real-time loop:

DO outside or before the loop:

Memory Locking

Lock all pages:

CPP
    mlockall(MCL_CURRENT | MCL_FUTURE);
            

Prevents the OS from paging anything to disk.

Multi-Rate Scheduling

Not all tasks need to run at the main frame rate. The Sim Engine can support tasks running at:

How Multi-Rate Scheduling Works

At each frame:

CPP
    if (frameId % 10 == 0)
        run_100Hz_task();
    if (frameId % 2 == 0)
        run_500Hz_task();
    run_1000Hz_task(); // always runs
            

Use Cases

Design Strategy

Simulation Determinism Theory

Simulation determinism means:
The same input sequence produces the same outputs every time.

In a real-time engine, determinism depends on:

Fixed time steps

No variable dt (delta time). All updates run at constant time intervals.

Deterministic execution order

All tasks must run in the same order every frame.

No race conditions

Avoid shared mutable state between threads unless lockless or protected.

No nondeterministic sources

Consistent floating-point behavior

Avoid hardware-dependent behavior