Skip to content

Add real-time scheduling helper functions and documentation#535

Open
srvald wants to merge 25 commits into
UniversalRobots:masterfrom
srvald:set_thread_priority_helper
Open

Add real-time scheduling helper functions and documentation#535
srvald wants to merge 25 commits into
UniversalRobots:masterfrom
srvald:set_thread_priority_helper

Conversation

@srvald

@srvald srvald commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR improves the real-time scheduling utilities in the client library and adds
documentation and examples for configuring scheduling priorities and CPU affinity
on both Linux and Windows.

Motivation

During internal tests on Windows, the RTDE example
rtde_client.cpp was executed while measuring cycle time and RTDE package parsing time.

Without any explicit CPU affinity or scheduling configuration, the application
showed higher scheduling jitter and less predictable execution timing.

After configuring CPU affinity and high-priority scheduling using the helper
functions introduced in this PR, both jitter and worst-case latency were
significantly reduced.

Before - Parse time After - Parse time
Before - Cycle time After - Cycle time

Timing measurements on Windows

Metric Before After Improvement
Parse time mean 9.85 µs 7.04 µs -28.5%
Parse time std dev 9.59 µs 2.32 µs -75.8%
Parse time P95 20 µs 12 µs -40.0%
Parse time P99 32 µs 15 µs -53.1%
Parse time max 4380 µs 155 µs -96.5%
Cycle time mean 1997.83 µs 1994.72 µs -0.2%
Cycle time std dev 721.54 µs 438.21 µs -39.3%
Cycle time P95 3028 µs 2732 µs -9.8%
Cycle time P99 3714 µs 3204 µs -13.7%
Cycle time max 231496 µs 50307 µs -78.3%

Key observations:

  • Parse time jitter was significantly reduced:

    • Standard deviation reduced by 75.8%
    • P99 reduced by 53.1%
    • Worst-case latency reduced from 4380 µs to 155 µs (96.5%)
  • Cycle time became more predictable:

    • Standard deviation reduced by 39.3%
    • P99 reduced by 13.7%
    • Worst-case latency reduced from 231496 µs to 50307 µs (78.3%)

While the average cycle time remained essentially unchanged (~2 ms), the reduction in jitter and worst-case latency improves timing predictability.

Changes

Helper functions

Added platform-specific helper functions for configuring execution priorities and
CPU affinities.

The helpers are not simple wrappers around the operating system APIs. Where
supported by the underlying platform, they:

  1. Apply the requested configuration.
  2. Retrieve the effective configuration from the operating system.
  3. Verify that the requested and applied values match.
  4. Log the resulting configuration.
  5. Report any mismatch or error condition.

The function returns true only when the requested configuration is successfully
applied and verified. Otherwise, it returns false.

Windows

Added wrappers for:

Additional improvements:

Linux

  • Added setThreadAffinity() (pthread_setaffinity_np)
  • Added affinity verification after applying the requested CPU set

Documentation

Added a new section to real_time.rst covering:

RTDE example

Updated the RTDE client example to demonstrate:

  • Process affinity configuration (Windows)
  • Thread affinity configuration
  • High-priority scheduling configuration
  • Cross-platform usage of the helper functions

Tests

Added unit tests covering:

  • Thread affinity helpers
  • Thread priority helpers
  • Process priority helpers
  • Process affinity helpers
  • FIFO scheduling helpers
  • Invalid handles
  • Invalid priorities
  • Invalid affinity masks

Example output

Successful configuration may produce logs similar to:

  • Windows
[INFO] Process affinity set to CPUs [6,7] (mask=0xC0)
[INFO] Thread affinity successfully set to CPUs [7] (mask=0x80)
[INFO] Process priority successfully set to REALTIME (0x100)
[INFO] Thread priority successfully set to TIME_CRITICAL (15)

If the application is executed without administrative privileges and attempts to
configure REALTIME_PRIORITY_CLASS, the following warning and verification
messages may be reported:

[INFO] Process affinity set to CPUs [6,7] (mask=0xC0)
[INFO] Thread affinity successfully set to CPUs [7] (mask=0x80)
[WARN] Process is not running with elevated privileges (UAC). REALTIME_PRIORITY_CLASS may fail. Try 'Run as Administrator'.
[INFO] Process priority successfully set to HIGH (0x80)
[WARN] Process priority mismatch. Expected REALTIME (0x100), got HIGH (0x80)
[ERROR] Unsuccessful in setting process to REALTIME_PRIORITY_CLASS
[ERROR] Failed to set FIFO scheduling

If an operation fails, the helper functions report both the operating system
error code and a readable error description:

[Error] Unsuccessful in setting process affinity to CPUs [] (mask=0x0). Error: 87 (The parameter is incorrect.)
  • Ubuntu
[INFO] Thread affinity successfully set to CPUs [7] 
[INFO] SCHED_FIFO OK, priority 99

Note

Medium Risk
Changes OS scheduling and affinity at runtime (including REALTIME_PRIORITY_CLASS on Windows), which can affect system responsiveness if misused; behavior is mostly additive with explicit failure paths and tests.

Overview
Adds verified CPU affinity and priority helpers for Linux and Windows, documents Windows soft real-time setup, and wires the RTDE example to use them before communication starts.

On Windows, new APIs wrap process/thread priority and affinity (setProcessPriority, setProcessAffinity, setThreadAffinity, setThreadPriority), plus pprocess_self(). Implementations read back OS state, log outcomes, restore priorities on mismatch, and warn when REALTIME_PRIORITY_CLASS is requested without elevation. setFiFoScheduling now promotes the process to REALTIME_PRIORITY_CLASS and sets the thread priority instead of only calling SetThreadPriority.

