首页 > 其他分享 >CFS(二)load_weight与vruntime

CFS(二)load_weight与vruntime

时间:2023-10-12 19:14:43浏览次数:46  
标签:load sched 权重 weight vruntime delta CFS

前言

在理清楚了CFS的基本实现以后,调度类fair_sched_class中规定了调度器的基本操作集合,cfs_rq实现了被操作的就绪队列。剩下的就是研究操作集合中的具体实现,看看CFS是如何管理这些队列中的进程的。本文主要解释了两个问题:

  • 什么样的任务归CFS管?
  • CFS如何实现队列内部的优先级划分?

调度策略与调度类

sched class sched policy
idle SCHED_IDLE
fair SCHED_NORMAL or SCHED_BATCH
rt SCHED_FIFO or SCHED_RR
dl SCHED_DEADLINE

每一种调度类实现了一类调度策略,CFS支持NORMAL任务和BATCH任务。当设定任务的调度策略为SCHED_NORMAL or SCHED_BATCH时该任务会被放入
CFS的就绪队列中。

这里有一个点需要注意,当设定的调度策略为SCHED_IDLE时,该任务实际放入的是CFS的就绪队列。只是其权重为3,比CFS中最低权重15还要小。

任务优先级&权重&虚拟时间

在内核中,每一个task都有一个调度实体记录其调度信息。struct load_weight记录着调度实体的权重信息.

struct sched_entity {
	struct load_weight		load;               // 权重信息
}

在CFS中vruntime最小的task会被优先调度,在引入了优先级以后我们希望高优先级的任务能够得到更多的运行时间,CFS采取的是权重值的方式影响vruntime的计算,每一次调度时将wall-time转化为vruntime并累计到对应的sched_entity上。不同优先级的task运行相同的wall-time,但是高优先级的task具备高权重,得到的vruntime较小,低优先级的task具备低权重得到的vruntime较高,这样一段时间运行下来,高优先级的task会被调度的次数更多,运行的时间更长。

在Linux中,CFS使用nice值来表示优先级,nice值越小其权重越大,可以理解为nice值越小优先级越高,CFS的任务的nice值范围为[-20,19]。通过查表sched_prio_to_weight可以实现nice值到权重值的转化。任务的默认nice值为0,对应的权重为1024,任意nice值的权重通过1024*1.25^(-nice)计算。比如nice值为-1,其权重值计算为1024*1.25=1280,这里与1277这个值存在一点偏差,存在一点数值上的微调的优化,具体微调的原因与vruntime的计算函数有关。

sched_prio_to_wmult是权重值表的反转值表,这个表由sched_prio_to_weight计算的得来,其计算方式为sched_prio_to_wmult[prio] = (2^32) / sched_prio_to_weight[prio]。这个表存在的目的是通过预计算的方式将除法运算转化为乘法运算,提高计算速度。比如nice值为0的任务计算如下4194304 = (2^32) / 1024

NOTE: WEIGHT_IDLEPRIO & WMULT_IDLEPRIO 是使用IDLE策略的任务在CFS中的权重设置。

#define WEIGHT_IDLEPRIO		3              
#define WMULT_IDLEPRIO		1431655765
const int sched_prio_to_weight[40] = {
 /* -20 */     88761,     71755,     56483,     46273,     36291,
 /* -15 */     29154,     23254,     18705,     14949,     11916,
 /* -10 */      9548,      7620,      6100,      4904,      3906,
 /*  -5 */      3121,      2501,      1991,      1586,      1277,
 /*   0 */      1024,       820,       655,       526,       423,
 /*   5 */       335,       272,       215,       172,       137,
 /*  10 */       110,        87,        70,        56,        45,
 /*  15 */        36,        29,        23,        18,        15,
};

