进程|10 行代码玩转弹性调度的小把戏


_本文原题:10 行代码玩转弹性调度的小把戏

进程|10 行代码玩转弹性调度的小把戏
本文插图
作者 | dog250
责编 | 唐小引
头 图 | CSDN 下载自东方 IC
出品 | CSDN
Linux 的进程调度器是通用的调度器 , 无论是 O(n)O(n) , O(1)O(1) , 还是 CFS , 均是基于统一的指标来对待所有进程的 。 也就是说 , 进程甚至无法自主退让 。
只要确定了一个进程的优先级 , 无论是是什么调度算法 , 该进程的地位总是不会变化 , 如果能做到下面的策略就好了:

  • 系统中进程多了 , 就加速退让 。
  • 系统中进程少了 , 就加速抢占 。
  • 工人来了 , 就退让 。
  • 经理来了 , 就抢占 。
  • … …
考虑一个进程 A 在一个特定的系统中运行 , 它最多只能用 40%的 CPU , 此时 , 如果有另外的待运行进程 , 那么这些进程自然分摊另外 60%的 CPU , 如果再来一个进程 A 呢?显然 , 两个进程 A 的 CPU 时间均会减少 。
能不能保证两个进程 A 仍然分别使用 40%的 CPU , 然后其它进程分摊剩余 20%的 CPU 呢?很难!
你可能说可以配 group 啊 , 但是这必须有一个静态的配置过程 , 很难动态自适应 。
换句话说 , Linux 的调度器是 非弹性的!
下面的代码展示了一个简单的弹性调度:
#!/usr/local/bin/stap -g
probe kernel.function( "__enqueue_entity")
{
task = _task_of($se)
pid = @cast(task, "struct task_struct")->pid
if($ 1== pid) {
_nr = $cfs_rq->nr_running
t = $se->vruntime;
$se->vruntime = t + 3000000*(_nr - 1)
}
}
意思是指定进程根据系统中负载的数量来退让:
  • 系统负载越高 , 指定进程占有 CPU 时间比例越低 。
  • 系统负载越低 , 指定进程占有 CPU 时间比例越高 。
来来来 , 看效果:

进程|10 行代码玩转弹性调度的小把戏
本文插图
可以看到:
  • 当只有一个 loop 的时候 , 它占用 100%的 CPU 。
  • 当再生一个 loop 的时候 , 它几乎和第一个 loop 平分 CPU 。
  • 当越来越多的 loop 运行的时候 , 第一个 loop 的 CPU 份额逐渐降低 。
  • 本是同根生 , 只有第一个 loop 被弹性了 。
嗯 , 效果还行 , 但不够平滑 。 试试二次曲线 ,or 三次曲线?
$se->vruntime = t + 200*(_nr - 1)*_nr*_nr
// or
// $se->vruntime = t + 20000*(_nr - 1)*_nr
200 何来?调一手好参数是必要的 。
此外 , 我这里弹性策略过于单一 , 其实是可以设计的足够复杂的 , 比如针对特定进程的特定策略 , 即便是简单的双斜率直线段 , 也比我这个 OK , 是吧 , 不多说 。
【进程|10 行代码玩转弹性调度的小把戏】有人问 , 如何找到要修改的代码在哪里 , 只要对 Linux 内核的执行原理足够熟悉 , 这并不难 , 对于手艺人而言 , 阿基米德 , 鲁班 , 庖丁 , 黄道婆这些人的地位是堪比欧几里得 , 笛卡尔的 。