mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-09-02 09:09:17 +00:00
perf: reduce packet buffer slicing churn (#2381)
* bench: add packet bytes extraction Criterion benchmark Adds a Criterion benchmark under easytier/benches/ covering ZCPacket::payload_bytes and tunnel_payload_bytes at 1280/4096-byte payload sizes, using iter_batched so ZCPacket construction stays in the setup phase and is excluded from the timed region. - Register the [[bench]] entry in easytier/Cargo.toml. - Document the bench and PACKET_BYTES_* env vars in benches/README.md. * perf: reduce packet buffer slicing churn Replace BytesMut::split_off with Buf::advance in ZCPacket bytes extraction paths (payload_bytes, tunnel_payload_bytes, convert_type, drop_foreign_header) and in TunZCPacketToBytes, and simplify the copy_from_slice in new_from_payload. When the buffer is in its unique (VEC) representation, split_off promotes it to the shared (ARC) representation, allocating a Shared control block and bumping the refcount on every call, and pins the buffer in shared mode. advance only mutates the in-place ptr/len/cap fields, avoiding that allocation/refcount churn on the TX hot path. The byte data itself is not copied by either path.
This commit is contained in:
@@ -1,4 +1,47 @@
|
||||
# TX Throughput Benchmark
|
||||
# Benchmarks
|
||||
|
||||
Criterion benchmarks for EasyTier hot paths.
|
||||
|
||||
| Bench | What it measures |
|
||||
| --------------------------- | -------------------------------------------------------------------------------- |
|
||||
| `tx_throughput` | End-to-end TX injection path through `peer_manager::send_msg_by_ip` |
|
||||
| `packet_bytes_extraction` | `ZCPacket::payload_bytes` / `tunnel_payload_bytes` extraction (advance hot path) |
|
||||
|
||||
## Packet Bytes Extraction
|
||||
|
||||
Criterion benchmark for `ZCPacket` bytes extraction — the methods touched by the
|
||||
`advance`-based slicing refactor. Measures `payload_bytes` and
|
||||
`tunnel_payload_bytes` at two payload sizes (1280, 4096). Setup
|
||||
(`ZCPacket::new_with_payload`) runs in the benchmark harness's preparation
|
||||
phase and is excluded from the timed region, so the numbers reflect only the
|
||||
extraction call.
|
||||
|
||||
### Quick start
|
||||
|
||||
```bash
|
||||
cargo bench --bench packet_bytes_extraction
|
||||
```
|
||||
|
||||
Smoke run:
|
||||
|
||||
```bash
|
||||
PACKET_BYTES_MEASUREMENT_SECS=2 \
|
||||
PACKET_BYTES_WARMUP_SECS=1 \
|
||||
PACKET_BYTES_SAMPLE_SIZE=10 \
|
||||
cargo bench --bench packet_bytes_extraction -- --quiet
|
||||
```
|
||||
|
||||
### Environment variables
|
||||
|
||||
| Variable | Default | Notes |
|
||||
| ------------------------------- | ------- | ---------------------------- |
|
||||
| `PACKET_BYTES_MEASUREMENT_SECS` | `10` | Criterion `measurement_time` |
|
||||
| `PACKET_BYTES_WARMUP_SECS` | `3` | Criterion `warm_up_time` |
|
||||
| `PACKET_BYTES_SAMPLE_SIZE` | `10` | Criterion `sample_size` (min 10) |
|
||||
|
||||
---
|
||||
|
||||
## TX Throughput Benchmark
|
||||
|
||||
Criterion benchmark for EasyTier's TX injection path (`peer_manager::send_msg_by_ip`).
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
use std::hint::black_box;
|
||||
use std::time::Duration;
|
||||
|
||||
use criterion::{BatchSize, Criterion, Throughput, criterion_group, criterion_main};
|
||||
|
||||
use easytier::tunnel::packet_def::ZCPacket;
|
||||
|
||||
const PAYLOAD_SIZES: &[usize] = &[1280, 4096];
|
||||
|
||||
fn env_parse<T: std::str::FromStr>(key: &str, default: T) -> T {
|
||||
std::env::var(key)
|
||||
.ok()
|
||||
.and_then(|v| v.parse().ok())
|
||||
.unwrap_or(default)
|
||||
}
|
||||
|
||||
fn bench_payload_bytes(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("payload_bytes");
|
||||
for &size in PAYLOAD_SIZES {
|
||||
let data = vec![0u8; size];
|
||||
group.throughput(Throughput::Bytes(size as u64));
|
||||
group.bench_with_input(format!("{size}"), &data, |b, data| {
|
||||
b.iter_batched(
|
||||
|| ZCPacket::new_with_payload(black_box(data)),
|
||||
|p| black_box(p).payload_bytes(),
|
||||
BatchSize::SmallInput,
|
||||
)
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
fn bench_tunnel_payload_bytes(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("tunnel_payload_bytes");
|
||||
for &size in PAYLOAD_SIZES {
|
||||
let data = vec![0u8; size];
|
||||
group.throughput(Throughput::Bytes(size as u64));
|
||||
group.bench_with_input(format!("{size}"), &data, |b, data| {
|
||||
b.iter_batched(
|
||||
|| ZCPacket::new_with_payload(black_box(data)),
|
||||
|p| black_box(p).tunnel_payload_bytes(),
|
||||
BatchSize::SmallInput,
|
||||
)
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
fn criterion_config() -> Criterion {
|
||||
let measurement_secs = env_parse("PACKET_BYTES_MEASUREMENT_SECS", 10u64);
|
||||
let warmup_secs = env_parse("PACKET_BYTES_WARMUP_SECS", 3u64);
|
||||
let sample_size = env_parse("PACKET_BYTES_SAMPLE_SIZE", 10usize).max(10);
|
||||
|
||||
Criterion::default()
|
||||
.measurement_time(Duration::from_secs(measurement_secs))
|
||||
.warm_up_time(Duration::from_secs(warmup_secs))
|
||||
.sample_size(sample_size)
|
||||
}
|
||||
|
||||
criterion_group! {
|
||||
name = benches;
|
||||
config = criterion_config();
|
||||
targets = bench_payload_bytes, bench_tunnel_payload_bytes
|
||||
}
|
||||
criterion_main!(benches);
|
||||
Reference in New Issue
Block a user