use core::sync::atomic::{AtomicU64, Ordering};
const TASK_CLOCK_EVENT_IRQ_BUDGET: usize = 64;
static TASK_TIMER_IRQ_COUNT: AtomicU64 = AtomicU64::new(0);
#[cfg(feature = "qperf-metrics")]
static SCHEDULER_IPI_SEND_COUNT: AtomicU64 = AtomicU64::new(0);
#[cfg(feature = "qperf-metrics")]
static SCHEDULER_IPI_CONSUME_COUNT: AtomicU64 = AtomicU64::new(0);
#[cfg(feature = "qperf-metrics")]
static IRQ_RETURN_SCHEDULER_CONTINUATION_COUNT: AtomicU64 = AtomicU64::new(0);
#[cfg(feature = "qperf-metrics")]
static IRQ_RETURN_SCHEDULER_WINDOW_COUNT: AtomicU64 = AtomicU64::new(0);
#[cfg(feature = "qperf-metrics")]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct QperfRuntimeSchedulerMetricsSnapshot {
pub task: ax_task::diagnostics::QperfSchedulerMetricsSnapshot,
pub active_mm_same_activations: u64,
pub active_mm_different_activations: u64,
pub active_mm_kernel_lazy_activations: u64,
pub active_mm_hardware_root_writes: u64,
pub active_mm_lease_activations: u64,
pub active_mm_lease_deactivations: u64,
pub active_mm_reclaim_ready: u64,
pub active_mm_reclaim_destroyed: u64,
pub scheduler_ipi_sends: u64,
pub scheduler_ipi_consumes: u64,
pub clockevent_irqs: u64,
pub irq_return_scheduler_continuations: u64,
pub irq_return_scheduler_windows: u64,
}
pub fn timer_irq_count() -> u64 {
TASK_TIMER_IRQ_COUNT.load(Ordering::Relaxed)
}
#[cfg(feature = "qperf-metrics")]
pub fn qperf_runtime_scheduler_metrics_snapshot() -> QperfRuntimeSchedulerMetricsSnapshot {
let active_mm = super::address_space::qperf_address_space_metrics_snapshot();
QperfRuntimeSchedulerMetricsSnapshot {
task: ax_task::diagnostics::qperf_scheduler_metrics_snapshot(),
active_mm_same_activations: active_mm.same_activations,
active_mm_different_activations: active_mm.different_activations,
active_mm_kernel_lazy_activations: active_mm.kernel_lazy_activations,
active_mm_hardware_root_writes: active_mm.hardware_root_writes,
active_mm_lease_activations: active_mm.lease_activations,
active_mm_lease_deactivations: active_mm.lease_deactivations,
active_mm_reclaim_ready: active_mm.reclaim_ready,
active_mm_reclaim_destroyed: active_mm.reclaim_destroyed,
scheduler_ipi_sends: SCHEDULER_IPI_SEND_COUNT.load(Ordering::Relaxed),
scheduler_ipi_consumes: SCHEDULER_IPI_CONSUME_COUNT.load(Ordering::Relaxed),
clockevent_irqs: timer_irq_count(),
irq_return_scheduler_continuations: IRQ_RETURN_SCHEDULER_CONTINUATION_COUNT
.load(Ordering::Relaxed),
irq_return_scheduler_windows: IRQ_RETURN_SCHEDULER_WINDOW_COUNT.load(Ordering::Relaxed),
}
}
#[cfg(feature = "qperf-metrics")]
pub(crate) fn record_irq_return_scheduler_continuation() {
IRQ_RETURN_SCHEDULER_CONTINUATION_COUNT.fetch_add(1, Ordering::Relaxed);
}
#[cfg(feature = "qperf-metrics")]
pub(crate) fn record_irq_return_scheduler_window() {
IRQ_RETURN_SCHEDULER_WINDOW_COUNT.fetch_add(1, Ordering::Relaxed);
}
#[cfg(all(feature = "qperf-metrics", any(feature = "ipi", feature = "wake-ipi")))]
pub(crate) fn record_scheduler_ipi_send() {
SCHEDULER_IPI_SEND_COUNT.fetch_add(1, Ordering::Relaxed);
}
#[cfg(all(feature = "qperf-metrics", any(feature = "ipi", feature = "wake-ipi")))]
pub(crate) fn record_scheduler_ipi_consume() {
SCHEDULER_IPI_CONSUME_COUNT.fetch_add(1, Ordering::Relaxed);
}
pub(crate) fn on_clock_event(
now: ax_task::time::MonotonicInstant,
scheduler_event: ax_task::runtime::service::ClaimedSchedulerDeadlines,
) -> ax_task::runtime::service::TaskClockEventOutcome {
TASK_TIMER_IRQ_COUNT.fetch_add(1, Ordering::Relaxed);
account_clock_event(now, scheduler_event)
}
fn account_clock_event(
now: ax_task::time::MonotonicInstant,
scheduler_event: ax_task::runtime::service::ClaimedSchedulerDeadlines,
) -> ax_task::runtime::service::TaskClockEventOutcome {
match ax_task::runtime::service::on_clock_event(
now,
TASK_CLOCK_EVENT_IRQ_BUDGET,
scheduler_event,
) {
Ok(outcome) => outcome,
Err(error) => panic!("task clockevent accounting failed: {error}"),
}
}
pub(crate) fn publish_scheduler_tick(
stamp: ax_task::runtime::service::SchedulerTickStamp,
mode: ax_task::runtime::service::SchedulerTickMode,
tick_ns: u64,
) {
ax_task::runtime::service::publish_scheduler_tick(stamp, mode, tick_ns)
.unwrap_or_else(|error| panic!("scheduler tick publication failed: {error}"));
}