SMP调度背景

在多处理器系统上,内核必须考虑好几个额外的问题,以确保良好的调度。


  • CPU负荷必须尽可能公平地在所有处理器上共享。
  • 进程与系统中某些处理器的亲合性(affinity)必须是可设置的。
  • 内核必须是能够将进程从一个CPU迁移到另一个上。

linux SMP调度就是将进程安排/迁移到合适的CPU中去,保持各CPU负载均衡的过程。如下图所示。linux调度之SMP负载均衡_Linux

SMP调度时机

scheduler_tick

try_to_wake_up(优先选择在唤醒的CPU上运行)

exec系统调用启动一个新进程时

SMP调度分析

CPU拓扑关系构建

系统启动时开始构建CPU拓扑关系。

linux调度之SMP负载均衡_数组_02

在ARM中,4核处理器示意图如下所示:

linux调度之SMP负载均衡_数组_03

上述4核处理器最后生成的调度域与调度组的拓扑关系图如下图如示:

linux调度之SMP负载均衡_linux_04

load_balance


  • 首先,load_balance()调用find_busiest_queue()来选出最忙的运行队列,在这个队列中具有最多的进程数。这个最忙的运行队列应该至少比当前的队列多出25%的进程数量。如果不存在具备这样条件的队列,find_busiest_queue()函数NULL,同时load_balance()也返回.如果存在,那么将返回这个最忙的运行时队列.
  • 然后,load_balance()函数从这个最忙的运行时队列中选出将要进行负载平衡的优先级数组(priority
    array).选取优先级数组原则是,首先考虑过期数组(expired
    array),因为这个数组中的进程相对来说已经很长时间没有运行了,所以它们极有可能不在处理器缓冲中.如果过期数组(expiredpriority array)为空,那就只能选择活跃数组(active array).
  • 下一步,load_balance()找出具有最高优先级(最小的数字)链表,因为把高优先级的进程分发出去比分发低优先级的更重要。
  • 为了能够找出一个没有运行,可以迁移并且没有被缓冲的进程,函数将分析每一个该队列中的进程.如果有一个进程符合标准,pull_task()函数将把这个进程从最忙的运行时队列迁移到目前正在运行的队列。
  • 只要这个运行时队列还处于不平衡的状态,函数将重复执行3和4,直到将多余进程从最忙的队列中迁移至目前正在运行的队列.最后,系统又处于平衡状态,当前运行队列解锁,load_balance()返回。

try_to_wake_up

唤醒进程涉及到应该由哪个CPU来运行唤醒进程。当找到一个亲和性的调度域且唤醒的CPU与之前该进程运行的CPU不是同一个CPU,考虑使用当前CPU来唤醒进程。也就是说优先选择wakeup CPU,否则选择pre CPU.

参考资料

《奔跑吧Linux》

《深入理解linux架构》

整理了一些个人觉得比较好的学习书籍、大厂面试题、和热门技术教学视频资料共享在里面(包括C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等等.),有需要的可以自行添加哦!~ (​资料获取​​)linux调度之SMP负载均衡_优先级_05

以上有不足的地方欢迎指出讨论,同时可以持续关注我,每天分享Linux、 C/C++后台开发干货内容!