Skip to content

Commit 2ab02d8

Browse files
eliothedemanfacebook-github-bot
authored andcommitted
Channel benchmarks (meta-pytorch#627)
Summary: Pull Request resolved: meta-pytorch#627 Differential Revision: D78755894
1 parent 354b66c commit 2ab02d8

File tree

3 files changed

+248
-1
lines changed

3 files changed

+248
-1
lines changed

hyperactor/Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# @generated by autocargo from //monarch/hyperactor:[hyperactor,hyperactor-example-derive]
1+
# @generated by autocargo from //monarch/hyperactor:[channel_benchmarks,hyperactor,hyperactor-example-derive]
22

33
[package]
44
name = "hyperactor"
@@ -9,6 +9,10 @@ description = "a high-performance, scalable actor framework for cluster computin
99
repository = "https://github.com/pytorch-labs/monarch/"
1010
license = "BSD-3-Clause"
1111

12+
[[bin]]
13+
name = "channel_benchmarks"
14+
path = "benches/channel_benchmarks.rs"
15+
1216
[[bin]]
1317
name = "hyperactor_example_derive"
1418
path = "example/derive.rs"
@@ -21,6 +25,7 @@ bincode = "1.3.3"
2125
bytes = { version = "1.9.0", features = ["serde"] }
2226
cityhasher = "0.1.0"
2327
crc32fast = "1.4"
28+
criterion = { version = "0.5.1", features = ["async_tokio", "csv_output"] }
2429
dashmap = { version = "5.5.3", features = ["rayon", "serde"] }
2530
derivative = "2.2"
2631
dns-lookup = "1.0"

hyperactor/benches/README.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Hyperactor Channel Benchmarks
2+
3+
This directory contains comprehensive benchmarks for the Hyperactor channel system using the Criterion benchmarking framework.
4+
5+
## Overview
6+
7+
The benchmark harness tests various aspects of channel performance:
8+
9+
1. **Channel Creation** - Benchmarks the cost of creating channels (dial/serve operations)
10+
2. **Message Sending** - Tests different sending methods (`try_post`, `post`, `send`)
11+
3. **Message Sizes** - Compares performance with different message sizes (small, medium, large)
12+
4. **Throughput** - Measures messages per second for different transports
13+
5. **Latency** - Round-trip latency measurements
14+
6. **Transport Comparison** - Performance comparison between different transport types
15+
16+
## Supported Transports
17+
18+
The benchmarks test the following channel transports:
19+
20+
- **Local** - In-process channels using mpsc
21+
- **TCP** - Network channels over TCP
22+
- **Unix** - Unix domain socket channels
23+
24+
## Message Types
25+
26+
Three message types are used to test different payload sizes:
27+
28+
- **SmallMessage** - ~16 bytes (id + value)
29+
- **MediumMessage** - ~1KB (id + 1KB data)
30+
- **LargeMessage** - ~64KB (id + 64KB payload)
31+
32+
## Running Benchmarks
33+
34+
### Run All Benchmarks
35+
```bash
36+
cargo bench
37+
```
38+
39+
### Run Specific Benchmark Groups
40+
```bash
41+
# Channel creation benchmarks
42+
cargo bench channel_creation
43+
44+
# Message sending benchmarks
45+
cargo bench message_sending
46+
47+
# Message size comparison
48+
cargo bench message_sizes
49+
50+
# Throughput benchmarks
51+
cargo bench throughput
52+
53+
# Latency benchmarks
54+
cargo bench latency
55+
56+
# Transport comparison
57+
cargo bench transport_comparison
58+
```
59+
60+
### Run with Specific Transport
61+
```bash
62+
# Run only local transport benchmarks
63+
cargo bench -- local
64+
65+
# Run only TCP transport benchmarks
66+
cargo bench -- tcp
67+
```
68+
69+
## Output
70+
71+
Benchmarks generate:
72+
73+
1. **Console Output** - Real-time results with timing statistics
74+
2. **HTML Reports** - Detailed reports in `target/criterion/` directory
75+
3. **Baseline Comparisons** - Performance regression detection
76+
77+
## Benchmark Details
78+
79+
### Channel Creation
80+
- Measures time to create server (`serve`) and client (`dial`) endpoints
81+
- Tests all supported transport types
82+
- Useful for understanding connection establishment overhead
83+
84+
### Message Sending
85+
- Compares `try_post` (non-blocking), `post` (fire-and-forget), and `send` (synchronous)
86+
- Tests local and TCP transports
87+
- Measures raw sending performance
88+
89+
### Message Sizes
90+
- Tests impact of payload size on performance
91+
- Uses local transport to isolate serialization/deserialization costs
92+
- Reports throughput in bytes per second
93+
94+
### Throughput
95+
- Measures sustained message rate
96+
- Batches messages to reduce measurement overhead
97+
- 10-second measurement window for stability
98+
99+
### Latency
100+
- Round-trip latency measurement
101+
- Uses echo server pattern
102+
- Tests both local and network transports
103+
104+
### Transport Comparison
105+
- Direct comparison of transport performance
106+
- Sends 1000 messages per iteration
107+
- Helps choose optimal transport for use case
108+
109+
## Interpreting Results
110+
111+
- **Lower is better** for latency measurements
112+
- **Higher is better** for throughput measurements
113+
- **Confidence intervals** indicate measurement reliability
114+
- **Slope** indicates performance scaling characteristics
115+
116+
## Configuration
117+
118+
Benchmarks can be customized by modifying:
119+
120+
- Message sizes in the message type definitions
121+
- Number of messages in throughput tests
122+
- Measurement duration in benchmark groups
123+
- Transport types tested
124+
125+
## Dependencies
126+
127+
The benchmark harness requires:
128+
129+
- `criterion` - Benchmarking framework
130+
- `tokio` - Async runtime
131+
- `serde` - Message serialization
132+
- `hyperactor` - The library being benchmarked
133+
134+
## Notes
135+
136+
- Benchmarks automatically handle async operations using Tokio runtime
137+
- Receiver tasks are spawned to consume messages and prevent backpressure
138+
- Results may vary based on system load and hardware
139+
- Network benchmarks may be affected by local network configuration
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
use std::future::IntoFuture;
10+
use std::iter::zip;
11+
use std::time::Duration;
12+
use std::time::Instant;
13+
14+
use criterion::BenchmarkId;
15+
use criterion::Criterion;
16+
use criterion::Throughput;
17+
use criterion::black_box;
18+
use criterion::criterion_group;
19+
use criterion::criterion_main;
20+
use hyperactor::Named;
21+
use hyperactor::RemoteMessage;
22+
use hyperactor::channel::ChannelAddr;
23+
use hyperactor::channel::ChannelRx;
24+
use hyperactor::channel::ChannelTransport;
25+
use hyperactor::channel::ChannelTx;
26+
use hyperactor::channel::Rx;
27+
use hyperactor::channel::Tx;
28+
use hyperactor::channel::dial;
29+
use hyperactor::channel::serve;
30+
use serde::Deserialize;
31+
use serde::Serialize;
32+
use tokio::runtime::Runtime;
33+
use tokio::sync::oneshot;
34+
35+
#[derive(Debug, Clone, Serialize, Deserialize, Named, PartialEq)]
36+
struct Message {
37+
id: u64,
38+
payload: Vec<u8>,
39+
}
40+
41+
impl Message {
42+
fn new(id: u64, size: usize) -> Self {
43+
Self {
44+
id,
45+
payload: vec![0; size],
46+
}
47+
}
48+
}
49+
50+
// Benchmark message sizes
51+
fn bench_message_sizes(c: &mut Criterion) {
52+
let mut group = c.benchmark_group("message_sizes");
53+
54+
let transports = vec![
55+
("local", ChannelTransport::Local),
56+
("tcp", ChannelTransport::Tcp),
57+
("metatls", ChannelTransport::MetaTls),
58+
("unix", ChannelTransport::Unix),
59+
];
60+
61+
for size_exp in 1..10 {
62+
let size = 10_usize.pow(size_exp);
63+
let fsize = size as f64;
64+
let (nice_size, postfix) = match size {
65+
1_000..=999_999 => (fsize / 1000f64, "kb"),
66+
1_000_000..=999_999_999 => (fsize / 1_000_000f64, "mb"),
67+
1_000_000_000..=999_999_999_999 => (fsize / 1_000_000_000f64, "gb"),
68+
_ => (fsize, "b"),
69+
};
70+
71+
for (transport_name, transport) in &transports {
72+
let transport = transport.clone();
73+
group.throughput(Throughput::Bytes(size as u64));
74+
group.bench_function(
75+
format!("message_{}_{}{}", transport_name, nice_size, postfix),
76+
move |b| {
77+
let mut b = b.to_async(Runtime::new().unwrap());
78+
let tt = &transport;
79+
b.iter_custom(|iters| async move {
80+
let addr = ChannelAddr::any(tt.clone());
81+
let (listen_addr, mut rx) = serve::<Message>(addr).await.unwrap();
82+
let tx = dial::<Message>(listen_addr).unwrap();
83+
let msg = Message::new(0, size);
84+
let start = Instant::now();
85+
for _ in 0..iters {
86+
tx.post(msg.clone());
87+
rx.recv().await.unwrap();
88+
}
89+
start.elapsed()
90+
});
91+
},
92+
);
93+
}
94+
}
95+
96+
group.finish();
97+
}
98+
99+
// Benchmark throughpu
100+
101+
criterion_group!(benches, bench_message_sizes);
102+
103+
criterion_main!(benches);

0 commit comments

Comments
 (0)