-
Notifications
You must be signed in to change notification settings - Fork 65
feat: auto listener benchmark #420
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: auto listener benchmark #420
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #420 +/- ##
=====================================
Coverage 47.9% 48.0%
=====================================
Files 69 69
Lines 9860 9855 -5
=====================================
Hits 4731 4731
+ Misses 5129 5124 -5 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
} | ||
|
||
// Enable listener with RAII guard | ||
let _guard = UserEventsListenerGuard::enable("myprovider") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this works as the tracepoint name will not exist at this point! This should be done after the provider is built, which will build the user_events exporter, which will create the tracepoint names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved UserEventsListenerGuard::enable(PROVIDER_NAME) to occur after building the provider in all benchmarks, ensuring tracepoints exist first.
…to feat/auto-listener-benchmark
let provider = setup_provider_default(); | ||
// Enable listener with RAII guard (after provider is built so tracepoints exist) | ||
let _guard = UserEventsListenerGuard::enable(PROVIDER_NAME).unwrap_or_else(|e| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this means the listener is always enabled when the benchmarks is run. What we really want is for the benchmark to run this with and without enabling the listener. A criterion bench group - like group.bench_function(enabled) and group.bench_function(disabled).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yes, good find - seems I missed while reviewing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the excellent suggestion! You're absolutely right - the current approach always enables the listener, which doesn't provide meaningful performance comparison data.
I've restructured all benchmark functions to use criterion bench groups that run both with and without the listener enabled:
Each benchmark now creates a benchmark_group with "disabled" and "enabled" variants
The "disabled" case runs without any listener management (baseline performance)
The "enabled" case uses the RAII guard to enable/disable the listener
This provides proper comparison data showing the actual overhead of enabling user events
The changes maintain all the safety benefits (RAII guards, proper cleanup) while giving us the performance comparison we need. Users can now see the baseline performance vs. the overhead of having the listener active.
This addresses the core issue you identified - we now have proper benchmark data for both states rather than always running with the listener enabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this. Requesting changes to address https://github.com/open-telemetry/opentelemetry-rust-contrib/pull/420/files#r2273844603
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All reviewer comments have been addressed:
✅ Fixed command injection risk by using sudo tee
with piped stdin instead of shell commands
✅ Replaced hardcoded "myprovider" with PROVIDER_NAME
constant
✅ Extracted duplicated dummy guard creation into dummy_guard()
helper method
✅ Added USER_EVENTS_PROVIDER_SUFFIX
constant to eliminate magic string
✅ Moved listener enabling to occur after provider creation (tracepoints exist)
✅ Removed experimental features from default in Cargo.toml
✅ Restructured benchmarks to compare enabled/disabled listener performance using criterion groups
✅ Reverted non-user-facing changes from CHANGELOG
The benchmarks now properly compare performance with and without the listener enabled, providing meaningful data for both states.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements automatic listener management for user-events logs benchmarking by introducing RAII guards that enable/disable the user events listener, eliminating the need for manual listener management and ensuring proper cleanup.
- Added
UserEventsListenerGuard
struct with automatic enable/disable functionality using RAII pattern - Updated all benchmark functions to test both enabled and disabled listener states automatically
- Enhanced benchmark results documentation with current performance data and automatic management details
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
File | Description |
---|---|
opentelemetry-user-events-logs/benches/logs.rs | Implements RAII guard for automatic listener management and updates benchmark functions to test both enabled/disabled states |
opentelemetry-user-events-logs/CHANGELOG.md | Adds empty line to changelog (no functional changes) |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
/// /sys/kernel/debug/tracing/events/user_events/myprovider_L2K1/enable | ||
/// For more details, see the Linux kernel documentation on user_events: | ||
/// https://docs.kernel.org/trace/user_events.html | ||
const USER_EVENTS_PROVIDER_SUFFIX: &str = "_L2K1"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The hardcoded suffix "_L2K1" is system-specific and may not work across different systems or kernel versions. Consider dynamically discovering the actual suffix by scanning the directory /sys/kernel/debug/tracing/events/user_events/
for providers starting with the provider name, or document this limitation more prominently.
const USER_EVENTS_PROVIDER_SUFFIX: &str = "_L2K1"; | |
// Dynamically discover the actual provider directory (with suffix) at runtime. | |
/// Returns the full provider directory name (e.g., "myprovider_L2K1") by scanning | |
/// /sys/kernel/debug/tracing/events/user_events/ for a directory starting with the provider name. | |
fn get_user_events_provider_dir(provider_name: &str) -> io::Result<String> { | |
let dir = "/sys/kernel/debug/tracing/events/user_events/"; | |
for entry in fs::read_dir(dir)? { | |
let entry = entry?; | |
let file_name = entry.file_name(); | |
let file_name_str = file_name.to_string_lossy(); | |
if file_name_str.starts_with(provider_name) { | |
return Ok(file_name_str.into_owned()); | |
} | |
} | |
Err(io::Error::new( | |
io::ErrorKind::NotFound, | |
format!("Provider directory for '{}' not found in {}", provider_name, dir), | |
)) | |
} |
Copilot uses AI. Check for mistakes.
/// * `Ok(String)` - The status content if user events are available | ||
/// * `Err(String)` - Error message if user events are not available | ||
fn check_user_events_available() -> Result<String, String> { | ||
match fs::read_to_string("/sys/kernel/tracing/user_events_status") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The path /sys/kernel/tracing/user_events_status
is hardcoded and differs from the debugfs path pattern used elsewhere (/sys/kernel/debug/tracing/
). Consider defining this as a constant or documenting why different paths are used for different operations.
Copilot uses AI. Check for mistakes.
if self.is_dummy { | ||
return; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The disable_path
variable is constructed using self.provider_name
which could be the dummy provider name if this is a dummy guard. However, the is_dummy
check occurs after the path construction. This could lead to attempting to write to an invalid path. Move the is_dummy
check before any path operations.
// Skip cleanup for dummy guards | |
if self.is_dummy { | |
return; | |
} | |
let disable_path = format!( | |
"/sys/kernel/debug/tracing/events/user_events/{}{}/enable", | |
self.provider_name, USER_EVENTS_PROVIDER_SUFFIX | |
); |
Copilot uses AI. Check for mistakes.
Fixes #369
Design discussion issue (if applicable) #
Changes
This PR improves the user-events logs benchmark by adding automatic enable/disable management for the user events listener using RAII guards. The benchmark now automatically enables the listener when tests start and disables it when they complete, ensuring proper cleanup even if the benchmark panics.
Key Changes:
UserEventsListenerGuard
RAII guard for automatic listener managementTechnical Details:
echo
commands to enable/disable listener:/sys/kernel/debug/tracing/events/user_events/myprovider_L2K1/enable
Merge requirement checklist
CHANGELOG.md
files updated for non-trivial, user-facing changes