wifi-densepose/vendor/midstream/benches/scheduler_bench.rs

511 lines
15 KiB
Rust

//! Comprehensive benchmarks for nanosecond-scheduler crate
//!
//! Benchmarks cover:
//! - Schedule overhead (target: <100ns)
//! - Task execution latency
//! - Priority queue operations
//! - Statistics calculation overhead
//! - Multi-threaded scheduling
//! - Batch operations
//!
//! Performance targets:
//! - Schedule overhead: <100ns
//! - Task execution: <1μs
//! - Stats calculation: <10μs
use criterion::{black_box, criterion_group, criterion_main, Criterion, BenchmarkId, Throughput};
use midstreamer_scheduler::{
NanoScheduler, Task, TaskPriority, ScheduleResult,
stats::SchedulerStats,
};
use std::time::{Duration, Instant};
use std::sync::{Arc, Mutex};
use std::thread;
// ============================================================================
// Test Task Generators
// ============================================================================
fn create_simple_task(id: u64) -> Task {
Task::new(
format!("task_{}", id),
Box::new(move || {
// Minimal work
black_box(id * 2);
}),
TaskPriority::Normal,
)
}
fn create_compute_task(id: u64, iterations: u64) -> Task {
Task::new(
format!("compute_{}", id),
Box::new(move || {
let mut sum = 0u64;
for i in 0..iterations {
sum = sum.wrapping_add(i);
}
black_box(sum);
}),
TaskPriority::Normal,
)
}
fn create_io_task(id: u64, sleep_micros: u64) -> Task {
Task::new(
format!("io_{}", id),
Box::new(move || {
thread::sleep(Duration::from_micros(sleep_micros));
black_box(id);
}),
TaskPriority::Normal,
)
}
fn create_priority_task(id: u64, priority: TaskPriority) -> Task {
Task::new(
format!("priority_{}", id),
Box::new(move || {
black_box(id);
}),
priority,
)
}
// ============================================================================
// Schedule Overhead Benchmarks
// ============================================================================
fn bench_schedule_overhead(c: &mut Criterion) {
let mut group = c.benchmark_group("schedule_overhead");
group.throughput(Throughput::Elements(1));
// Single task scheduling
group.bench_function("single_task", |b| {
let mut scheduler = NanoScheduler::new(4);
let mut task_id = 0u64;
b.iter(|| {
task_id += 1;
let task = create_simple_task(task_id);
black_box(scheduler.schedule(black_box(task)))
});
});
// Batch scheduling
for batch_size in [10, 50, 100, 500].iter() {
group.throughput(Throughput::Elements(*batch_size as u64));
group.bench_with_input(
BenchmarkId::new("batch", batch_size),
batch_size,
|b, &size| {
let mut scheduler = NanoScheduler::new(4);
let mut task_id = 0u64;
b.iter(|| {
let tasks: Vec<_> = (0..size)
.map(|_| {
task_id += 1;
create_simple_task(task_id)
})
.collect();
for task in tasks {
black_box(scheduler.schedule(black_box(task)));
}
});
}
);
}
group.finish();
}
fn bench_schedule_with_priorities(c: &mut Criterion) {
let mut group = c.benchmark_group("schedule_priorities");
let priorities = [
("critical", TaskPriority::Critical),
("high", TaskPriority::High),
("normal", TaskPriority::Normal),
("low", TaskPriority::Low),
];
for (name, priority) in priorities.iter() {
group.bench_function(*name, |b| {
let mut scheduler = NanoScheduler::new(4);
let mut task_id = 0u64;
b.iter(|| {
task_id += 1;
let task = create_priority_task(task_id, *priority);
black_box(scheduler.schedule(black_box(task)))
});
});
}
group.finish();
}
// ============================================================================
// Task Execution Latency Benchmarks
// ============================================================================
fn bench_execution_latency(c: &mut Criterion) {
let mut group = c.benchmark_group("execution_latency");
// Minimal work
group.bench_function("minimal_work", |b| {
let mut scheduler = NanoScheduler::new(4);
b.iter(|| {
let task = create_simple_task(1);
scheduler.schedule(task);
scheduler.run_once();
});
});
// Light compute
group.bench_function("light_compute", |b| {
let mut scheduler = NanoScheduler::new(4);
b.iter(|| {
let task = create_compute_task(1, 100);
scheduler.schedule(task);
scheduler.run_once();
});
});
// Medium compute
group.bench_function("medium_compute", |b| {
let mut scheduler = NanoScheduler::new(4);
b.iter(|| {
let task = create_compute_task(1, 1000);
scheduler.schedule(task);
scheduler.run_once();
});
});
// Heavy compute
group.bench_function("heavy_compute", |b| {
let mut scheduler = NanoScheduler::new(4);
b.iter(|| {
let task = create_compute_task(1, 10000);
scheduler.schedule(task);
scheduler.run_once();
});
});
group.finish();
}
fn bench_execution_throughput(c: &mut Criterion) {
let mut group = c.benchmark_group("execution_throughput");
for num_tasks in [10, 50, 100, 500, 1000].iter() {
group.throughput(Throughput::Elements(*num_tasks as u64));
group.bench_with_input(
BenchmarkId::new("tasks", num_tasks),
num_tasks,
|b, &size| {
b.iter(|| {
let mut scheduler = NanoScheduler::new(4);
for i in 0..size {
let task = create_simple_task(i as u64);
scheduler.schedule(task);
}
while scheduler.has_pending_tasks() {
scheduler.run_once();
}
});
}
);
}
group.finish();
}
// ============================================================================
// Priority Queue Benchmarks
// ============================================================================
fn bench_priority_queue_operations(c: &mut Criterion) {
let mut group = c.benchmark_group("priority_queue");
// Push operations
group.bench_function("push_operations", |b| {
let mut scheduler = NanoScheduler::new(4);
let mut task_id = 0u64;
b.iter(|| {
task_id += 1;
let priority = match task_id % 4 {
0 => TaskPriority::Critical,
1 => TaskPriority::High,
2 => TaskPriority::Normal,
_ => TaskPriority::Low,
};
let task = create_priority_task(task_id, priority);
black_box(scheduler.schedule(black_box(task)))
});
});
// Pop operations
group.bench_function("pop_operations", |b| {
b.iter(|| {
let mut scheduler = NanoScheduler::new(4);
// Fill queue
for i in 0..100 {
let priority = match i % 4 {
0 => TaskPriority::Critical,
1 => TaskPriority::High,
2 => TaskPriority::Normal,
_ => TaskPriority::Low,
};
let task = create_priority_task(i, priority);
scheduler.schedule(task);
}
// Pop all
while scheduler.has_pending_tasks() {
black_box(scheduler.run_once());
}
});
});
// Mixed operations
group.bench_function("mixed_operations", |b| {
let mut scheduler = NanoScheduler::new(4);
let mut task_id = 0u64;
b.iter(|| {
task_id += 1;
// Interleave push and pop
if task_id % 3 == 0 {
scheduler.run_once();
} else {
let priority = match task_id % 4 {
0 => TaskPriority::Critical,
1 => TaskPriority::High,
2 => TaskPriority::Normal,
_ => TaskPriority::Low,
};
let task = create_priority_task(task_id, priority);
black_box(scheduler.schedule(task));
}
});
});
group.finish();
}
// ============================================================================
// Statistics Calculation Benchmarks
// ============================================================================
fn bench_statistics_overhead(c: &mut Criterion) {
let mut group = c.benchmark_group("statistics");
// Stats collection overhead
group.bench_function("stats_collection", |b| {
let mut scheduler = NanoScheduler::new(4);
// Generate some history
for i in 0..100 {
let task = create_compute_task(i, 100);
scheduler.schedule(task);
}
while scheduler.has_pending_tasks() {
scheduler.run_once();
}
b.iter(|| {
black_box(scheduler.get_stats())
});
});
// Stats calculation with varying history sizes
for history_size in [10, 50, 100, 500, 1000].iter() {
group.bench_with_input(
BenchmarkId::new("history", history_size),
history_size,
|b, &size| {
let mut scheduler = NanoScheduler::new(4);
for i in 0..size {
let task = create_compute_task(i as u64, 100);
scheduler.schedule(task);
}
while scheduler.has_pending_tasks() {
scheduler.run_once();
}
b.iter(|| {
black_box(scheduler.get_stats())
});
}
);
}
group.finish();
}
// ============================================================================
// Multi-threaded Scheduling Benchmarks
// ============================================================================
fn bench_multithreaded_scheduling(c: &mut Criterion) {
let mut group = c.benchmark_group("multithreaded");
for num_threads in [1, 2, 4, 8].iter() {
group.bench_with_input(
BenchmarkId::new("threads", num_threads),
num_threads,
|b, &threads| {
b.iter(|| {
let scheduler = Arc::new(Mutex::new(NanoScheduler::new(threads)));
let mut handles = vec![];
for thread_id in 0..threads {
let scheduler = Arc::clone(&scheduler);
let handle = thread::spawn(move || {
for i in 0..100 {
let task = create_compute_task(
thread_id as u64 * 100 + i,
100
);
scheduler.lock().unwrap().schedule(task);
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let mut scheduler = scheduler.lock().unwrap();
while scheduler.has_pending_tasks() {
scheduler.run_once();
}
});
}
);
}
group.finish();
}
fn bench_contention_scenarios(c: &mut Criterion) {
let mut group = c.benchmark_group("contention");
// High contention
group.bench_function("high_contention", |b| {
b.iter(|| {
let scheduler = Arc::new(Mutex::new(NanoScheduler::new(4)));
let mut handles = vec![];
for _ in 0..8 {
let scheduler = Arc::clone(&scheduler);
let handle = thread::spawn(move || {
for i in 0..50 {
let task = create_simple_task(i);
scheduler.lock().unwrap().schedule(task);
thread::yield_now();
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
});
});
// Low contention
group.bench_function("low_contention", |b| {
b.iter(|| {
let scheduler = Arc::new(Mutex::new(NanoScheduler::new(4)));
let mut handles = vec![];
for _ in 0..2 {
let scheduler = Arc::clone(&scheduler);
let handle = thread::spawn(move || {
for i in 0..200 {
let task = create_simple_task(i);
scheduler.lock().unwrap().schedule(task);
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
});
});
group.finish();
}
// ============================================================================
// Criterion Configuration
// ============================================================================
criterion_group! {
name = overhead_benches;
config = Criterion::default()
.sample_size(1000)
.measurement_time(Duration::from_secs(10))
.warm_up_time(Duration::from_secs(3));
targets = bench_schedule_overhead, bench_schedule_with_priorities
}
criterion_group! {
name = latency_benches;
config = Criterion::default()
.sample_size(200)
.measurement_time(Duration::from_secs(10));
targets = bench_execution_latency, bench_execution_throughput
}
criterion_group! {
name = queue_benches;
config = Criterion::default()
.sample_size(500)
.measurement_time(Duration::from_secs(8));
targets = bench_priority_queue_operations
}
criterion_group! {
name = stats_benches;
config = Criterion::default()
.sample_size(500);
targets = bench_statistics_overhead
}
criterion_group! {
name = threading_benches;
config = Criterion::default()
.sample_size(50)
.measurement_time(Duration::from_secs(15));
targets = bench_multithreaded_scheduling, bench_contention_scenarios
}
criterion_main!(
overhead_benches,
latency_benches,
queue_benches,
stats_benches,
threading_benches
);