LWN: small-task packing披了马甲卷土重来

TurboSched: the return of small-task packing

By Jonathan Corbet

July 1, 2019

CPU scheduling(处理器的调度)是个很难得到完美实现的工作,因为在选下一个运行的进程时,不是很容易能在保证公平性、尽量省电、尽量用足处理器的能力这几点之间平衡好。目前的系统架构也越来越复杂,情况并没有好转。例如在非对称系统(big.LITTLE这种架构)里的调度功能就很难实现好。还有某些最新处理器里支持的turbo mode也是一个例子。Parth Shah最近就提供了一个TurboSched patch set,希望能改善scheduler调度器的能力从而最大化利用这类处理器的性能。

对我们这些在计算机这行做了太多年的人来说,刚看到"turbo mode"的时候,第一反应就是1980年代的个人电脑上的一个“turbo"键。当时,按下这个键的话可以上CPU的时钟能让当时让人震惊的4.77Mhz提升到一个更快的的速度,主要是为了某些特殊应用场景下的,平时还是要使用普通的慢速模式。现代设计的turbo mode已经跟这个完全不同了,差异不仅仅是PC前面板上没有那个按键了。简单来说,现代的turbo mode会能让CPU以超出它设计速度的频率来运行一段时间,前提是系统的其他部分状态都合适,能够允许CPU超频。

因此Turbo mode会能够让CPU在运行某个特定进程的时候增加CPU的频率。不过,CPU平时肯定不能一直用turbo mode的速度来跑,因为这个高速模式只能持续一小段时间,否则CPU温度就会升得太高。因此scheduler的一个重要任务,就是要确保系统的功耗不能太高了。

因此,这意味着某些CPU需要被关闭。假如所有CPU都在全速运行,系统的功耗限制就会导致这些CPU都不能进入turbo mode。也就是说,这个模式只对某些特定workload有用,而对其他大多数场景来说没有帮助。

什么样的workload会更适合turbo mode呢?就是系统并没有完全利用全部资源(意味着某些CPU可以被关闭),此时有少数进程如果能拿到更高的CPU运行速度会很有帮助。当然,要想得到这个好处,首先得先确保turbo mode是可用的。当前kernel里的CPU scheduler会考虑很多因素之后采用一个平衡策略,不过并没有考虑“确保某些CPU能进入turbo mode” 这个 需求。因此对有能力进入turbo mode并且workload也确实需要turbo mode的系统来说,当前的scheduler的选择并不是最优的。例如当前scheduler设计目标是让系统能尽快响应,确保尽量把所有CPU利用满。因此这就决定了系统会把进程分散在各个CPU之上。如果某个睡眠进程被唤醒需要继续执行了,scheduler就会想着把这个进程放到某个最空闲的CPU上,这样就能让它尽快得到执行,而不是在run queue里面等待。通常来说这个选择是正确的,不过如果你的目标是让一些CPU能尽量长的时间都被power down从而其他CPU能进turbo mode的话,这样就不合适了,相反应该把新唤醒的进程放到某个已经在busy running的CPU上,从而让其他CPU继续睡着去吧。

这种调度行为(能把更多的进程塞到已经在running的CPU)就是TurboSched patch set的目标。不过这种packing(打包塞在一起)的决策需要很仔细的做好预先评判,否则的话进程的scheduling latency(调度延迟)就会大增,系统计算能力同时也没有得到充分利用。为了避免这些负面作用,TurboSched就只对“jitter”进程做packing。jitter进程就是指一些很少执行、并且对响应时间要求不高的进程。这类进程通常都是在做一些系统定期维护的动作,哪怕跟别的任务共享一个CPU也不会有太大影响。

那么马上就跳出一个问题:scheduler怎么能确定哪些进程是属于“jitter”进程呢?答案是它没法判断,因此需要靠user space来明确的标注出来。TurboSched是基于一个(尚未合入的)scheduler utilization clamping patch set,这个patch set允许系统管理员来对特定进程指定分配它能占有最多多少CPU资源。这样管理员就能避免某个进程导致CPU升频,哪怕这个进程一刻不停的运行。通过这种方式标注后,这些进程就能减少对CPU的占用了。而TurboSched认为对这些被限制了最大CPU占用率的进程,就不应该浪费一个正在睡眠的CPU来执行它。

在这次的patch里面实现的逻辑其实更进了一步,明确规定jitter进程不可以被放到一个<12.5%利用率的CPU上去执行。这是因为这种利用率很低的CPU很可能会很快进入idle状态,如果放个新的进程上去的话就可能导致CPU没法进idle了,大家都不期望有这种结果。当然,大家也都不想看到jitter进程堆积在一起之后让某些CPU负载过重,所以代码里也有一个上限限制,确保不要对某个CPU塞太多jitter进程上去。

这个方案看起来可能对有些开发者很熟悉,很像是2012年(甚至更早)的时候讨论的small-task packing算法。small-task packing方案一直没能合入mainline,所以人们很容易想到一个问题,这次的方案会有更大机会合入吗?这次最大的区别在于对jitter进程的明确标注这里,它使得TurboSched在大多数不需要利用这个功能的系统上,都没有任何影响。也就是说如果没有这些被限制了占用率的进程的话,scheduler就跟当前的运行模式没有任何区别,系统也就不会有任何性能差异。

与此同时,根据patch里画的一个ASCII图示来看,对某些workload可能会有高达13%的性能改善。当然不会是所有workload都有这个改善,不过在某些特定系统上(具有几个行为固定并且仔细调试过的workload),TurboSched就能让系统运行的更好。再加上这个patch的改动对其他场景下基本上没有什么负面影响,这次可能真的能够合入scheduler code base。

全文完

LWN文章遵循CC BY-SA 4.0许可协议。

极度欢迎将文章分享到朋友圈 

长按下面二维码关注:Linux News搬运工,希望每周的深度文章以及开源社区的各种新近言论,能够让大家满意~

我来评几句
登录后评论

已发表评论数()

相关站点

热门文章