-
Notifications
You must be signed in to change notification settings - Fork 1.9k
[ENH] Benchmark for s3 heap. #5564
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
Conversation
Reviewer ChecklistPlease leverage this checklist to ensure your code review is thorough before approving Testing, Bugs, Errors, Logs, Documentation
System Compatibility
Quality
|
|
Add Benchmark for This PR introduces a new benchmarking tool for the Key Changes• Added new benchmark example file Affected Areas• This summary was automatically generated by @propel-code-bot |
| #[derive(Clone, Eq, PartialEq)] | ||
| pub struct Options { | ||
| pub runtime: usize, | ||
| pub target_throughput: usize, | ||
| pub max_tokio_tasks: usize, | ||
| } | ||
|
|
||
| impl Default for Options { | ||
| fn default() -> Self { | ||
| Options { | ||
| runtime: 60, | ||
| target_throughput: 100_000, | ||
| max_tokio_tasks: 10_000_000, | ||
| } | ||
| } | ||
| } |
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.
[BestPractice]
The design of this benchmark could be refined to provide more realistic and clearer results.
- Misleading Configuration and High Memory Usage: The
max_tokio_tasksfield inOptionsis used to define a very large channel capacity (over 10 million elements). This could lead to high memory consumption (potentially >600MB) if the consumer task falls behind, which might mask performance bottlenecks by simply buffering them. - Ineffective Task Limit Check: The check
if tasks_alive > options.max_tokio_tasksis unlikely to ever trigger since only one long-lived task is spawned.
Consider simplifying this by removing max_tokio_tasks and sizing the channel relative to the throughput. Using tx.send(...).await instead of try_send() would also introduce back-pressure, giving a better signal of the sustainable throughput of the system under test.
For example:
// In Options struct, remove max_tokio_tasks
pub struct Options {
pub runtime: usize,
pub target_throughput: usize,
}
// In main(), adjust channel size
let (tx, mut rx) =
tokio::sync::mpsc::channel::<Schedule>(options.target_throughput * 2); // e.g. 2s buffer
// In the producer loop, use awaitable send and remove task check
// ...
if tx.send(Schedule { ... }).await.is_err() {
// The receiver has been dropped, so we can stop.
break;
}
// ...- I/O in Hot Loop: The
eprintln!in the consumer's hot loop can introduce I/O overhead and affect measurements. It would be better to aggregate statistics and print a summary only at the end of the run.
Context for Agents
[**BestPractice**]
The design of this benchmark could be refined to provide more realistic and clearer results.
1. **Misleading Configuration and High Memory Usage**: The `max_tokio_tasks` field in `Options` is used to define a very large channel capacity (over 10 million elements). This could lead to high memory consumption (potentially >600MB) if the consumer task falls behind, which might mask performance bottlenecks by simply buffering them.
2. **Ineffective Task Limit Check**: The check `if tasks_alive > options.max_tokio_tasks` is unlikely to ever trigger since only one long-lived task is spawned.
Consider simplifying this by removing `max_tokio_tasks` and sizing the channel relative to the throughput. Using `tx.send(...).await` instead of `try_send()` would also introduce back-pressure, giving a better signal of the sustainable throughput of the system under test.
For example:
```rust
// In Options struct, remove max_tokio_tasks
pub struct Options {
pub runtime: usize,
pub target_throughput: usize,
}
// In main(), adjust channel size
let (tx, mut rx) =
tokio::sync::mpsc::channel::<Schedule>(options.target_throughput * 2); // e.g. 2s buffer
// In the producer loop, use awaitable send and remove task check
// ...
if tx.send(Schedule { ... }).await.is_err() {
// The receiver has been dropped, so we can stop.
break;
}
// ...
```
3. **I/O in Hot Loop**: The `eprintln!` in the consumer's hot loop can introduce I/O overhead and affect measurements. It would be better to aggregate statistics and print a summary only at the end of the run.
File: rust/s3heap/examples/s3heap-benchmark.rs
Line: 32| name: "demo".to_string(), | ||
| }, | ||
| nonce, | ||
| next_scheduled: Utc::now() |
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.
We could make a configuration of this benchmark where next_scheduled is spread out a bit more to see how we do when we don't bucket that well.
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.
Good idea. We can add that.
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.
Left one comment
5e54c6d to
52da7a6
Compare
74bfed0 to
d5312b4
Compare
| ); | ||
| let (tx, mut rx) = | ||
| tokio::sync::mpsc::channel::<Schedule>(options.target_throughput + options.max_tokio_tasks); | ||
| let count = Arc::new(AtomicU64::new(0)); |
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.
[PerformanceOptimization]
The channel capacity is set to options.target_throughput + options.max_tokio_tasks, which is over 10 million with the default options. This will result in a channel buffer that consumes a large amount of memory (~650MB) and can lead to very large batches being processed by the consumer. This might be intentional for stress-testing, but if the goal is to simulate more frequent, smaller batches, you might consider reducing this capacity. Using just options.target_throughput would still allow for significant batching while using less memory.
Context for Agents
[**PerformanceOptimization**]
The channel capacity is set to `options.target_throughput + options.max_tokio_tasks`, which is over 10 million with the default options. This will result in a channel buffer that consumes a large amount of memory (~650MB) and can lead to very large batches being processed by the consumer. This might be intentional for stress-testing, but if the goal is to simulate more frequent, smaller batches, you might consider reducing this capacity. Using just `options.target_throughput` would still allow for significant batching while using less memory.
File: rust/s3heap/examples/s3heap-benchmark.rs
Line: 48| let mut next = Duration::ZERO; | ||
| loop { | ||
| let gap = interarrival_duration(options.target_throughput as f64)(&mut guac); | ||
| let future = interarrival_duration(1.0 / 60.0)(&mut guac); |
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.
[BestPractice]
The variable name future is a bit confusing in an async context, as it can be mistaken for a Rust Future type. Since it represents a std::time::Duration, consider renaming it to something more descriptive like schedule_delay to improve clarity. You'll also need to update its usage on line 96.
Context for Agents
[**BestPractice**]
The variable name `future` is a bit confusing in an `async` context, as it can be mistaken for a Rust `Future` type. Since it represents a `std::time::Duration`, consider renaming it to something more descriptive like `schedule_delay` to improve clarity. You'll also need to update its usage on line 96.
File: rust/s3heap/examples/s3heap-benchmark.rs
Line: 7852da7a6 to
43edec4
Compare
d4ceee4 to
b18c541
Compare
4007de1 to
08647ab
Compare
75ff5ab to
1de60cc
Compare
Unscientifically, minio can push 1k triggers per second with batching that keeps the latency under one second. No need for sciencing this one.
b18c541 to
0c2442a
Compare
| { | ||
| break; | ||
| } | ||
| eprintln!("HEAP::PUSH {}", buffer.len()); |
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.
[BestPractice]
For a more accurate performance measurement, it's generally better to avoid I/O operations like eprintln! inside the hot loop of a benchmark. Printing to stderr can introduce latency and skew the results. The summary statistics printed at the end of the run are sufficient for reporting.
Context for Agents
[**BestPractice**]
For a more accurate performance measurement, it's generally better to avoid I/O operations like `eprintln!` inside the hot loop of a benchmark. Printing to stderr can introduce latency and skew the results. The summary statistics printed at the end of the run are sufficient for reporting.
File: rust/s3heap/examples/s3heap-benchmark.rs
Line: 66
Description of changes
Unscientifically, minio can push 1k triggers per second with batching
that keeps the latency under one second. No need for sciencing this
one.
Test plan
Local + CI
Migration plan
N/A
Observability plan
N/A
Documentation Changes
N/A