use std::collections::BTreeMap;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use super::service::ServiceModeLabel;
use super::{Scheduler, SchedulerConfig, dirty, execution, inventory, thread_probe};
use crate::module::ModuleRegistry;
fn new_default_scheduler() -> Scheduler {
Scheduler::new(SchedulerConfig::default(), Arc::new(ModuleRegistry::new()))
.unwrap_or_else(|error| panic!("scheduler starts: {error}"))
}
fn entries_by_service(
scheduler: &Scheduler,
) -> BTreeMap<&'static str, inventory::ServiceInventoryEntry> {
scheduler
.service_inventory()
.into_iter()
.map(|entry| (entry.service, entry))
.collect()
}
#[test]
fn default_profile_pins_as_built_service_inventory() {
assert!(SchedulerConfig::default().distribution.is_none());
let scheduler = new_default_scheduler();
let by_service = entries_by_service(&scheduler);
let labels: Vec<&'static str> = scheduler
.service_inventory()
.iter()
.map(|entry| entry.service)
.collect();
assert_eq!(
labels,
vec![
inventory::DIRTY_CPU,
inventory::DIRTY_IO,
inventory::FILE_IO_RING,
inventory::STANDARD_IO_RING,
inventory::GENERIC_IO_RING,
inventory::DISTRIBUTION,
inventory::READINESS,
],
"the inventory enumerates exactly the service set, in order"
);
let expected_dirty_cpu = num_cpus::get().max(1);
let dirty_cpu = &by_service[inventory::DIRTY_CPU];
assert_eq!(dirty_cpu.mode, ServiceModeLabel::Owned);
assert_eq!(dirty_cpu.actual, expected_dirty_cpu);
assert_eq!(dirty_cpu.configured, expected_dirty_cpu);
let expected_dirty_cpu_names: Vec<String> = (0..expected_dirty_cpu)
.map(|index| format!("dirty-cpu-{index}"))
.collect();
assert_eq!(dirty_cpu.thread_names, expected_dirty_cpu_names);
let dirty_io = &by_service[inventory::DIRTY_IO];
assert_eq!(dirty_io.mode, ServiceModeLabel::Owned);
assert_eq!(dirty_io.actual, dirty::DEFAULT_DIRTY_IO_THREADS);
let expected_dirty_io_names: Vec<String> = (0..dirty::DEFAULT_DIRTY_IO_THREADS)
.map(|index| format!("dirty-io-{index}"))
.collect();
assert_eq!(dirty_io.thread_names, expected_dirty_io_names);
let generic = &by_service[inventory::GENERIC_IO_RING];
assert_eq!(generic.mode, ServiceModeLabel::Disabled);
assert_eq!(generic.actual, 0);
assert!(generic.thread_names.is_empty());
let distribution = &by_service[inventory::DISTRIBUTION];
assert_eq!(distribution.mode, ServiceModeLabel::Disabled);
assert_eq!(distribution.actual, 0);
assert_eq!(distribution.configured, 0);
assert!(distribution.thread_names.is_empty());
assert_eq!(
distribution.instance,
super::service::ServiceInstanceId::DISABLED
);
let readiness = &by_service[inventory::READINESS];
assert_eq!(readiness.mode, ServiceModeLabel::Disabled);
assert_eq!((readiness.configured, readiness.actual), (0, 0));
assert!(readiness.thread_names.is_empty());
assert!(readiness.fd_classes.is_empty());
assert_eq!(
readiness.instance,
super::service::ServiceInstanceId::DISABLED
);
let heartbeat = scheduler
.service_policies()
.into_iter()
.find(|line| line.policy == inventory::HEARTBEAT)
.expect("heartbeat policy line present");
assert_eq!(heartbeat.mode, ServiceModeLabel::Disabled);
assert_eq!(heartbeat.spawned_total, 0);
let file_ring = &by_service[inventory::FILE_IO_RING];
let standard_ring = &by_service[inventory::STANDARD_IO_RING];
assert_eq!(file_ring.mode, ServiceModeLabel::Owned);
assert_eq!(standard_ring.mode, ServiceModeLabel::Owned);
assert_ne!(file_ring.instance, standard_ring.instance);
#[cfg(not(target_os = "linux"))]
{
let expected_file_names: Vec<String> = (0..4)
.map(|index| format!("{}-{index}", crate::io::FILE_IO_RING_THREAD_PREFIX))
.collect();
let expected_standard_names: Vec<String> = (0..4)
.map(|index| format!("{}-{index}", crate::io::STANDARD_IO_RING_THREAD_PREFIX))
.collect();
assert_eq!(file_ring.actual, 4);
assert_eq!(file_ring.thread_names, expected_file_names);
assert_eq!(standard_ring.actual, 4);
assert_eq!(standard_ring.thread_names, expected_standard_names);
assert!(
expected_file_names
.iter()
.all(|name| !expected_standard_names.contains(name)),
"file and standard ring worker names must not collide"
);
}
#[cfg(target_os = "linux")]
{
assert_eq!(file_ring.actual, 0);
assert_eq!(standard_ring.actual, 0);
}
scheduler.shutdown();
}
#[test]
fn distribution_none_disables_the_bundle_and_some_names_both_runtimes() {
let none = new_default_scheduler();
let none_entry = entries_by_service(&none)[inventory::DISTRIBUTION].clone();
assert_eq!(none_entry.mode, ServiceModeLabel::Disabled);
assert_eq!(none_entry.actual, 0);
assert!(none_entry.thread_names.is_empty());
none.shutdown();
let some = Scheduler::new(
SchedulerConfig {
thread_count: Some(1),
distribution: Some(crate::distribution::DistributionConfig::default()),
..SchedulerConfig::default()
},
Arc::new(ModuleRegistry::new()),
)
.unwrap_or_else(|error| panic!("scheduler starts: {error}"));
let some_entry = entries_by_service(&some)[inventory::DISTRIBUTION].clone();
assert_eq!(some_entry.mode, ServiceModeLabel::Owned);
assert_eq!(some_entry.configured, 2);
assert_eq!(some_entry.actual, 2);
assert!(
some_entry
.thread_names
.contains(&crate::distribution::sender::DIST_SEND_THREAD_NAME.to_owned()),
"the sender runtime worker is named in the bundle line: {:?}",
some_entry.thread_names
);
assert!(
some_entry
.thread_names
.contains(&crate::distribution::NET_KERNEL_THREAD_NAME.to_owned()),
"the net-kernel runtime worker is named in the bundle line: {:?}",
some_entry.thread_names
);
assert_ne!(
some_entry.instance,
super::service::ServiceInstanceId::DISABLED
);
let heartbeat = some
.service_policies()
.into_iter()
.find(|line| line.policy == inventory::HEARTBEAT)
.expect("heartbeat policy line present");
assert_eq!(heartbeat.mode, ServiceModeLabel::Owned);
some.shutdown();
}
#[test]
fn disabled_dirty_pools_report_disabled_entries_and_policy() {
let scheduler = Scheduler::new(
SchedulerConfig {
thread_count: Some(1),
dirty_cpu_threads: Some(0),
dirty_io_threads: Some(0),
..SchedulerConfig::default()
},
Arc::new(ModuleRegistry::new()),
)
.unwrap_or_else(|error| panic!("scheduler starts: {error}"));
let by_service = entries_by_service(&scheduler);
for service in [inventory::DIRTY_CPU, inventory::DIRTY_IO] {
let entry = &by_service[service];
assert_eq!(entry.mode, ServiceModeLabel::Disabled, "{service} disabled");
assert_eq!(entry.actual, 0);
assert_eq!(entry.configured, 0);
assert!(entry.thread_names.is_empty());
assert!(entry.fd_classes.is_empty());
assert_eq!(entry.instance, super::service::ServiceInstanceId::DISABLED);
}
let dirty_complete = scheduler
.service_policies()
.into_iter()
.find(|line| line.policy == inventory::DIRTY_COMPLETE)
.expect("dirty-complete policy line present");
assert_eq!(dirty_complete.mode, ServiceModeLabel::Disabled);
assert_eq!(dirty_complete.spawned_total, 0);
scheduler.shutdown();
}
#[test]
fn dirty_complete_is_a_policy_line_not_a_thread_line() {
let scheduler = new_default_scheduler();
let policies = scheduler.service_policies();
let dirty_complete = policies
.iter()
.find(|line| line.policy == inventory::DIRTY_COMPLETE)
.expect("dirty-complete policy line present");
assert_eq!(dirty_complete.mode, ServiceModeLabel::Owned);
assert_eq!(dirty_complete.spawned_total, 0);
for entry in scheduler.service_inventory() {
for name in &entry.thread_names {
assert!(
!name.starts_with("dirty-complete-"),
"transient burst thread must not appear as a thread line: {name}"
);
}
}
scheduler.shutdown();
}
#[test]
fn instance_ids_are_stable_across_inventory_calls() {
let scheduler = new_default_scheduler();
let first = entries_by_service(&scheduler);
let second = entries_by_service(&scheduler);
for (service, entry) in &first {
assert_eq!(entry.instance, second[service].instance);
}
scheduler.shutdown();
}
#[cfg(target_os = "macos")]
#[test]
fn service_inventory_threads_are_all_live_in_the_os_probe() {
let scheduler = new_default_scheduler();
let mut claimed: Vec<String> = scheduler.worker_names().to_vec();
for entry in scheduler.service_inventory() {
claimed.extend(entry.thread_names);
}
let claimed = thread_probe::thread_name_multiset(&claimed);
let mut live = BTreeMap::new();
let mut satisfied = false;
for _ in 0..100 {
live = thread_probe::thread_name_multiset(&thread_probe::process_thread_names());
satisfied = claimed
.iter()
.all(|(name, count)| live.get(name).copied().unwrap_or(0) >= *count);
if satisfied {
break;
}
thread::sleep(Duration::from_millis(10));
}
assert!(
satisfied,
"inventory claims threads absent from the OS probe: claimed={claimed:?} live={live:?}"
);
scheduler.shutdown();
}
#[test]
fn process_wide_aggregate_dedups_shared_instances_once() {
let first = new_default_scheduler();
let second = new_default_scheduler();
let mut combined: Vec<inventory::ServiceInventoryEntry> = Vec::new();
combined.extend(first.service_inventory());
combined.extend(second.service_inventory());
let mut seen = std::collections::BTreeSet::new();
let mut naive_sum = 0usize;
for entry in &combined {
if entry.mode == ServiceModeLabel::Disabled {
continue;
}
naive_sum += entry.actual;
assert!(
seen.insert(entry.instance),
"Owned instance ids must be process-unique"
);
}
assert_eq!(inventory::deduped_thread_aggregate(&combined), naive_sum);
let shared_instance = super::service::ServiceInstanceId::mint();
let shared_entry = |actual: usize| inventory::ServiceInventoryEntry {
service: "shared-ring",
mode: ServiceModeLabel::Shared,
instance: shared_instance,
configured: actual,
actual,
thread_names: Vec::new(),
fd_classes: Vec::new(),
};
let two_reporters = vec![shared_entry(4), shared_entry(4)];
assert_eq!(
inventory::deduped_thread_aggregate(&two_reporters),
4,
"a shared 4-thread ring serving two schedulers bills 4, never 8"
);
let mut with_disabled = two_reporters;
with_disabled.push(inventory::ServiceInventoryEntry {
service: "off",
mode: ServiceModeLabel::Disabled,
instance: super::service::ServiceInstanceId::DISABLED,
configured: 0,
actual: 0,
thread_names: Vec::new(),
fd_classes: Vec::new(),
});
assert_eq!(inventory::deduped_thread_aggregate(&with_disabled), 4);
first.shutdown();
second.shutdown();
}
#[test]
fn post_shutdown_inventory_reports_all_joined_services_as_zero() {
let scheduler = Scheduler::new(
SchedulerConfig {
thread_count: Some(1),
distribution: Some(crate::distribution::DistributionConfig::default()),
..SchedulerConfig::default()
},
Arc::new(ModuleRegistry::new()),
)
.unwrap_or_else(|error| panic!("scheduler starts: {error}"));
let before = entries_by_service(&scheduler);
assert_eq!(
before[inventory::DISTRIBUTION].mode,
ServiceModeLabel::Owned
);
assert_eq!(
before[inventory::DISTRIBUTION].configured,
2,
"owned bundle requests the sender + net-kernel runtimes"
);
scheduler.shutdown();
let after = entries_by_service(&scheduler);
for service in [
inventory::DIRTY_CPU,
inventory::DIRTY_IO,
inventory::FILE_IO_RING,
inventory::STANDARD_IO_RING,
inventory::DISTRIBUTION,
] {
assert_eq!(after[service].actual, 0, "{service} joined at shutdown");
assert_eq!(after[service].configured, before[service].configured);
}
scheduler.shutdown();
let twice = entries_by_service(&scheduler);
assert_eq!(twice[inventory::DISTRIBUTION].actual, 0);
}
#[test]
fn generic_io_configured_is_stable_across_shutdown() {
let scheduler = Scheduler::new(
SchedulerConfig {
thread_count: Some(1),
io: Some(crate::io::RingConfig::default()),
..SchedulerConfig::default()
},
Arc::new(ModuleRegistry::new()),
)
.unwrap_or_else(|error| panic!("scheduler starts: {error}"));
let before = entries_by_service(&scheduler)[inventory::GENERIC_IO_RING].clone();
assert_eq!(before.mode, ServiceModeLabel::Owned);
assert_eq!(
before.actual, before.configured,
"all requested generic-IO threads live at construction"
);
assert!(
before
.thread_names
.contains(&crate::io::bridge::IO_COMPLETION_THREAD_NAME.to_owned()),
"the completion bridge is part of the generic-IO line"
);
scheduler.shutdown();
let after = entries_by_service(&scheduler)[inventory::GENERIC_IO_RING].clone();
assert_eq!(
after.configured, before.configured,
"the construction request must survive shutdown unchanged"
);
assert_eq!(after.actual, 0, "ring joined and bridge stopped");
}
#[test]
fn idle_park_floor_is_pinned_at_five_ms() {
assert_eq!(execution::IDLE_PARK_TIMEOUT, Duration::from_millis(5));
assert_eq!(execution::IDLE_WAKES_PER_SEC_PER_WORKER, 200);
}
#[test]
fn idle_wake_rate_stays_within_signed_bound() {
let scheduler = new_default_scheduler();
let workers = scheduler.worker_names().len();
assert!(workers >= 1, "a scheduler always has at least one worker");
thread::sleep(Duration::from_millis(50));
let window = Duration::from_millis(500);
let start = scheduler.idle_park_count();
let started_at = std::time::Instant::now();
thread::sleep(window);
let parks = scheduler.idle_park_count().saturating_sub(start);
let elapsed = started_at.elapsed();
let wakes_per_sec = parks as f64 / elapsed.as_secs_f64();
let ceiling = 2.0 * execution::IDLE_WAKES_PER_SEC_PER_WORKER as f64 * workers as f64;
assert!(
wakes_per_sec <= ceiling,
"idle wake rate {wakes_per_sec:.1}/s exceeds signed ceiling {ceiling:.1}/s \
for {workers} workers (floor {}ms)",
execution::IDLE_PARK_TIMEOUT.as_millis(),
);
scheduler.shutdown();
}