const u32 sched_prio_to_wmult[40] = {
 /* -20 */     48388,     59856,     76040,     92818,    118348,
 /* -15 */    147320,    184698,    229616,    287308,    360437,
 /* -10 */    449829,    563644,    704093,    875809,   1099582,
 /*  -5 */   1376151,   1717300,   2157191,   2708050,   3363326,
 /*   0 */   4194304,   5237765,   6557202,   8165337,  10153587,
 /*   5 */  12820798,  15790321,  19976592,  24970740,  31350126,
 /*  10 */  39045157,  49367440,  61356676,  76695844,  95443717,
 /*  15 */ 119304647, 148102320, 186737708, 238609294, 286331153,
};

接下来就需要研究一下三个问题,wall-time是如何计算出vruntime的?为什么权重值的设定是这样的?sched_prio_to_wmult这个表又是如何加速计算的?这三个问题都与计算的过程相关。
calc_delta_fair负责计算,当调度实体的权重等于NICE_0_LOAD时计算得到的vruntime与wall-time是一致,此时直接返回不需要转换。计算的关键部分在__calc_delta中。

static inline u64 calc_delta_fair(u64 delta, struct sched_entity *se)
{
	if (unlikely(se->load.weight != NICE_0_LOAD))
		delta = __calc_delta(delta, NICE_0_LOAD, &se->load);

	return delta;
}

__calc_delta此时接受三个参数,delta_exec为wall-time,weight为nice值为0对应的权重,lw为任务的权重信息。这段代码比较长,其实可以不用细看,其计算了vruntime = delta_exec * weight / lw->weight。但是直接计算会用到除法,为了加速,这里做了一点改动vruntime = (delta_exec * weight * 2^32) / lw->weight) >> 32,最后一步转化将2^32 / lw->weight变成lw->inv_weight得到vruntime = (delta_exec * weight * lw->inv_weight)。这里通过预计算的方式将除法转化为乘法来加速运算。至此解释了“wall-time是如何计算出vruntime的?”以及“sched_prio_to_wmult这个表又是如何加速计算的?”这两个问题。

static u64 __calc_delta(u64 delta_exec, unsigned long weight, struct load_weight *lw)
{
	u64 fact = scale_load_down(weight);
	int shift = WMULT_SHIFT;
	__update_inv_weight(lw);
	if (unlikely(fact >> 32)) {
		while (fact >> 32) {
			fact >>= 1;
			shift--;
		}
	}
	/* hint to use a 32x32->64 mul */
	fact = (u64)(u32)fact * lw->inv_weight;
	while (fact >> 32) {
		fact >>= 1;
		shift--;
	}
	return mul_u64_u32_shr(delta_exec, fact, shift);
}

关于为什么权重值为什么要以系数1.25计算,参考core.c中的说明。作者期望每提升一级优先级其相对的可运行时间增加10%,其他任务的可运行时间减少10%。这里需要理解相对的含义。首先通过上述函数,我们可以通过虚拟时间计算其wall-time。delta_exec = vruntime * (lw->weight) / 1024,在这个公式中1024和vruntime都是常数(因为CFS的目标就是vruntime相等),因此计算wall-time的占比就是计算其权重的占比。举一个例子,假设此时有三个任务权重分别为820、1024、1024,其wall-time占比此时分别为:820/2868=28.5%1024/2868=35.7%35.7%。此时将任务3的权重提高一级到1277,此时wall-tiem的占比分别为26.2%32.8%40.9%。此时可以看到任务3的占比上升(40.9% - 35.7%) = 5.2%,另外两个任务共同下降(35.7% - 32.8%) + (28.5% - 26.2%) = 2.9% + 2.3% = 5.2%,相对增加了10.4%10%这个相对比例与任务的数量及其权重应该是无关的,是算法层面能保证得到这个近似值。

标签:load,sched,权重,weight,vruntime,delta,CFS
From: https://www.cnblogs.com/wodemia/p/17757721.html

