ax_runtime/thread/
scheduler_events.rs1use core::sync::atomic::{AtomicU64, Ordering};
4
5const TASK_CLOCK_EVENT_IRQ_BUDGET: usize = 64;
6
7static TASK_TIMER_IRQ_COUNT: AtomicU64 = AtomicU64::new(0);
8#[cfg(feature = "qperf-metrics")]
9static SCHEDULER_IPI_SEND_COUNT: AtomicU64 = AtomicU64::new(0);
10#[cfg(feature = "qperf-metrics")]
11static SCHEDULER_IPI_CONSUME_COUNT: AtomicU64 = AtomicU64::new(0);
12#[cfg(feature = "qperf-metrics")]
13static IRQ_RETURN_SCHEDULER_CONTINUATION_COUNT: AtomicU64 = AtomicU64::new(0);
14#[cfg(feature = "qperf-metrics")]
15static IRQ_RETURN_SCHEDULER_WINDOW_COUNT: AtomicU64 = AtomicU64::new(0);
16
17#[cfg(feature = "qperf-metrics")]
19#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
20pub struct QperfRuntimeSchedulerMetricsSnapshot {
21 pub task: ax_task::diagnostics::QperfSchedulerMetricsSnapshot,
22 pub active_mm_same_activations: u64,
23 pub active_mm_different_activations: u64,
24 pub active_mm_kernel_lazy_activations: u64,
25 pub active_mm_hardware_root_writes: u64,
26 pub active_mm_lease_activations: u64,
27 pub active_mm_lease_deactivations: u64,
28 pub active_mm_reclaim_ready: u64,
29 pub active_mm_reclaim_destroyed: u64,
30 pub scheduler_ipi_sends: u64,
31 pub scheduler_ipi_consumes: u64,
32 pub clockevent_irqs: u64,
33 pub irq_return_scheduler_continuations: u64,
34 pub irq_return_scheduler_windows: u64,
35}
36
37pub fn timer_irq_count() -> u64 {
39 TASK_TIMER_IRQ_COUNT.load(Ordering::Relaxed)
40}
41
42#[cfg(feature = "qperf-metrics")]
44pub fn qperf_runtime_scheduler_metrics_snapshot() -> QperfRuntimeSchedulerMetricsSnapshot {
45 let active_mm = super::address_space::qperf_address_space_metrics_snapshot();
46 QperfRuntimeSchedulerMetricsSnapshot {
47 task: ax_task::diagnostics::qperf_scheduler_metrics_snapshot(),
48 active_mm_same_activations: active_mm.same_activations,
49 active_mm_different_activations: active_mm.different_activations,
50 active_mm_kernel_lazy_activations: active_mm.kernel_lazy_activations,
51 active_mm_hardware_root_writes: active_mm.hardware_root_writes,
52 active_mm_lease_activations: active_mm.lease_activations,
53 active_mm_lease_deactivations: active_mm.lease_deactivations,
54 active_mm_reclaim_ready: active_mm.reclaim_ready,
55 active_mm_reclaim_destroyed: active_mm.reclaim_destroyed,
56 scheduler_ipi_sends: SCHEDULER_IPI_SEND_COUNT.load(Ordering::Relaxed),
57 scheduler_ipi_consumes: SCHEDULER_IPI_CONSUME_COUNT.load(Ordering::Relaxed),
58 clockevent_irqs: timer_irq_count(),
59 irq_return_scheduler_continuations: IRQ_RETURN_SCHEDULER_CONTINUATION_COUNT
60 .load(Ordering::Relaxed),
61 irq_return_scheduler_windows: IRQ_RETURN_SCHEDULER_WINDOW_COUNT.load(Ordering::Relaxed),
62 }
63}
64
65#[cfg(feature = "qperf-metrics")]
66pub(crate) fn record_irq_return_scheduler_continuation() {
67 IRQ_RETURN_SCHEDULER_CONTINUATION_COUNT.fetch_add(1, Ordering::Relaxed);
68}
69
70#[cfg(feature = "qperf-metrics")]
71pub(crate) fn record_irq_return_scheduler_window() {
72 IRQ_RETURN_SCHEDULER_WINDOW_COUNT.fetch_add(1, Ordering::Relaxed);
73}
74
75#[cfg(all(feature = "qperf-metrics", any(feature = "ipi", feature = "wake-ipi")))]
76pub(crate) fn record_scheduler_ipi_send() {
77 SCHEDULER_IPI_SEND_COUNT.fetch_add(1, Ordering::Relaxed);
78}
79
80#[cfg(all(feature = "qperf-metrics", any(feature = "ipi", feature = "wake-ipi")))]
81pub(crate) fn record_scheduler_ipi_consume() {
82 SCHEDULER_IPI_CONSUME_COUNT.fetch_add(1, Ordering::Relaxed);
83}
84
85pub(crate) fn on_clock_event(
87 now: ax_task::time::MonotonicInstant,
88 scheduler_event: ax_task::runtime::service::ClaimedSchedulerDeadlines,
89) -> ax_task::runtime::service::TaskClockEventOutcome {
90 TASK_TIMER_IRQ_COUNT.fetch_add(1, Ordering::Relaxed);
91 account_clock_event(now, scheduler_event)
92}
93fn account_clock_event(
94 now: ax_task::time::MonotonicInstant,
95 scheduler_event: ax_task::runtime::service::ClaimedSchedulerDeadlines,
96) -> ax_task::runtime::service::TaskClockEventOutcome {
97 match ax_task::runtime::service::on_clock_event(
98 now,
99 TASK_CLOCK_EVENT_IRQ_BUDGET,
100 scheduler_event,
101 ) {
102 Ok(outcome) => outcome,
103 Err(error) => panic!("task clockevent accounting failed: {error}"),
104 }
105}
106pub(crate) fn publish_scheduler_tick(
107 stamp: ax_task::runtime::service::SchedulerTickStamp,
108 mode: ax_task::runtime::service::SchedulerTickMode,
109 tick_ns: u64,
110) {
111 ax_task::runtime::service::publish_scheduler_tick(stamp, mode, tick_ns)
112 .unwrap_or_else(|error| panic!("scheduler tick publication failed: {error}"));
113}