17 KiB
Nanosecond-Scheduler Integration Strategy
Executive Summary
This document details the integration of the nanosecond-scheduler crate into the Lean Agentic Learning System. The nanosecond-scheduler provides ultra-low-latency, high-precision task scheduling capabilities essential for real-time AI systems, high-frequency decision-making, and time-critical agent operations.
Research Background
Real-Time Scheduling Theory
Definition: Real-time scheduling involves allocating processor time to tasks with strict timing constraints, ensuring deadlines are met [1].
Key Concepts:
-
Hard Real-Time [1]: Missing a deadline is catastrophic
- Medical devices
- Industrial control systems
- High-frequency trading
-
Soft Real-Time [2]: Missing deadlines degrades performance but isn't catastrophic
- Video streaming
- Interactive applications
- AI inference
-
Scheduling Algorithms [3]:
- Rate-Monotonic (RM): Priority based on period
- Earliest Deadline First (EDF): Priority based on deadline
- Least Laxity First (LLF): Priority based on slack time
-
Jitter and Latency [4]:
- Jitter: Variation in execution time
- Latency: Time from trigger to execution
- Worst-Case Execution Time (WCET)
High-Precision Timing
Modern Hardware Capabilities:
- CPU TSC (Time Stamp Counter): Nanosecond precision
- HPET (High Precision Event Timer): ~10ns resolution
- RDTSC instruction: Direct cycle counting
Operating System Support:
- Linux:
CLOCK_MONOTONIC_RAW,SCHED_FIFO - RT-Linux patches for deterministic scheduling
- CPU isolation and affinity
References
[1] Liu, C. L., & Layland, J. W. (1973). "Scheduling algorithms for multiprogramming in a hard-real-time environment." Journal of the ACM, 20(1), 46-61.
[2] Buttazzo, G. C. (2011). "Hard Real-Time Computing Systems." Springer.
[3] Sha, L., et al. (2004). "Real time scheduling theory: A historical perspective." Real-Time Systems, 28(2-3), 101-155.
[4] Kopetz, H. (2011). "Real-Time Systems: Design Principles for Distributed Embedded Applications." Springer.
[5] Brandenburg, B. B., & Anderson, J. H. (2007). "Feather-trace: A light-weight event tracing toolkit." OSPERT 2007.
Integration Architecture
┌─────────────────────────────────────────────────────────────┐
│ Nanosecond-Scheduler Integration │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────┐ ┌─────────────────┐ │
│ │ High Priority │ │ Deadline │ │
│ │ Task Queue │◄──────►│ Manager │ │
│ │ (ns precision)│ │ │ │
│ └────────┬───────┘ └─────────┬───────┘ │
│ │ │ │
│ │ ▼ │
│ ┌────────▼───────┐ ┌─────────────────┐ │
│ │ CPU-Pinned │ │ Latency │ │
│ │ Workers │◄──────►│ Monitor │ │
│ └────────┬───────┘ └─────────────────┘ │
│ │ │
│ ┌────────▼───────┐ ┌─────────────────┐ │
│ │ Agent │ │ Real-Time │ │
│ │ Execution │◄──────►│ Constraints │ │
│ └────────────────┘ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Use Cases
1. High-Frequency Trading Bot
Problem: Execute trades within microsecond time windows.
Solution: Schedule trade decisions with nanosecond precision.
Implementation:
let mut scheduler = NanosecondScheduler::new();
// Schedule high-priority trade execution
scheduler.schedule_with_deadline(
Task::ExecuteTrade(trade),
Deadline::from_nanos(5_000), // 5 microseconds
Priority::Critical,
);
// Ensure execution
scheduler.run_until_idle_with_guarantee();
2. Real-Time Sensor Fusion
Problem: Fuse data from multiple sensors with strict timing requirements.
Solution: Schedule sensor reads and fusion with precise timing.
Implementation:
// Schedule periodic sensor reads
scheduler.schedule_periodic(
Task::ReadSensor(sensor_id),
Period::from_micros(100), // 100μs period
Priority::High,
);
// Schedule fusion with deadline
scheduler.schedule_with_deadline(
Task::FuseSensorData,
Deadline::from_micros(150),
Priority::High,
);
3. Low-Latency Inference
Problem: ML inference must complete within strict latency budget.
Solution: Schedule inference with guaranteed execution time.
Implementation:
// Schedule inference with WCET guarantee
let wcet = estimate_worst_case_execution_time(&model);
scheduler.schedule_with_wcet(
Task::RunInference(model, input),
wcet,
Deadline::from_micros(1000), // 1ms deadline
Priority::High,
);
Technical Specifications
API Design
pub struct NanosecondScheduler {
task_queue: PriorityQueue<ScheduledTask>,
workers: Vec<CpuPinnedWorker>,
latency_monitor: LatencyMonitor,
config: SchedulerConfig,
}
pub struct ScheduledTask {
pub id: TaskId,
pub task: Task,
pub priority: Priority,
pub deadline: Option<Instant>,
pub period: Option<Duration>,
pub wcet: Option<Duration>,
}
pub enum Priority {
Critical, // RT priority 99
High, // RT priority 90
Normal, // RT priority 50
Low, // SCHED_OTHER
}
pub struct SchedulerConfig {
pub enable_cpu_pinning: bool,
pub enable_rt_scheduling: bool,
pub num_workers: usize,
pub latency_budget_ns: u64,
}
impl NanosecondScheduler {
pub fn new(config: SchedulerConfig) -> Result<Self, Error>;
pub fn schedule(
&mut self,
task: Task,
priority: Priority,
) -> TaskHandle;
pub fn schedule_with_deadline(
&mut self,
task: Task,
deadline: Deadline,
priority: Priority,
) -> TaskHandle;
pub fn schedule_periodic(
&mut self,
task: Task,
period: Period,
priority: Priority,
) -> TaskHandle;
pub fn schedule_with_wcet(
&mut self,
task: Task,
wcet: Duration,
deadline: Deadline,
priority: Priority,
) -> TaskHandle;
pub fn cancel(&mut self, handle: TaskHandle) -> Result<(), Error>;
pub fn get_latency_stats(&self) -> LatencyStats;
pub fn wait_for_completion(&self, handle: TaskHandle) -> Result<TaskResult, Error>;
}
Performance Requirements
| Metric | Target | Rationale |
|---|---|---|
| Scheduling overhead | <100ns | Minimal impact |
| Jitter | <1μs | Predictable execution |
| Deadline miss rate | <0.001% | High reliability |
| Context switch latency | <2μs | Fast transitions |
| Wakeup latency | <10μs | Responsive |
Integration Points
1. Agent Decision Scheduling
Location: src/lean_agentic/agent.rs
Enhancement:
pub struct RealTimeAgent {
agent: AgenticLoop,
scheduler: NanosecondScheduler,
latency_budget: Duration,
}
impl RealTimeAgent {
pub async fn make_decision_with_deadline(
&mut self,
context: &Context,
deadline: Deadline,
) -> Result<Action, Error> {
let task = Task::PlanAndAct {
context: context.clone(),
};
let handle = self.scheduler.schedule_with_deadline(
task,
deadline,
Priority::High,
);
// Wait for completion
match self.scheduler.wait_for_completion(handle) {
Ok(TaskResult::Action(action)) => Ok(action),
Err(e) => Err(Error::DeadlineMissed(e)),
}
}
}
2. Stream Processing with Latency Guarantees
Location: src/lean_agentic/learning.rs
Enhancement:
impl StreamLearner {
pub fn process_stream_with_latency_guarantee(
&mut self,
stream: impl Stream<Item = Message>,
max_latency: Duration,
) -> impl Stream<Item = ProcessingResult> {
let scheduler = NanosecondScheduler::new(config);
stream.map(move |message| {
let deadline = Instant::now() + max_latency;
let handle = scheduler.schedule_with_deadline(
Task::ProcessMessage(message),
deadline,
Priority::High,
);
scheduler.wait_for_completion(handle)
})
}
}
3. Knowledge Graph Updates with Priority
Location: src/lean_agentic/knowledge.rs
Enhancement:
impl KnowledgeGraph {
pub fn update_with_priority(
&mut self,
entities: Vec<Entity>,
priority: Priority,
) -> TaskHandle {
self.scheduler.schedule(
Task::UpdateKnowledgeGraph { entities },
priority,
)
}
pub fn critical_update(
&mut self,
entity: Entity,
deadline: Deadline,
) -> Result<(), Error> {
let handle = self.scheduler.schedule_with_deadline(
Task::UpdateEntity { entity },
deadline,
Priority::Critical,
);
self.scheduler.wait_for_completion(handle)?;
Ok(())
}
}
Implementation Phases
Phase 1: Core Scheduler (Week 1)
- Implement priority queue
- Add CPU pinning support
- Create RT scheduling integration
- Implement basic task execution
- Write unit tests
Phase 2: Deadline Management (Week 2)
- Add deadline tracking
- Implement EDF scheduling
- Create WCET estimation
- Add deadline miss detection
- Write integration tests
Phase 3: Latency Monitoring (Week 3)
- Implement latency tracking
- Add jitter measurement
- Create performance metrics
- Add alerting for violations
- Benchmark performance
Phase 4: Advanced Features (Week 4)
- Add periodic task support
- Implement admission control
- Create task dependencies
- Add load balancing
- Write documentation
Benchmarking Strategy
Benchmark Suite
#[bench]
fn bench_schedule_overhead(b: &mut Bencher) {
let mut scheduler = NanosecondScheduler::new(default_config());
let task = Task::Noop;
b.iter(|| {
scheduler.schedule(task.clone(), Priority::Normal)
});
}
#[bench]
fn bench_deadline_scheduling(b: &mut Bencher) {
let mut scheduler = NanosecondScheduler::new(default_config());
let deadline = Deadline::from_micros(100);
b.iter(|| {
let handle = scheduler.schedule_with_deadline(
Task::Compute(|_| 42),
deadline,
Priority::High,
);
scheduler.wait_for_completion(handle)
});
}
#[bench]
fn bench_periodic_tasks(b: &mut Bencher) {
let mut scheduler = NanosecondScheduler::new(default_config());
b.iter(|| {
scheduler.schedule_periodic(
Task::Noop,
Period::from_micros(100),
Priority::Normal,
)
});
}
Latency Measurement
#[test]
fn measure_scheduling_latency() {
let mut scheduler = NanosecondScheduler::new(config);
let mut latencies = Vec::new();
for _ in 0..10000 {
let start = Instant::now();
let handle = scheduler.schedule(
Task::Noop,
Priority::High,
);
scheduler.wait_for_completion(handle).unwrap();
let latency = start.elapsed();
latencies.push(latency);
}
let stats = LatencyStats::from_samples(&latencies);
assert!(stats.p99() < Duration::from_micros(10));
assert!(stats.max() < Duration::from_micros(50));
println!("Scheduling latency:");
println!(" p50: {:?}", stats.p50());
println!(" p99: {:?}", stats.p99());
println!(" max: {:?}", stats.max());
}
Platform-Specific Optimizations
Linux
#[cfg(target_os = "linux")]
fn configure_rt_scheduling() -> Result<(), Error> {
use libc::{sched_setscheduler, sched_param, SCHED_FIFO};
let param = sched_param {
sched_priority: 99,
};
unsafe {
if sched_setscheduler(0, SCHED_FIFO, ¶m) != 0 {
return Err(Error::RtSchedulingFailed);
}
}
// Pin to isolated CPU
pin_to_cpu(7)?;
Ok(())
}
fn pin_to_cpu(cpu: usize) -> Result<(), Error> {
use libc::{cpu_set_t, sched_setaffinity, CPU_SET, CPU_ZERO};
unsafe {
let mut cpu_set: cpu_set_t = std::mem::zeroed();
CPU_ZERO(&mut cpu_set);
CPU_SET(cpu, &mut cpu_set);
if sched_setaffinity(0, std::mem::size_of::<cpu_set_t>(), &cpu_set) != 0 {
return Err(Error::CpuPinningFailed);
}
}
Ok(())
}
Windows
#[cfg(target_os = "windows")]
fn configure_high_priority() -> Result<(), Error> {
use winapi::um::processthreadsapi::{
GetCurrentThread, SetThreadPriority
};
use winapi::um::winbase::THREAD_PRIORITY_TIME_CRITICAL;
unsafe {
let thread = GetCurrentThread();
if SetThreadPriority(thread, THREAD_PRIORITY_TIME_CRITICAL) == 0 {
return Err(Error::PrioritySettingFailed);
}
}
Ok(())
}
Success Criteria
- Scheduling overhead < 100ns (p99)
- Jitter < 1μs (p99)
- Deadline miss rate < 0.001%
- Context switch latency < 2μs
- Support for 10,000+ tasks/second
- Zero priority inversions in tests
- Full platform support (Linux, macOS, Windows)
Safety and Error Handling
Deadline Misses
pub enum DeadlineViolation {
SoftMiss { actual: Duration, expected: Duration },
HardMiss { actual: Duration, expected: Duration },
}
impl NanosecondScheduler {
fn handle_deadline_miss(&mut self, task: &ScheduledTask, violation: DeadlineViolation) {
match violation {
DeadlineViolation::SoftMiss { actual, expected } => {
tracing::warn!(
task_id = ?task.id,
actual_ns = actual.as_nanos(),
expected_ns = expected.as_nanos(),
"Soft deadline missed"
);
}
DeadlineViolation::HardMiss { actual, expected } => {
tracing::error!(
task_id = ?task.id,
actual_ns = actual.as_nanos(),
expected_ns = expected.as_nanos(),
"Hard deadline missed - critical violation"
);
self.trigger_emergency_protocol(task);
}
}
}
}
Monitoring Dashboard
pub struct LatencyMonitor {
samples: RingBuffer<Duration>,
violations: Vec<DeadlineViolation>,
stats: LatencyStats,
}
impl LatencyMonitor {
pub fn report(&self) -> MonitoringReport {
MonitoringReport {
p50_latency: self.stats.p50(),
p99_latency: self.stats.p99(),
max_latency: self.stats.max(),
deadline_miss_rate: self.calculate_miss_rate(),
jitter: self.calculate_jitter(),
utilization: self.calculate_utilization(),
}
}
}
Future Enhancements
- GPU Scheduling: Extend to CUDA/OpenCL tasks
- Distributed Scheduling: Coordinate across machines
- Energy-Aware: Optimize for power consumption
- Predictive Scheduling: ML-based WCET prediction
- Formal Verification: Prove schedulability
References
[1] Liu & Layland (1973). Scheduling algorithms for hard-real-time. [2] Buttazzo (2011). Hard Real-Time Computing Systems. [3] Sha et al. (2004). Real time scheduling theory. [4] Kopetz (2011). Real-Time Systems. [5] Brandenburg & Anderson (2007). Feather-trace.
Appendix A: Example Usage
use midstream::nanosecond_scheduler::*;
// Create scheduler with RT configuration
let config = SchedulerConfig {
enable_cpu_pinning: true,
enable_rt_scheduling: true,
num_workers: 4,
latency_budget_ns: 1_000, // 1μs
};
let mut scheduler = NanosecondScheduler::new(config)?;
// Schedule high-priority task with deadline
let handle = scheduler.schedule_with_deadline(
Task::ProcessCriticalEvent(event),
Deadline::from_micros(100),
Priority::Critical,
);
// Wait for completion
match scheduler.wait_for_completion(handle) {
Ok(result) => println!("Completed: {:?}", result),
Err(Error::DeadlineMissed(..)) => eprintln!("Deadline violated!"),
}
// Get performance statistics
let stats = scheduler.get_latency_stats();
println!("Latency p99: {:?}", stats.p99());