grate-limiter 0.1.1

Anticipatory rate-limit orchestration engine for multi-provider systems. Predict limits before providers enforce them.
Documentation
use criterion::{Criterion, black_box, criterion_group, criterion_main};
use grate_limiter::{
    CapabilityConfig, CapabilityProvider, Dimension, EngineConfig, GrateLimiter, MockClock,
    Observation, Outcome, ProviderConfig, QuotaConfig, StatusClass, Usage, Window,
};
use std::sync::Arc;

fn setup_engine(provider_count: usize) -> (GrateLimiter, Arc<MockClock>) {
    let clock = Arc::new(MockClock::new());
    let config = EngineConfig::default().with_clock(clock.clone());
    let engine = GrateLimiter::new(config);

    let mut cap_providers = Vec::with_capacity(provider_count);
    for i in 0..provider_count {
        let name = format!("provider-{i}");
        engine.upsert_provider(ProviderConfig {
            name: name.clone(),
            quotas: vec![QuotaConfig {
                dimension: Dimension::Requests,
                limit: 1000,
                window: Some(Window::Minute),
            }],
            priority: (provider_count - i) as u16,
            weight: 1.0,
            cooldown_seconds: 30,
        });
        cap_providers.push(CapabilityProvider {
            provider: name,
            priority: (provider_count - i) as u16,
        });
    }

    engine.upsert_capability(CapabilityConfig {
        name: "bench-cap".into(),
        providers: cap_providers,
    });

    (engine, clock)
}

fn bench_select(c: &mut Criterion) {
    let mut group = c.benchmark_group("select");

    for count in [2, 10, 50, 100] {
        let (engine, _clock) = setup_engine(count);
        group.bench_function(format!("{count}_providers"), |b| {
            b.iter(|| black_box(engine.select("bench-cap")))
        });
    }

    group.finish();
}

fn bench_observe(c: &mut Criterion) {
    let mut group = c.benchmark_group("observe");

    let (engine, _clock) = setup_engine(10);
    group.bench_function("single_observation", |b| {
        b.iter(|| {
            black_box(engine.observe(Observation {
                provider: "provider-0".into(),
                capability: Some("bench-cap".into()),
                usage: Usage {
                    requests: 1,
                    tokens: Some(100),
                    ..Default::default()
                },
                outcome: Outcome {
                    status: StatusClass::Success,
                    latency_ms: 100,
                },
            }))
        })
    });

    group.finish();
}

fn bench_mixed_workload(c: &mut Criterion) {
    let mut group = c.benchmark_group("mixed");

    let (engine, clock) = setup_engine(10);
    group.bench_function("select_observe_cycle", |b| {
        b.iter(|| {
            let decision = engine.select("bench-cap").unwrap();
            clock.advance_ms(1);
            engine
                .observe(Observation {
                    provider: decision.provider,
                    capability: Some("bench-cap".into()),
                    usage: Usage {
                        requests: 1,
                        ..Default::default()
                    },
                    outcome: Outcome {
                        status: StatusClass::Success,
                        latency_ms: 50,
                    },
                })
                .unwrap();
        })
    });

    group.finish();
}

criterion_group!(benches, bench_select, bench_observe, bench_mixed_workload);
criterion_main!(benches);