-
Notifications
You must be signed in to change notification settings - Fork 126
feat(axtask): add work-stealing load balancing for SMP #1016
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
b97948b
4bcde68
70a2167
2769b4e
34f5ba3
754a8aa
732fb36
f2a3678
2f401df
5f6432b
f8783d6
8b55fb1
07326e6
df95e32
3259fda
2840e69
585fba4
bc5c352
73ac5e0
85b54f6
6acc246
cbaf784
c86f162
644c1a3
d2e4e21
fb2e36e
1484008
9e9f145
b664dba
1a1ffa1
22d998e
6206c8a
14bdf34
ae3ed2c
38be233
05183fa
0922b7a
c7219f6
1173159
e3b9b7f
7727677
2e229b7
47c9fb5
bb4b4f0
7c9cfe1
18169f1
4d749da
a0f6f84
844acc9
75416e5
494f6d8
ed38ca4
98211ce
2f3a943
3b553ed
60bf0dc
b081e29
22530ce
20db4db
d68b534
83f48c4
146e1c9
ecf535b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -54,10 +54,35 @@ impl<T> BaseScheduler for FifoScheduler<T> { | |
| self.ready_queue.pop_front() | ||
| } | ||
|
|
||
| fn pick_next_task_matching( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [建议] 例如 虽然在 work-stealing 场景下影响有限(大部分任务匹配即返回),但作为公开 trait 方法,重排可能引入调度公平性问题。 建议改用 cursor/索引遍历 + 原位删除,或者在 trait doc 中说明 参考 CFS 实现(BTreeMap::remove 不改变排序),FifoScheduler/RRScheduler 也可以用类似思路:遍历 VecDeque 找到匹配项索引,用
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [建议] SCHED 语义注意: 经验证当前实现正确保持 FIFO 顺序: |
||
| &mut self, | ||
| predicate: impl Fn(&Self::SchedItem) -> bool, | ||
| ) -> Option<Self::SchedItem> { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔍 [建议]
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [建议/非阻塞] alloc::vec::Vec 暂存在 no_std 内核中会触发堆分配。虽然 try_steal 非热路径,后续可考虑用 cursor API 原地遍历。当前实现语义正确,不作为合入阻塞条件。 |
||
| let mut cursor = self.ready_queue.cursor_front_mut(); | ||
| loop { | ||
| let task_ptr = cursor.current_ptr()?; | ||
| let matched = unsafe { | ||
| Arc::increment_strong_count(task_ptr.as_ptr()); | ||
| let task = Arc::from_raw(task_ptr.as_ptr()); | ||
| let matched = predicate(&task); | ||
| drop(task); | ||
| matched | ||
| }; | ||
| if matched { | ||
| return cursor.remove_current(); | ||
| } | ||
| cursor.move_next(); | ||
| } | ||
| } | ||
|
|
||
| fn put_prev_task(&mut self, prev: Self::SchedItem, _preempt: bool) { | ||
| self.ready_queue.push_back(prev); | ||
| } | ||
|
|
||
| fn is_empty(&self) -> bool { | ||
| self.ready_queue.is_empty() | ||
| } | ||
|
|
||
| fn task_tick(&mut self, _current: &Self::SchedItem) -> bool { | ||
| false // no reschedule | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,6 +41,17 @@ pub trait BaseScheduler { | |
| /// Returns [`None`] if there is not runnable task. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔍 [建议] |
||
| fn pick_next_task(&mut self) -> Option<Self::SchedItem>; | ||
|
|
||
| /// Picks the next task matching a predicate, removing it from the | ||
| /// scheduler. Returns [`None`] if no matching task exists. | ||
| /// | ||
| /// The predicate check and removal happen atomically within a single | ||
| /// lock acquisition — the task is never left in an "out of queue" | ||
| /// window observable by other CPUs. | ||
| fn pick_next_task_matching( | ||
| &mut self, | ||
| predicate: impl Fn(&Self::SchedItem) -> bool, | ||
| ) -> Option<Self::SchedItem>; | ||
|
|
||
| /// Puts the previous task back to the scheduler. The previous task is | ||
| /// usually placed at the end of the ready queue, making it less likely | ||
| /// to be re-scheduled. | ||
|
|
@@ -58,4 +69,11 @@ pub trait BaseScheduler { | |
|
|
||
| /// set priority for a task | ||
| fn set_priority(&mut self, task: &Self::SchedItem, prio: isize) -> bool; | ||
|
|
||
| /// Returns `true` if the ready queue has no runnable tasks. | ||
| /// | ||
| /// Used as a fast, racy heuristic (without holding the lock) to skip | ||
| /// empty queues before attempting work-stealing — mirrors Linux's | ||
| /// `src_rq->nr_running > 1` check in `idle_balance()`. | ||
| fn is_empty(&self) -> bool; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -300,6 +300,25 @@ impl<G: BaseGuard, T: ?Sized> BaseSpinLock<G, T> { | |
| // there's no need to lock the inner mutex. | ||
| unsafe { &mut *self.data.get() } | ||
| } | ||
|
|
||
| /// Returns a shared reference to the inner data without acquiring the | ||
| /// lock. The data may be concurrently modified — the result is stale | ||
| /// the instant this returns. Only use for racy heuristics analoguous | ||
| /// to Linux's `src_rq->nr_running > 1` check. | ||
| /// | ||
| /// This is a shared (`&`) reference rather than `&mut`, so it does not | ||
| /// carry `noalias` — the compiler will not assume exclusivity and will | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [建议 - 非阻塞] 建议在 SAFETY 注释中更明确地说明:
|
||
| /// not miscompile concurrent accesses to the same data from other CPUs. | ||
| /// | ||
| /// # Safety | ||
| /// | ||
| /// The caller must ensure that no other thread is concurrently writing | ||
| /// to the inner data in a way that would cause a data race for the | ||
| /// specific fields being read. | ||
| #[inline(always)] | ||
| pub unsafe fn data_unchecked(&self) -> &T { | ||
| unsafe { &*self.data.get() } | ||
| } | ||
| } | ||
|
|
||
| impl<G: BaseGuard, T: Default> Default for BaseSpinLock<G, T> { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.