Skip to content

Commit dc5d2b7

Browse files
committed
wip
1 parent fe120f7 commit dc5d2b7

44 files changed

Lines changed: 2147 additions & 443 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,7 @@ clap = { version = "4", features = ["derive"] }
4141
regex = "1"
4242
criterion = "0.4"
4343

44+
[[bench]]
45+
name = "lease_hotpath"
46+
harness = false
47+
path = "benches/hotpath/lease.rs"

benches/hotpath/.gitkeep

Whitespace-only changes.

benches/hotpath/lease.rs

Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
//! Lease domain hotpath benchmarks
2+
//!
3+
//! Measures performance of critical lease operations:
4+
//! - acquire: First lease acquisition (cold path)
5+
//! - acquire_contended: Multiple waiters competing for same lease
6+
//! - extend: Active lease extension
7+
//! - release: Lease release with waiter handoff
8+
//! - peek: Read-only lease inspection
9+
10+
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
11+
use fitz::core::lease::service::LeaseService;
12+
use std::sync::Arc;
13+
use tokio::runtime::Runtime;
14+
15+
// Include the shared config module from parent directory
16+
#[path = "../config.rs"]
17+
mod config;
18+
19+
/// Benchmark: Acquire a lease (no contention)
20+
fn bench_lease_acquire_uncontended(c: &mut Criterion) {
21+
let rt = Runtime::new().unwrap();
22+
23+
c.bench_function("lease_acquire_uncontended", |b| {
24+
b.iter(|| {
25+
rt.block_on(async {
26+
// Arrange
27+
let service = LeaseService::new();
28+
29+
// Act: Acquire lease with no contention
30+
let grant = service
31+
.acquire("bench/resource".to_string(), 60)
32+
.await
33+
.unwrap();
34+
35+
// Prevent optimization
36+
black_box(grant)
37+
})
38+
});
39+
});
40+
}
41+
42+
/// Benchmark: Acquire lease when one already exists (becomes waiter)
43+
fn bench_lease_acquire_contended(c: &mut Criterion) {
44+
let rt = Runtime::new().unwrap();
45+
46+
c.bench_function("lease_acquire_contended", |b| {
47+
b.iter(|| {
48+
rt.block_on(async {
49+
// Arrange: Create service with existing lease
50+
let service = Arc::new(LeaseService::new());
51+
let _existing = service
52+
.acquire("bench/resource".to_string(), 60)
53+
.await
54+
.unwrap();
55+
56+
// Act: Second acquire becomes a waiter (non-blocking in bench)
57+
let service_clone = service.clone();
58+
let handle = tokio::spawn(async move {
59+
service_clone
60+
.acquire("bench/resource".to_string(), 30)
61+
.await
62+
});
63+
64+
// Measure enqueue latency, not waiting time
65+
black_box(handle.abort());
66+
})
67+
});
68+
});
69+
}
70+
71+
/// Benchmark: Extend an active lease
72+
fn bench_lease_extend(c: &mut Criterion) {
73+
let rt = Runtime::new().unwrap();
74+
75+
c.bench_function("lease_extend", |b| {
76+
b.iter(|| {
77+
rt.block_on(async {
78+
// Arrange: Acquire a lease first
79+
let service = LeaseService::new();
80+
let grant = service
81+
.acquire("bench/resource".to_string(), 60)
82+
.await
83+
.unwrap();
84+
85+
// Act: Extend the lease
86+
let result = service
87+
.extend("bench/resource".to_string(), &grant.id, &grant.token, 30)
88+
.await;
89+
90+
black_box(result)
91+
})
92+
});
93+
});
94+
}
95+
96+
/// Benchmark: Release a lease (no waiters)
97+
fn bench_lease_release_no_waiters(c: &mut Criterion) {
98+
let rt = Runtime::new().unwrap();
99+
100+
c.bench_function("lease_release_no_waiters", |b| {
101+
b.iter(|| {
102+
rt.block_on(async {
103+
// Arrange: Acquire a lease
104+
let service = LeaseService::new();
105+
let grant = service
106+
.acquire("bench/resource".to_string(), 60)
107+
.await
108+
.unwrap();
109+
110+
// Act: Release the lease
111+
let result = service
112+
.release("bench/resource".to_string(), &grant.id, &grant.token)
113+
.await;
114+
115+
black_box(result)
116+
})
117+
});
118+
});
119+
}
120+
121+
/// Benchmark: Release lease with waiter handoff
122+
fn bench_lease_release_with_waiter(c: &mut Criterion) {
123+
let rt = Runtime::new().unwrap();
124+
125+
c.bench_function("lease_release_with_waiter", |b| {
126+
b.iter(|| {
127+
rt.block_on(async {
128+
// Arrange: Acquire lease and enqueue a waiter
129+
let service = Arc::new(LeaseService::new());
130+
let grant = service
131+
.acquire("bench/resource".to_string(), 60)
132+
.await
133+
.unwrap();
134+
135+
let service_clone = service.clone();
136+
let waiter_handle = tokio::spawn(async move {
137+
service_clone
138+
.acquire("bench/resource".to_string(), 30)
139+
.await
140+
});
141+
142+
// Small delay to ensure waiter is enqueued
143+
tokio::time::sleep(tokio::time::Duration::from_micros(100)).await;
144+
145+
// Act: Release lease (grants to waiter)
146+
let result = service
147+
.release("bench/resource".to_string(), &grant.id, &grant.token)
148+
.await;
149+
150+
// Cleanup
151+
let _ = waiter_handle.await;
152+
black_box(result)
153+
})
154+
});
155+
});
156+
}
157+
158+
/// Benchmark: Peek at active lease
159+
fn bench_lease_peek(c: &mut Criterion) {
160+
let rt = Runtime::new().unwrap();
161+
162+
c.bench_function("lease_peek", |b| {
163+
b.iter(|| {
164+
rt.block_on(async {
165+
// Arrange: Acquire a lease
166+
let service = LeaseService::new();
167+
let _grant = service
168+
.acquire("bench/resource".to_string(), 60)
169+
.await
170+
.unwrap();
171+
172+
// Act: Peek at the lease
173+
let result = service.peek("bench/resource").await;
174+
175+
black_box(result)
176+
})
177+
});
178+
});
179+
}
180+
181+
/// Benchmark: Peek when no lease exists
182+
fn bench_lease_peek_empty(c: &mut Criterion) {
183+
let rt = Runtime::new().unwrap();
184+
185+
c.bench_function("lease_peek_empty", |b| {
186+
b.iter(|| {
187+
rt.block_on(async {
188+
// Arrange: Empty service
189+
let service = LeaseService::new();
190+
191+
// Act: Peek at non-existent lease
192+
let result = service.peek("bench/resource").await;
193+
194+
black_box(result)
195+
})
196+
});
197+
});
198+
}
199+
200+
/// Benchmark: Token computation (HMAC generation)
201+
fn bench_lease_token_computation(c: &mut Criterion) {
202+
let rt = Runtime::new().unwrap();
203+
204+
c.bench_function("lease_token_computation", |b| {
205+
b.iter(|| {
206+
rt.block_on(async {
207+
// Arrange
208+
let service = LeaseService::new();
209+
210+
// Act: Acquire triggers token computation
211+
let grant = service
212+
.acquire("bench/resource".to_string(), 60)
213+
.await
214+
.unwrap();
215+
216+
black_box(grant.token)
217+
})
218+
});
219+
});
220+
}
221+
222+
/// Benchmark: Lease acquire/release cycle
223+
fn bench_lease_acquire_release_cycle(c: &mut Criterion) {
224+
let rt = Runtime::new().unwrap();
225+
226+
c.bench_function("lease_acquire_release_cycle", |b| {
227+
b.iter(|| {
228+
rt.block_on(async {
229+
// Arrange
230+
let service = LeaseService::new();
231+
232+
// Act: Full cycle
233+
let grant = service
234+
.acquire("bench/resource".to_string(), 60)
235+
.await
236+
.unwrap();
237+
238+
let result = service
239+
.release("bench/resource".to_string(), &grant.id, &grant.token)
240+
.await;
241+
242+
black_box(result)
243+
})
244+
});
245+
});
246+
}
247+
248+
/// Benchmark: Multiple concurrent leases (different keys)
249+
fn bench_lease_concurrent_different_keys(c: &mut Criterion) {
250+
let rt = Runtime::new().unwrap();
251+
let mut group = c.benchmark_group("lease_concurrent_different_keys");
252+
253+
for num_keys in [10, 50, 100] {
254+
group.bench_with_input(
255+
BenchmarkId::from_parameter(num_keys),
256+
&num_keys,
257+
|b, &num_keys| {
258+
b.iter(|| {
259+
rt.block_on(async {
260+
// Arrange
261+
let service = Arc::new(LeaseService::new());
262+
263+
// Act: Acquire multiple leases concurrently
264+
let handles: Vec<_> = (0..num_keys)
265+
.map(|i| {
266+
let service_clone = service.clone();
267+
tokio::spawn(async move {
268+
service_clone
269+
.acquire(format!("bench/resource{}", i), 60)
270+
.await
271+
})
272+
})
273+
.collect();
274+
275+
let results = futures::future::join_all(handles).await;
276+
black_box(results)
277+
})
278+
});
279+
},
280+
);
281+
}
282+
283+
group.finish();
284+
}
285+
286+
/// Benchmark: Queue depth (number of waiters per lease)
287+
fn bench_lease_waiter_queue_depth(c: &mut Criterion) {
288+
let rt = Runtime::new().unwrap();
289+
let mut group = c.benchmark_group("lease_waiter_queue_depth");
290+
291+
for num_waiters in [5, 10, 20] {
292+
group.bench_with_input(
293+
BenchmarkId::from_parameter(num_waiters),
294+
&num_waiters,
295+
|b, &num_waiters| {
296+
b.iter(|| {
297+
rt.block_on(async {
298+
// Arrange: One active lease
299+
let service = Arc::new(LeaseService::new());
300+
let grant = service
301+
.acquire("bench/resource".to_string(), 60)
302+
.await
303+
.unwrap();
304+
305+
// Act: Enqueue multiple waiters
306+
let handles: Vec<_> = (0..num_waiters)
307+
.map(|_| {
308+
let service_clone = service.clone();
309+
tokio::spawn(async move {
310+
service_clone
311+
.acquire("bench/resource".to_string(), 30)
312+
.await
313+
})
314+
})
315+
.collect();
316+
317+
// Small delay to ensure all waiters enqueue
318+
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
319+
320+
// Release and measure handoff to first waiter
321+
let result = service
322+
.release("bench/resource".to_string(), &grant.id, &grant.token)
323+
.await;
324+
325+
// Cleanup: abort remaining waiters
326+
for handle in handles {
327+
handle.abort();
328+
}
329+
330+
black_box(result)
331+
})
332+
});
333+
},
334+
);
335+
}
336+
337+
group.finish();
338+
}
339+
340+
criterion_group! {
341+
name = hotpath_lease;
342+
config = config::criterion_config();
343+
targets =
344+
bench_lease_acquire_uncontended,
345+
bench_lease_acquire_contended,
346+
bench_lease_extend,
347+
bench_lease_release_no_waiters,
348+
bench_lease_release_with_waiter,
349+
bench_lease_peek,
350+
bench_lease_peek_empty,
351+
bench_lease_token_computation,
352+
bench_lease_acquire_release_cycle,
353+
bench_lease_concurrent_different_keys,
354+
bench_lease_waiter_queue_depth,
355+
}
356+
357+
criterion_main!(hotpath_lease);

benches/subsystem/lease.rs

Whitespace-only changes.

benches/system/.gitkeep

Whitespace-only changes.

0 commit comments

Comments
 (0)