相关文章

  • vue中下载excel文件4种方法,2、通过 a 标签 download 属性结合 blob 构造函数下载发送p
    vue中下载excel文件4种方法,2、通过a标签download属性结合blob构造函数下载发送post请求和后台poi返回文件流实现下载1、通过url下载即后端提供文件的地址,直接使用浏览器去下载通过window.location.href=文件路径下载window.location.href=`${location.origin}/opera......
  • 如何让裸机的虚拟机上的k8s拥有LoadBalace的能力?
    很久之前就接触k8s了,但是一直没有深入学习。最近一段时间刚好有空,所以开始了复习的路程。我们以一个小项目作为试验。1.看部署的yaml文件  在k8s中,运行kubectlapply-fdemo.yaml之后,会创建service和pod的资源对象,但是如果没有安装第三方插件metalab的话,不会......
  • CFS(一)设计理念与实现架构
    前言本文对CFS的基础的设计理念以及在内核实现上的基本代码架构进行了分析,从宏观上梳理调度和CFS的脉络。本文所有的代码基于Linux4.19。CFS的设计理念和目标CFS(CompletelyFairScheduler)完全公平调度器,从字面上看定义的很清晰,首先CFS的本质是一个调度器,所谓调度就是决定CPU......
  • 关于微信小程序VM22:2 (in promise) MiniProgramError {“errMsg“:“hideLoading:fai
    参考地址:https://blog.csdn.net/qq_41227106/article/details/108465104 出现错误的原因如下1、是微信小程序2、把请求接口统一封装,开始请求接口时showLoading,请求接口后hideLoading3、一个页面同时请求多个接口,由于请求是异步的,很有可能上一个开启了showLoading还没请求完......
  • jquery uploadify动态更新配置参数方法uploadifySettings()
    1.使用scriptData给后台传参数的时候,必须声明'method':'GET',因为默认是POST2.$("#uploadify").uploadifySettings('scriptData',{'name':'liudong','age':22});动态更新配置参数$("#uploadify&quo......
  • ./a.out: error while loading shared libraries: libgsl.so.25: cannot open shared
     001、问题: ./a.out:errorwhileloadingsharedlibraries:libgsl.so.25:cannotopensharedobjectfile:Nosuchfileordirectory 002、解决方法[root@pc1test]#lsa.c[root@pc1test]#gcc-I/usr/local/include/gsl-lgsl-lgslcblasa.c[root@pc1test]#......
  • 报错Intel MKL FATAL ERROR: Cannot load libmkl_core.so.的一种解决方法
    问题今天上80服务器跑mdistiller的代码时,意外发现torch、numpy都不能用了T_T以torch为例,出现如下报错情况以numpy为例,出现如下报错情况我们先看看报错信息,这个报错来自InterMKL。InterMKL全称是TheIntelMathKernelLibrary,它是一个主要是用于科学计算的共享库,提供了很......
  • Error: Failed to download metadata for repo 'appstream': Cannot prepare internal
    一背景跑了一份centos容器,想装一下net-tools,报如下错误Error:Failedtodownloadmetadataforrepo'appstream':Cannotprepareinternalmirrorlist:NoURLsinmirrorlist 二解决参考帖子:https://developer.aliyun.com/article/1165954  CentOS已经停止......
  • The designer cannot be shown because the document for it was never loaded. (Visua
    Thedesignercannotbeshownbecausethedocumentforitwasneverloaded. 查看窗体设计器报错   查看代码是空的   多做代码备份。 REFhttps://stackoverflow.com/questions/7688630/the-designer-could-not-be-shown-for-this-file-because-none-of-the-classes-wi......
  • 【动画进阶】神奇的背景,生化危机4日食 Loading 动画还原
    最近,在Steam玩一款老游戏(生化危机4重置版),其中,每当游戏转场的过程中,都有这么一个有趣的Loading动画:整个效果有点类似于日食效果,中间一圈黑色,向外散发着太阳般的光芒。本文,我们将尝试使用CSS,还原这个效果。整个效果做出来,类似于如下两个动画效果这样:实现主体效果其实......