Skip to main content

trueno/brick/patterns/
wake_skip_state.rs

1//! AWP-09: Smart Payload Wake Skip
2
3/// Wake skip optimization state.
4///
5/// Tracks whether a wakeup is actually needed or can be skipped
6/// to avoid unnecessary context switches.
7#[derive(Debug, Default)]
8pub struct WakeSkipState {
9    /// Number of items pending
10    pending_items: usize,
11    /// Whether there's a registered waker
12    has_waker: bool,
13    /// Last poll had work to do
14    last_poll_had_work: bool,
15    /// Consecutive empty polls
16    empty_poll_count: u32,
17    /// Threshold for skipping wakes
18    skip_threshold: u32,
19}
20
21impl WakeSkipState {
22    /// Create with skip threshold.
23    pub fn new(skip_threshold: u32) -> Self {
24        Self {
25            pending_items: 0,
26            has_waker: false,
27            last_poll_had_work: false,
28            empty_poll_count: 0,
29            skip_threshold,
30        }
31    }
32
33    /// Register that a waker exists.
34    pub fn register_waker(&mut self) {
35        self.has_waker = true;
36    }
37
38    /// Clear waker registration.
39    pub fn clear_waker(&mut self) {
40        self.has_waker = false;
41    }
42
43    /// Add pending items.
44    pub fn add_pending(&mut self, count: usize) {
45        self.pending_items += count;
46    }
47
48    /// Remove pending items.
49    pub fn remove_pending(&mut self, count: usize) {
50        self.pending_items = self.pending_items.saturating_sub(count);
51    }
52
53    /// Record poll result.
54    pub fn record_poll(&mut self, had_work: bool) {
55        self.last_poll_had_work = had_work;
56        if had_work {
57            self.empty_poll_count = 0;
58        } else {
59            self.empty_poll_count += 1;
60        }
61    }
62
63    /// Determine if wake should be skipped.
64    #[must_use]
65    pub fn should_skip_wake(&self) -> bool {
66        // Skip if:
67        // 1. No waker registered
68        // 2. Already has pending items (will be polled anyway)
69        // 3. Had recent empty polls (probably will be empty again)
70        if !self.has_waker {
71            return true;
72        }
73        if self.pending_items > 0 && self.last_poll_had_work {
74            return true; // Already has work queued
75        }
76        if self.empty_poll_count >= self.skip_threshold {
77            return true; // Likely to be empty again
78        }
79        false
80    }
81
82    /// Check if wake is needed.
83    #[must_use]
84    pub fn needs_wake(&self) -> bool {
85        !self.should_skip_wake() && self.pending_items > 0
86    }
87
88    /// Get pending count.
89    #[must_use]
90    pub fn pending(&self) -> usize {
91        self.pending_items
92    }
93
94    /// Reset empty poll tracking (after successful wake).
95    pub fn reset_tracking(&mut self) {
96        self.empty_poll_count = 0;
97    }
98}