Skip to content

perf(lambda-rs): Optimize event dispatch#192

Open
vmarcella wants to merge 1 commit intomainfrom
vmarcella/optimize-event-dispatch
Open

perf(lambda-rs): Optimize event dispatch#192
vmarcella wants to merge 1 commit intomainfrom
vmarcella/optimize-event-dispatch

Conversation

@vmarcella
Copy link
Member

Summary

Optimizes ApplicationRuntime event dispatch by precomputing per-category
listener buckets so each event is delivered only to interested components
instead of scanning the full component stack. This reduces dispatch from
O(C) per event to O(k) per event after a one-time O(C) startup index
build, where C is total components and k is listeners for the event
category.

Related Issues

Changes

  • Added per-category event listener indexing in
    crates/lambda-rs/src/runtimes/application.rs
  • Updated dispatch to iterate only listeners for the current event category
  • Added unit tests for bucket mapping, empty-mask rejection, and listener index
    construction

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • Feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation (updates to docs, specs, tutorials, or comments)
  • Refactor (code change that neither fixes a bug nor adds a feature)
  • Performance (change that improves performance)
  • Test (adding or updating tests)
  • Build/CI (changes to build process or CI configuration)

Affected Crates

  • lambda-rs
  • lambda-rs-platform
  • lambda-rs-args
  • lambda-rs-logging
  • Other:

Checklist

  • Code follows the repository style guidelines (cargo +nightly fmt --all)
  • Code passes clippy (cargo clippy --workspace --all-targets -- -D warnings)
  • Tests pass (cargo test --workspace)
  • New code includes appropriate documentation
  • Public API changes are documented
  • Breaking changes are noted in this PR description

Testing

Commands run:

cargo test -p lambda-rs runtimes::application

Manual verification steps (if applicable):

Screenshots/Recordings

N/A

Platform Testing

  • macOS
  • Windows
  • Linux

Additional Notes

@github-actions
Copy link

✅ Coverage Report

📊 View Full HTML Report (download artifact)

Overall Coverage

Metric Value
Total Line Coverage 76.90%
Lines Covered 12757 / 16588

Changed Files in This PR

File Coverage Lines
crates/lambda-rs/src/runtimes/application.rs 35.27% 194/550

PR Files Coverage: 35.27% (194/550 lines)


Generated by cargo-llvm-cov · Latest main coverage

Last updated: 2026-03-11 01:12:48 UTC · Commit: ea542bb

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Optimizes ApplicationRuntime event dispatch by introducing a precomputed per-category listener index, reducing per-event iteration to only components interested in the event’s category.

Changes:

  • Added event_listener_bucket and build_event_listener_index helpers to map event categories to listener buckets and precompute listeners.
  • Updated event dispatch to iterate only the listener indices for the current event category.
  • Added unit tests covering bucket mapping, empty-mask rejection, and listener index construction.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +198 to +210
if event_mask.contains(EventMask::WINDOW) {
return Ok(0);
}
if event_mask.contains(EventMask::KEYBOARD) {
return Ok(1);
}
if event_mask.contains(EventMask::MOUSE) {
return Ok(2);
}
if event_mask.contains(EventMask::RUNTIME) {
return Ok(3);
}
if event_mask.contains(EventMask::COMPONENT) {
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

event_listener_bucket is documented as accepting only a single event-category bit, but the implementation uses contains(...), which will silently accept multi-bit masks (e.g. WINDOW | KEYBOARD would map to bucket 0). This makes invariant violations hard to detect and can misroute events if a composite mask is ever passed. Consider matching on exact equality (or explicitly validating the mask has exactly one bit set) and add a unit test asserting multi-bit masks are rejected.

Suggested change
if event_mask.contains(EventMask::WINDOW) {
return Ok(0);
}
if event_mask.contains(EventMask::KEYBOARD) {
return Ok(1);
}
if event_mask.contains(EventMask::MOUSE) {
return Ok(2);
}
if event_mask.contains(EventMask::RUNTIME) {
return Ok(3);
}
if event_mask.contains(EventMask::COMPONENT) {
if event_mask == EventMask::WINDOW {
return Ok(0);
}
if event_mask == EventMask::KEYBOARD {
return Ok(1);
}
if event_mask == EventMask::MOUSE {
return Ok(2);
}
if event_mask == EventMask::RUNTIME {
return Ok(3);
}
if event_mask == EventMask::COMPONENT {

Copilot uses AI. Check for mistakes.
Comment on lines 287 to +290
let mut event_loop = LoopBuilder::new().build();
let window = self.window_builder.build(&mut event_loop);
let mut component_stack = self.component_stack;
let listener_index = build_event_listener_index(&component_stack);
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

listener_index is built once before the RuntimeEvent::Initialized attach phase runs. If a component’s event_mask() depends on state established during on_attach (or later changes during runtime), it won’t be included in the correct buckets and will stop receiving those events (a behavior change vs the previous per-dispatch mask check). Consider building/rebuilding the index after on_attach completes, or updating the index when masks can change, or documenting/enforcing that event_mask() must be stable before runtime start.

Copilot uses AI. Check for mistakes.
Comment on lines 559 to 560
logging::trace!("Sending event: {:?} to all components", event);

Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

The trace log message says the event is sent "to all components", but dispatch now iterates only the components in the current category bucket. Updating the message (e.g., to "to matching components" and/or include listener count) will avoid misleading diagnostics.

Copilot uses AI. Check for mistakes.
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.

2 participants