一些过时的研究认为在提高频率过程中,IPC (instruction per cycle)不变,以下面频率加倍为例,他们认为提高频率clockrate后CPU处理指令的速度加倍,但cycle同比例缩小,因此单位cycle时间内处理的指令数是不变的。但现有研究纠正了这一观点,实际在提高频率后,在不同负载下,用于处理指令的cycles数并不是同比例变化的,因此要处理同样多的指令时,分母变得更大,即单位cycle处理的指令数减小,因此对于部分应用来说,提高频率IPS的提速是越来越缓慢的。如下图所示,为了达到相同的IPS,不同类型的任务所需要的频点是不一样的,我们可以利用这一点来进行调频优化。
基于龙蜥操作系统的应用性能监测与预测软件
作品完成和提交方式:选择本赛题的参赛队伍需要首先复刻(Fork)本项目,然后在复刻的项目中添加参赛队员、合作完成作品开发即可,无需提交PR到赛题项目。如果作品为文档形式,也请将作品文档提交到项目代码库中。在作品完成过程中,围绕作品的相关讨论等可以以疑修(Issue)形式发布和讨论,也可使用里程碑对整个任务进行规划管理。
1. 赛题背景
业界分析显示,数据中心的资源利用率普遍较低。为降低成本和减少资源浪费,采取了各种共置策略,即在同一服务器上运行多个应用程序。然而,这种做法引发了资源争夺问题,尤其是在资源竞争激烈时,可能会严重影响应用性能,并使得无法保证应用的服务质量。此外,出于隐私和资源限制等因素,生产环境中在线应用的性能指标往往难以获得。因此,一个高效且精准的应用性能监测与预测软件对于应用调度至关重要。参赛者需基于龙蜥操作系统开发一款能够通过低级平台指标预测高级应用指标的应用性能预测软件。
2. 赛题要求
一、背景介绍
概述:我们发现不同类型的负载,随着频率的变化,其每秒处理的指令数变化情况不一,特别是对于CPU密集型和访存密集型的应用。
近期的研究证明了在CPU执行期间,存在相当大比例的stall cycles,这就导致CPU无法感知到真实的算力需求,继而导致无法给到合适的频率。
不同类型的任务在执行期间的stall cycles占比不同,即对CPU算力的敏感程度不一,因此需要再Linux Kernel中能够感知这种任务类型的变化。为了降低区分任务过程中的开销,我们根据stall cycles的比例大致将任务分为三类:CPU密集型、访存密集型、平衡型。
我们使用IPS吞吐量作为反映CPU性能变化的指标,随着频率的升高,IO密集型任务的IPS并没有呈现出预期的增加趋势,这正是由于stall cycles的存在。已知:
IPS = IPC * f = inst/cycle*f
一些过时的研究认为在提高频率过程中,IPC (instruction per cycle)不变,以下面频率加倍为例,他们认为提高频率clockrate后CPU处理指令的速度加倍,但cycle同比例缩小,因此单位cycle时间内处理的指令数是不变的。但现有研究纠正了这一观点,实际在提高频率后,在不同负载下,用于处理指令的cycles数并不是同比例变化的,因此要处理同样多的指令时,分母变得更大,即单位cycle处理的指令数减小,因此对于部分应用来说,提高频率IPS的提速是越来越缓慢的。如下图所示,为了达到相同的IPS,不同类型的任务所需要的频点是不一样的,我们可以利用这一点来进行调频优化。
如果想基于这种负载特征进行调频,就需要能够给内核一个能反映负载特征的指标,我们使用PMU来进行实现,通过对任务执行期间的PMU数据进行拟合,我们可以得到反映任务类型的指标,继而根据这种特征得到不同类型任务的频率和IPS的对应关系,通过后面的IPS模型进行更合理的调频操作。
对于同一款CPU,不同负载类型的性能表现(IPS水平)和频率的关系是不一样的,有些是和我们/系统设想的一样,性能表现与频率呈正比关系,而也有许多负载表现除了不一样的规律,它们和频率的关系表现出了一种非线性的关系,即频率升高对于它们的性能影响越来越小,并且这种衰减程度还各不相同。
当前Linux Kernel通过追踪CPU负载情况(util),来给予足够算力满足算力需求。我们称之为基于util的算力模型。该模型将CPU算力归一化到1024,以统一的线性关系(正比)给予指定CPU util足够算力(频点)。这样的算力模型可以以很低的代价计算出满足性能的算力需求(频点),问题则是系统中的算力模型过于简单,本质上只是一个正比映射的关系,且对所有负载类型都一视同仁,但是我们在上述现象中可以看到,对于不同负载而言,其性能表现随频点变化的速度存在巨大差异,如果忽略这一差异,会造成极大的算力浪费。
二、方案原理
目前的主流的负载追踪方法是对每个CPU的util进行追踪并给予算力,经典的如schedutil,以及它的变种pelt与walt。而如第一节看到的,由于mem stall存在,对于一些IO/内存密集型的负载而言,随着频率的升高,cycle数会同步升高,公式1很好地展示了这个关系。 cycle = A * freq + B(1) 而cycle数的上升则会让负载误以为需求的上升(实际上并非是指令执行的增加),进而继续提频,如此往复,直到频率上升至最高或负载需求下降。这样的恶性循环会导致性能与功耗的极大浪费。 INST数则完全避免了这个问题,首先,inst数本身就是真实的指令需求,当负载的IPC稳定是,ISNT数可以等价为cycle数(IPS = IPC * freq), 而当负载的IPC随频率变化时,INST数又能反应真实计算需求。

三、实验分析
我们在不同的benchmark上进行了实验验证,结果如下:
在数据收集阶段,我们设定一个采样间隔(周期T=20ms),分析每周期内的IPS的变化情况,因此每周期的IPS值为:
IPS = INSTcurr / T.
由于同一任务在执行期间,每周期内的执行inst数我们可以认为是近似的,因此相邻周期内有很强的相关性,这里我们就可以利用局部性进行预测了。
IPSpred = a * IPScurr + (1 - a) * IPSprev
此时我们可以预测下一周期内 IPSpred = INSTpred / T’,我们可以通过调频来控制下一周期内任务的执行时间T’变长或者变短,以达到控制利用率的目的。根据公式:
IPS = INST * freq / (A * freq + B) => IPS = freq / (freq * stall_SPI + CPI)
当 stall_SPI 为0时,负载和性能呈正比关系,当stall_SPI变大,负载和性能呈非线性关系,且stall_SPI越大,CPU频率能够影响的事件越小,IPS随频率上升速度降低,这个时候就会出现频率升高,IPS上升速度变慢的现象。
由于 SPI = stall_SPI + CPI / freq,所以只有知道负载在某个频点下的SPI以及负载对应的stall_SPI,我们就能计算出负载在该核心上的基础CPI,进而计算出负载在所有频点的IPS表现。负载在某个频点下的SPI可以直接获得,因此问题变成:计算当前的负载的stall_SPI,这里使用两点法(X是stall_SPI):
(SPIa - X) * freqa = (SPIb - X) * freqb
对公式进行简化,得到:
X = (SPIa * freqa - SPIb * freqb)/(freqa - freqb)
模型的具体拟合部分由于涉及PMU数据采集拟合,尚未整理完毕,大致思路是通过不同周期间的相关性和局部性进行建模,可以预测接下来一个周期的IPS水平,从而根据我们的freq-IPS模型进行DVFS操作。