On Linux, setThreadAffinity is added with post-apply verification; existing setFiFoScheduling behavior is unchanged aside from living alongside the new helper.

examples/rtde_client.cpp pins CPUs (process mask on Windows, thread CPU 7 on Linux) and requests max FIFO scheduling at startup. doc/real_time.rst and doc/examples/rtde_client.rst describe helper usage and Microsoft soft-RT guidance. tests/test_helpers.cpp adds coverage for valid/invalid affinity and priority cases (Windows-only for process helpers).

Reviewed by Cursor Bugbot for commit 41f371c. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread src/helpers.cpp
Comment thread tests/test_helpers.cpp Outdated
@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 76.92308% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.09%. Comparing base (611f409) to head (41f371c).
⚠️ Report is 7 commits behind head on master.

Files with missing lines Patch % Lines
src/helpers.cpp 76.92% 3 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #535      +/-   ##
==========================================
+ Coverage   78.95%   79.09%   +0.14%     
==========================================
  Files         115      115              
  Lines        6766     6788      +22     
  Branches     2986     3004      +18     
==========================================
+ Hits         5342     5369      +27     
+ Misses       1052     1044       -8     
- Partials      372      375       +3     
Flag Coverage Δ
check_version_ur10-3.15.8 11.47% <0.00%> (-1.38%) ⬇️
check_version_ur10e-10.11.0 11.06% <0.00%> (-0.10%) ⬇️
check_version_ur10e-5.15.2 11.11% <0.00%> (-0.05%) ⬇️
check_version_ur12e-10.12.1 11.06% <0.00%> (-0.10%) ⬇️
check_version_ur12e-5.25.1 11.06% <0.00%> (-0.25%) ⬇️
check_version_ur15-10.12.1 11.06% <0.00%> (-0.05%) ⬇️
check_version_ur15-5.25.1 11.06% <0.00%> (-0.28%) ⬇️
check_version_ur16e-10.12.1 11.11% <0.00%> (-0.05%) ⬇️
check_version_ur16e-5.25.1 11.30% <0.00%> (+0.14%) ⬆️
check_version_ur18-10.12.1 11.06% <0.00%> (-0.10%) ⬇️
check_version_ur18-5.25.1 11.06% <0.00%> (-0.21%) ⬇️
check_version_ur20-10.12.1 11.06% <0.00%> (-0.10%) ⬇️
check_version_ur20-5.25.1 11.06% <0.00%> (-0.24%) ⬇️
check_version_ur3-3.14.3 11.25% <0.00%> (-1.46%) ⬇️
check_version_ur30-10.12.1 11.11% <0.00%> (-0.05%) ⬇️
check_version_ur30-5.25.1 11.11% <0.00%> (-0.28%) ⬇️
check_version_ur3e-10.11.0 11.06% <0.00%> (-0.10%) ⬇️
check_version_ur3e-5.9.4 11.06% <0.00%> (-1.03%) ⬇️
check_version_ur5-3.15.8 11.25% <0.00%> (-1.42%) ⬇️
check_version_ur5e-10.11.0 11.06% <0.00%> (-0.10%) ⬇️
check_version_ur5e-5.12.8 11.06% <0.00%> (-0.46%) ⬇️
check_version_ur7e-10.11.0 11.06% <0.00%> (-0.05%) ⬇️
check_version_ur7e-5.22.2 11.25% <0.00%> (+0.14%) ⬆️
check_version_ur8long-10.12.1 11.11% <0.00%> (+<0.01%) ⬆️
check_version_ur8long-5.25.1 11.52% <0.00%> (+0.17%) ⬆️
python_scripts 75.90% <ø> (ø)
start_ursim 82.78% <ø> (-2.42%) ⬇️
ur5-3.14.3 74.68% <76.92%> (+0.13%) ⬆️
ur5e-10.11.0 69.30% <76.92%> (+0.06%) ⬆️
ur5e-10.12.0 70.47% <76.92%> (+0.10%) ⬆️
ur5e-10.7.0 68.81% <76.92%> (-0.03%) ⬇️
ur5e-5.9.4 75.15% <76.92%> (-0.04%) ⬇️
ur7e-10.13.0 70.41% <76.92%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@srvald srvald closed this Jul 2, 2026
@srvald srvald reopened this Jul 2, 2026
Comment thread src/helpers.cpp
Comment thread tests/test_helpers.cpp
Comment thread src/helpers.cpp
Comment thread src/helpers.cpp
Comment thread src/helpers.cpp

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

There are 4 total unresolved issues (including 3 from previous reviews).

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 37599d1. Configure here.

Comment thread tests/test_helpers.cpp
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(0, &cpuset);
EXPECT_DEATH(setThreadAffinity(thread, cpuset), "");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linux invalid handle expects death

Medium Severity

The Linux branch of setThreadAffinity_invalidHandle uses EXPECT_DEATH for a default-constructed pthread_t, but setThreadAffinity calls pthread_setaffinity_np and returns false on error (for example ESRCH) without terminating the process.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 37599d1. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@urfeex The expect death is set because when using an invalid handle on Ubuntu it will seg fault. Therefore if I use expect false it will raise an error.

@srvald

srvald commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

@urfeex Regarding the missing Codecov lines, I'm not sure how to reproduce those failures. They were added as defensive checks, but so far I haven't been able to trigger those conditions or reproduce them in the tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant