mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 11:16:47 +00:00
多核负载均衡(#193)
* feat(sched):CPU负载检测初步实现 * fix(smp):调整smp中的apic的头文件声明 * fix(smp):简单的负载均衡算法实现 * fix(sched):抽离负载均衡方法 * fix(sched):修改rt中的运行队列bug,调整负载均衡逻辑 * fix(process):移除无用测试代码 * reformat code
This commit is contained in:
parent
ef9f9732b0
commit
1d48996375
@ -36,3 +36,4 @@
|
|||||||
#include <sched/sched.h>
|
#include <sched/sched.h>
|
||||||
#include <time/sleep.h>
|
#include <time/sleep.h>
|
||||||
#include <mm/mm-types.h>
|
#include <mm/mm-types.h>
|
||||||
|
#include <smp/smp.h>
|
||||||
|
@ -7,7 +7,6 @@ pub mod atomic;
|
|||||||
pub mod list;
|
pub mod list;
|
||||||
pub mod lockref;
|
pub mod lockref;
|
||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
|
pub mod rwlock;
|
||||||
pub mod semaphore;
|
pub mod semaphore;
|
||||||
pub mod wait_queue;
|
pub mod wait_queue;
|
||||||
pub mod rwlock;
|
|
||||||
|
|
||||||
|
@ -165,9 +165,10 @@ impl<T> RwLock<T> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
/// @brief 尝试获得WRITER守卫
|
/// @brief 尝试获得WRITER守卫
|
||||||
pub fn try_write(&self) -> Option<RwLockWriteGuard<T>> {
|
pub fn try_write(&self) -> Option<RwLockWriteGuard<T>> {
|
||||||
let res:bool = self
|
let res: bool = self
|
||||||
.lock
|
.lock
|
||||||
.compare_exchange(0, WRITER, Ordering::Acquire, Ordering::Relaxed).is_ok();
|
.compare_exchange(0, WRITER, Ordering::Acquire, Ordering::Relaxed)
|
||||||
|
.is_ok();
|
||||||
//只有lock大小为0的时候能获得写者守卫
|
//只有lock大小为0的时候能获得写者守卫
|
||||||
if res {
|
if res {
|
||||||
return Some(RwLockWriteGuard {
|
return Some(RwLockWriteGuard {
|
||||||
@ -443,5 +444,3 @@ impl<'rwlock, T> Drop for RwLockWriteGuard<'rwlock, T> {
|
|||||||
.fetch_and(!(WRITER | UPGRADED), Ordering::Release);
|
.fetch_and(!(WRITER | UPGRADED), Ordering::Release);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,6 +103,10 @@ impl CFSQueue {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// 获取运行队列的长度
|
||||||
|
pub fn get_cfs_queue_size(&mut self) -> usize {
|
||||||
|
return self.queue.len();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief CFS调度器类
|
/// @brief CFS调度器类
|
||||||
@ -172,6 +176,10 @@ impl SchedulerCFS {
|
|||||||
// kdebug!("set cpu idle: id={}", cpu_id);
|
// kdebug!("set cpu idle: id={}", cpu_id);
|
||||||
self.cpu_queue[cpu_id].idle_pcb = pcb;
|
self.cpu_queue[cpu_id].idle_pcb = pcb;
|
||||||
}
|
}
|
||||||
|
/// 获取某个cpu的运行队列中的进程数
|
||||||
|
pub fn get_cfs_queue_len(&mut self, cpu_id: u32) -> usize {
|
||||||
|
return self.cpu_queue[cpu_id as usize].get_cfs_queue_size();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scheduler for SchedulerCFS {
|
impl Scheduler for SchedulerCFS {
|
||||||
|
@ -6,6 +6,7 @@ use crate::{
|
|||||||
context::switch_process,
|
context::switch_process,
|
||||||
interrupt::{cli, sti},
|
interrupt::{cli, sti},
|
||||||
},
|
},
|
||||||
|
include::bindings::bindings::smp_get_total_cpu,
|
||||||
include::bindings::bindings::{
|
include::bindings::bindings::{
|
||||||
process_control_block, pt_regs, EINVAL, EPERM, MAX_CPU_NUM, PF_NEED_MIGRATE, PROC_RUNNING,
|
process_control_block, pt_regs, EINVAL, EPERM, MAX_CPU_NUM, PF_NEED_MIGRATE, PROC_RUNNING,
|
||||||
SCHED_FIFO, SCHED_NORMAL, SCHED_RR,
|
SCHED_FIFO, SCHED_NORMAL, SCHED_RR,
|
||||||
@ -27,7 +28,43 @@ pub fn cpu_executing(cpu_id: u32) -> &'static mut process_control_block {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 获取某个cpu的负载情况,返回当前负载,cpu_id 是获取负载的cpu的id
|
||||||
|
// TODO:将获取负载情况调整为最近一段时间运行进程的数量
|
||||||
|
pub fn get_cpu_loads(cpu_id: u32) -> u32 {
|
||||||
|
let cfs_scheduler = __get_cfs_scheduler();
|
||||||
|
let rt_scheduler = __get_rt_scheduler();
|
||||||
|
let len_cfs = cfs_scheduler.get_cfs_queue_len(cpu_id);
|
||||||
|
let len_rt = rt_scheduler.get_rt_queue_len(cpu_id);
|
||||||
|
// let load_rt = rt_scheduler.get_load_list_len(cpu_id);
|
||||||
|
// kdebug!("this cpu_id {} is load rt {}", cpu_id, load_rt);
|
||||||
|
|
||||||
|
return (len_rt + len_cfs) as u32;
|
||||||
|
}
|
||||||
|
// 负载均衡
|
||||||
|
pub fn loads_balance(pcb: &mut process_control_block) {
|
||||||
|
// 对pcb的迁移情况进行调整
|
||||||
|
// 获取总的CPU数量
|
||||||
|
let cpu_num = unsafe { smp_get_total_cpu() };
|
||||||
|
// 获取当前负载最小的CPU的id
|
||||||
|
let mut min_loads_cpu_id = pcb.cpu_id;
|
||||||
|
let mut min_loads = get_cpu_loads(pcb.cpu_id);
|
||||||
|
for cpu_id in 0..cpu_num {
|
||||||
|
let tmp_cpu_loads = get_cpu_loads(cpu_id);
|
||||||
|
if min_loads - tmp_cpu_loads > 0 {
|
||||||
|
min_loads_cpu_id = cpu_id;
|
||||||
|
min_loads = tmp_cpu_loads;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将当前pcb迁移到负载最小的CPU
|
||||||
|
// 如果当前pcb的PF_NEED_MIGRATE已经置位,则不进行迁移操作
|
||||||
|
if (min_loads_cpu_id != pcb.cpu_id) && (pcb.flags & (PF_NEED_MIGRATE as u64)) == 0 {
|
||||||
|
// sched_migrate_process(pcb, min_loads_cpu_id as usize);
|
||||||
|
pcb.flags |= PF_NEED_MIGRATE as u64;
|
||||||
|
pcb.migrate_to = min_loads_cpu_id;
|
||||||
|
// kdebug!("set migrating, pcb:{:?}", pcb);
|
||||||
|
}
|
||||||
|
}
|
||||||
/// @brief 具体的调度器应当实现的trait
|
/// @brief 具体的调度器应当实现的trait
|
||||||
pub trait Scheduler {
|
pub trait Scheduler {
|
||||||
/// @brief 使用该调度器发起调度的时候,要调用的函数
|
/// @brief 使用该调度器发起调度的时候,要调用的函数
|
||||||
@ -44,12 +81,13 @@ fn __sched() -> Option<&'static mut process_control_block> {
|
|||||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||||
|
|
||||||
let next: &'static mut process_control_block;
|
let next: &'static mut process_control_block;
|
||||||
match rt_scheduler.pick_next_task_rt() {
|
match rt_scheduler.pick_next_task_rt(current_pcb().cpu_id) {
|
||||||
Some(p) => {
|
Some(p) => {
|
||||||
next = p;
|
next = p;
|
||||||
// kdebug!("next pcb is {}",next.pid);
|
// kdebug!("next pcb is {}",next.pid);
|
||||||
// rt_scheduler.enqueue_task_rt(next.priority as usize, next);
|
// 将pick的进程放回原处
|
||||||
sched_enqueue(next, false);
|
rt_scheduler.enqueue_front(next);
|
||||||
|
|
||||||
return rt_scheduler.sched();
|
return rt_scheduler.sched();
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -65,12 +103,20 @@ fn __sched() -> Option<&'static mut process_control_block> {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn sched_enqueue(pcb: &'static mut process_control_block, mut reset_time: bool) {
|
pub extern "C" fn sched_enqueue(pcb: &'static mut process_control_block, mut reset_time: bool) {
|
||||||
|
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||||
|
|
||||||
// 调度器不处理running位为0的进程
|
// 调度器不处理running位为0的进程
|
||||||
if pcb.state & (PROC_RUNNING as u64) == 0 {
|
if pcb.state & (PROC_RUNNING as u64) == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let cfs_scheduler = __get_cfs_scheduler();
|
let cfs_scheduler = __get_cfs_scheduler();
|
||||||
let rt_scheduler = __get_rt_scheduler();
|
let rt_scheduler = __get_rt_scheduler();
|
||||||
|
// TODO 前几号进程不进行迁移,这里需要判断修改,当前的意思为了调试已经初始化完成的rt进程
|
||||||
|
// if pcb.pid > 4 && pcb.policy!=0{
|
||||||
|
if pcb.pid > 4 {
|
||||||
|
loads_balance(pcb);
|
||||||
|
}
|
||||||
|
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||||
|
|
||||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||||
if (pcb.flags & (PF_NEED_MIGRATE as u64)) != 0 {
|
if (pcb.flags & (PF_NEED_MIGRATE as u64)) != 0 {
|
||||||
|
@ -4,7 +4,9 @@ use alloc::{boxed::Box, collections::LinkedList, vec::Vec};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::asm::current::current_pcb,
|
arch::asm::current::current_pcb,
|
||||||
include::bindings::bindings::{process_control_block, PF_NEED_SCHED, SCHED_FIFO, SCHED_RR},
|
include::bindings::bindings::{
|
||||||
|
process_control_block, MAX_CPU_NUM, PF_NEED_SCHED, SCHED_FIFO, SCHED_RR,
|
||||||
|
},
|
||||||
kBUG, kdebug,
|
kBUG, kdebug,
|
||||||
libs::spinlock::RawSpinlock,
|
libs::spinlock::RawSpinlock,
|
||||||
};
|
};
|
||||||
@ -23,7 +25,7 @@ pub fn __get_rt_scheduler() -> &'static mut SchedulerRT {
|
|||||||
|
|
||||||
/// @brief 初始化rt调度器
|
/// @brief 初始化rt调度器
|
||||||
pub unsafe fn sched_rt_init() {
|
pub unsafe fn sched_rt_init() {
|
||||||
kdebug!("test rt init");
|
kdebug!("rt scheduler init");
|
||||||
if RT_SCHEDULER_PTR.is_null() {
|
if RT_SCHEDULER_PTR.is_null() {
|
||||||
RT_SCHEDULER_PTR = Box::leak(Box::new(SchedulerRT::new()));
|
RT_SCHEDULER_PTR = Box::leak(Box::new(SchedulerRT::new()));
|
||||||
} else {
|
} else {
|
||||||
@ -86,11 +88,15 @@ impl RTQueue {
|
|||||||
self.queue.push_front(pcb);
|
self.queue.push_front(pcb);
|
||||||
self.lock.unlock();
|
self.lock.unlock();
|
||||||
}
|
}
|
||||||
|
pub fn get_rt_queue_size(&mut self) -> usize {
|
||||||
|
return self.queue.len();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief RT调度器类
|
/// @brief RT调度器类
|
||||||
pub struct SchedulerRT {
|
pub struct SchedulerRT {
|
||||||
cpu_queue: Vec<&'static mut RTQueue>,
|
cpu_queue: Vec<Vec<&'static mut RTQueue>>,
|
||||||
|
load_list: Vec<&'static mut LinkedList<u64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SchedulerRT {
|
impl SchedulerRT {
|
||||||
@ -102,20 +108,32 @@ impl SchedulerRT {
|
|||||||
// todo: 从cpu模块来获取核心的数目
|
// todo: 从cpu模块来获取核心的数目
|
||||||
let mut result = SchedulerRT {
|
let mut result = SchedulerRT {
|
||||||
cpu_queue: Default::default(),
|
cpu_queue: Default::default(),
|
||||||
|
load_list: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// 为每个cpu核心创建队列
|
// 为每个cpu核心创建队列
|
||||||
|
for cpu_id in 0..MAX_CPU_NUM {
|
||||||
|
result.cpu_queue.push(Vec::new());
|
||||||
|
// 每个CPU有MAX_RT_PRIO个优先级队列
|
||||||
for _ in 0..SchedulerRT::MAX_RT_PRIO {
|
for _ in 0..SchedulerRT::MAX_RT_PRIO {
|
||||||
result.cpu_queue.push(Box::leak(Box::new(RTQueue::new())));
|
result.cpu_queue[cpu_id as usize].push(Box::leak(Box::new(RTQueue::new())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 为每个cpu核心创建负载统计队列
|
||||||
|
for _ in 0..MAX_CPU_NUM {
|
||||||
|
result
|
||||||
|
.load_list
|
||||||
|
.push(Box::leak(Box::new(LinkedList::new())));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief 挑选下一个可执行的rt进程
|
/// @brief 挑选下一个可执行的rt进程
|
||||||
pub fn pick_next_task_rt(&mut self) -> Option<&'static mut process_control_block> {
|
pub fn pick_next_task_rt(&mut self, cpu_id: u32) -> Option<&'static mut process_control_block> {
|
||||||
// 循环查找,直到找到
|
// 循环查找,直到找到
|
||||||
// 这里应该是优先级数量,而不是CPU数量,需要修改
|
// 这里应该是优先级数量,而不是CPU数量,需要修改
|
||||||
for i in 0..SchedulerRT::MAX_RT_PRIO {
|
for i in 0..SchedulerRT::MAX_RT_PRIO {
|
||||||
let cpu_queue_i: &mut RTQueue = self.cpu_queue[i as usize];
|
let cpu_queue_i: &mut RTQueue = self.cpu_queue[cpu_id as usize][i as usize];
|
||||||
let proc: Option<&'static mut process_control_block> = cpu_queue_i.dequeue();
|
let proc: Option<&'static mut process_control_block> = cpu_queue_i.dequeue();
|
||||||
if proc.is_some() {
|
if proc.is_some() {
|
||||||
return proc;
|
return proc;
|
||||||
@ -124,6 +142,22 @@ impl SchedulerRT {
|
|||||||
// return 一个空值
|
// return 一个空值
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_rt_queue_len(&mut self, cpu_id: u32) -> usize {
|
||||||
|
let mut sum = 0;
|
||||||
|
for prio in 0..SchedulerRT::MAX_RT_PRIO {
|
||||||
|
sum += self.cpu_queue[cpu_id as usize][prio as usize].get_rt_queue_size();
|
||||||
|
}
|
||||||
|
return sum as usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_load_list_len(&mut self, cpu_id: u32) -> usize {
|
||||||
|
return self.load_list[cpu_id as usize].len();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enqueue_front(&mut self, pcb: &'static mut process_control_block) {
|
||||||
|
self.cpu_queue[pcb.cpu_id as usize][pcb.priority as usize].enqueue_front(pcb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scheduler for SchedulerRT {
|
impl Scheduler for SchedulerRT {
|
||||||
@ -132,8 +166,9 @@ impl Scheduler for SchedulerRT {
|
|||||||
fn sched(&mut self) -> Option<&'static mut process_control_block> {
|
fn sched(&mut self) -> Option<&'static mut process_control_block> {
|
||||||
current_pcb().flags &= !(PF_NEED_SCHED as u64);
|
current_pcb().flags &= !(PF_NEED_SCHED as u64);
|
||||||
// 正常流程下,这里一定是会pick到next的pcb的,如果是None的话,要抛出错误
|
// 正常流程下,这里一定是会pick到next的pcb的,如果是None的话,要抛出错误
|
||||||
|
let cpu_id = current_pcb().cpu_id;
|
||||||
let proc: &'static mut process_control_block =
|
let proc: &'static mut process_control_block =
|
||||||
self.pick_next_task_rt().expect("No RT process found");
|
self.pick_next_task_rt(cpu_id).expect("No RT process found");
|
||||||
|
|
||||||
// 如果是fifo策略,则可以一直占有cpu直到有优先级更高的任务就绪(即使优先级相同也不行)或者主动放弃(等待资源)
|
// 如果是fifo策略,则可以一直占有cpu直到有优先级更高的任务就绪(即使优先级相同也不行)或者主动放弃(等待资源)
|
||||||
if proc.policy == SCHED_FIFO {
|
if proc.policy == SCHED_FIFO {
|
||||||
@ -167,14 +202,27 @@ impl Scheduler for SchedulerRT {
|
|||||||
}
|
}
|
||||||
// curr优先级更大,说明一定是实时进程,将所选进程入队列,此时需要入队首
|
// curr优先级更大,说明一定是实时进程,将所选进程入队列,此时需要入队首
|
||||||
else {
|
else {
|
||||||
self.cpu_queue[proc.cpu_id as usize].enqueue_front(proc);
|
self.cpu_queue[cpu_id as usize][proc.cpu_id as usize].enqueue_front(proc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enqueue(&mut self, pcb: &'static mut process_control_block) {
|
fn enqueue(&mut self, pcb: &'static mut process_control_block) {
|
||||||
|
let cpu_id = pcb.cpu_id;
|
||||||
let cpu_queue = &mut self.cpu_queue[pcb.cpu_id as usize];
|
let cpu_queue = &mut self.cpu_queue[pcb.cpu_id as usize];
|
||||||
cpu_queue.enqueue(pcb);
|
cpu_queue[cpu_id as usize].enqueue(pcb);
|
||||||
|
// // 获取当前时间
|
||||||
|
// let time = unsafe { _rdtsc() };
|
||||||
|
// let freq = unsafe { Cpu_tsc_freq };
|
||||||
|
// // kdebug!("this is timeeeeeeer {},freq is {}, {}", time, freq, cpu_id);
|
||||||
|
// // 将当前时间加入负载记录队列
|
||||||
|
// self.load_list[cpu_id as usize].push_back(time);
|
||||||
|
// // 如果队首元素与当前时间差超过设定值,则移除队首元素
|
||||||
|
// while self.load_list[cpu_id as usize].len() > 1
|
||||||
|
// && (time - *self.load_list[cpu_id as usize].front().unwrap() > 10000000000)
|
||||||
|
// {
|
||||||
|
// self.load_list[cpu_id as usize].pop_front();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
|
|
||||||
#include <process/preempt.h>
|
#include <process/preempt.h>
|
||||||
#include <sched/sched.h>
|
#include <sched/sched.h>
|
||||||
|
#include <driver/acpi/acpi.h>
|
||||||
|
#include <driver/interrupt/apic/apic.h>
|
||||||
#include "ipi.h"
|
#include "ipi.h"
|
||||||
|
|
||||||
static void __smp_kick_cpu_handler(uint64_t irq_num, uint64_t param, struct pt_regs *regs);
|
static void __smp_kick_cpu_handler(uint64_t irq_num, uint64_t param, struct pt_regs *regs);
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
#include <common/glib.h>
|
#include <common/glib.h>
|
||||||
|
|
||||||
#include <common/asm.h>
|
#include <common/asm.h>
|
||||||
#include <driver/acpi/acpi.h>
|
|
||||||
#include <driver/interrupt/apic/apic.h>
|
|
||||||
|
|
||||||
#define MAX_SUPPORTED_PROCESSOR_NUM 1024
|
#define MAX_SUPPORTED_PROCESSOR_NUM 1024
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user