Performance: Eliminate atomic reference-counting overhead in EventsExecutor collection updates#3193
Performance: Eliminate atomic reference-counting overhead in EventsExecutor collection updates#3193adi213-glitch wants to merge 1 commit into
Conversation
|
Tick the box to add this pull request to the merge queue (same as
|
…llection updates Signed-off-by: Aditya <theaditya213@gmail.com>
There was a problem hiding this comment.
Pull request overview
This PR optimizes the EventsExecutor::refresh_current_collection() hot path by avoiding unnecessary std::shared_ptr copies when ExecutorEntitiesCollection diffs are applied, reducing atomic reference-count churn during high-frequency spinning.
Changes:
- Updated
update()callbacks for subscriptions/clients/services/waitables to take entities asconst auto &instead of by value. - Updated timer
update()callbacks to takeconst rclcpp::TimerBase::SharedPtr &instead of by value.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
hi, thanks for opening a pull request! a few comments:
|
|
Hi @skyegalaxy, thank you for the review and for pointing out the architectural roadmap! That makes complete sense. I wasn't aware the experimental events executor was slated for deprecation in favor of EventsCBGExecutor. I will close this PR and pivot my focus to the rolling branch. I'm going to set up a benchmark rig for the new EventsCBGExecutor to audit its internal collection updates and see if any similar performance issues pop up there. Appreciate the guidance on targeting rolling first. I'll make sure any future optimizations are directed there and tagged for backporting if applicable. |
Issue :
During a performance review of the EventsExecutor hot paths, it was observed that std::shared_ptr entities (timers, subscriptions, clients, services, waitables) were being passed by value into lambda callbacks during refresh_current_collection().
Impact :
Passing std::shared_ptr by value triggers an atomic increment and subsequent decrement of the control block's reference counter. In high-frequency spin loops, these atomic Read-Modify-Write operations force hardware-level cache synchronization barriers, resulting in avoidable instruction pressure and cache-line bouncing across CPU cores.
Fix :
Updated lambda signatures within refresh_current_collection() to capture collection entities via const auto & or const rclcpp::TimerBase::SharedPtr &. This does zero-copy, read-only references to the underlying resources already owned structurally by the collection container, completely bypassing unnecessary atomic operations.
Testing & Verification :
Compiled using colcon on Ubuntu 24.04 / ROS 2 Jazzy.
Profiled utilizing a dedicated Google Benchmark rig scaling the active entity footprint up to 1,000 entities to isolate the micro-architectural behavior from background kernel scheduling noise.
Results: The zero-copy optimization demonstrated a measurable CPU execution latency reduction, saving ~3.64 ms per processing cycle on the magnified payload (amounting to a ~1.9% throughput enhancement).
The patch operates strictly internal to events_executor.cpp and maintains absolute public API and ABI compatibility.
