CFS调度器负载计算_scale_load_down-程序员宅基地

技术标签: CFS  load_sum  Linux5.0  进程管理  负载  

     /******以下结论和代码分析都是基于最新Linux master分支(Linux5.0)******/

1. 负载结构体

每个调度实体都有一个负载结构,用来跟踪调度实体对系统的负载贡献

struct sched_entity { 

struct load_weight        load;  
#ifdef CONFIG_SMP
    struct sched_avg        avg;
#endif
};

struct sched_avg {
    u64                last_update_time;/*上次负载更新时间 */
    u64                load_sum;/* 负载贡献*/
    u64                runnable_load_sum;/*runable状态负载贡献 */
    u32                util_sum; /* running状态负载贡献*/
    u32                period_contrib;/*负载计算时,不足一个周期的部分 */
    unsigned long            load_avg;/* 平均负载*/
    unsigned long            runnable_load_avg;/* runable 状态平均负载*/
    unsigned long            util_avg;/* running状态平均负载*/
}

调度实体sched_entity和cfs_rq都内嵌一个shed_avg。

调度实体sched_enity说明:

load_sum: /*累计runable和block衰减负载 */

runnable_load_sum 与load_sum一样

util_sum:/* 累计running衰减时间总和*/

load_avg: 平均负载, (load_sum*load->weight)/最大衰减值

最大衰减累加时间:进程在CPU上运行无限长时,根据PELT算法计算出的衰减值.

当进程无限运行后,load_avg总是无限接近进程权重值(load.weight)

对调度实体来说load_sum=runnable_load_sum,   load_avg=runnable_load_avg

对于CFS调度队列来说
load_sum  = 整个队列负载 * 整个队列权重

 

2. 调度实体/CFS队列负载更新

每个调度实体负载更新的时机:

1. 从阻塞状态到runnable状态(入队列)

2. 从running状态到runnable状态(入队列)

3. 从runnable状态到running状态(出队列,CPU运行)

4. 从runable状态到阻塞状态(出队列)

总结: 入队列和出队列更新调度实体负载/CFS负载

进程负载更新函数为update_load_avg,

static inline void update_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
{
    u64 now = cfs_rq_clock_pelt(cfs_rq);
    /*更新调度实体负载 */
    if (se->avg.last_update_time && !(flags & SKIP_AGE_LOAD))
        __update_load_avg_se(now, cfs_rq, se);
    /* 更新CFS队列负载*/
    decayed  = update_cfs_rq_load_avg(now, cfs_rq);
}

2.1 调度实体负载更新

int __update_load_avg_se(u64 now, struct cfs_rq *cfs_rq, struct sched_entity *se)
{
        /*更新load_sun和runnable_load_sun */    
    if (___update_load_sum(now, &se->avg, !!se->on_rq, !!se->on_rq,
                cfs_rq->curr == se)) {
        /*更新平均负载load_avg和runnable_load_avg *
        ___update_load_avg(&se->avg, se_weight(se), se_runnable(se));   
        return 1;
    }

    return 0;
}

其中__update_load_sum根据PELT算法计算调度实体负载,从传的参数也可以看出,

对于调度实体load=runnable = !!se->on_rq,非0即1

而平均负载的计算,传了se的weight和runnable weight,对于线程调度实体,weight==runnable weight

static __always_inline void
___update_load_avg(struct sched_avg *sa, unsigned long load, unsigned long runnable)
{
    u32 divider = LOAD_AVG_MAX - 1024 + sa->period_contrib;/* 根据PELT计算的最大负载值*/

/* 计算平均负载*/
    sa->load_avg = div_u64(load * sa->load_sum, divider);
    sa->runnable_load_avg =    div_u64(runnable * sa->runnable_load_sum, divider);
    WRITE_ONCE(sa->util_avg, sa->util_sum / divider);
}

2.2 CFS 队列负载更新

/* 实际上跟调度实体调用函数一样,只是参数有差别*/

int __update_load_avg_cfs_rq(u64 now, struct cfs_rq *cfs_rq)
{
    if (___update_load_sum(now, &cfs_rq->avg,
                scale_load_down(cfs_rq->load.weight),
                scale_load_down(cfs_rq->runnable_weight),
                cfs_rq->curr != NULL)) {

        ___update_load_avg(&cfs_rq->avg, 1, 1);
        trace_pelt_cfs_tp(cfs_rq);
        return 1;
    }

    return 0;
}

3. 调度实体入队列/出队列对CFS队列负载的影响

3.1 调度实体加入CFS队列时

static void
enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
{

  /*更新调度实体虚拟时间和min_vruntime */

    update_curr(cfs_rq);
    /* 先更新se负载*/
    update_load_avg(cfs_rq, se, UPDATE_TG | DO_ATTACH);
    /* 把se 的runnable load_sum加到CFS队列的runnable_load_sum*/
    enqueue_runnable_load_avg(cfs_rq, se);

/* 把se的权重load.weight加到CFS队列的总权重*/
    account_entity_enqueue(cfs_rq, se);
    if (!curr)
        __enqueue_entity(cfs_rq, se);/*加如运行队列红黑数 */
    se->on_rq = 1;/* 标记入在runnable队列上*/
}

3.2 调度实体出队列

static void
dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
{
    /*
     更新虚拟时间和min_vruntime
     */
    update_curr(cfs_rq);

    /*更新调度实体和CFS负载 */
    update_load_avg(cfs_rq, se, UPDATE_TG);
    /*减去se的runable负载 */
    dequeue_runnable_load_avg(cfs_rq, se);
    /*标记se没有在运行队列 */
    se->on_rq = 0;
    /*减去se的权重load.weight */
    account_entity_dequeue(cfs_rq, se);

}

4. 负载更新函数

/* 更新se的load_sum和load_avg*/

int __update_load_avg_se(u64 now, struct cfs_rq *cfs_rq, struct sched_entity *se)

/* 更新cfs的load_sum和load_avg*/

int __update_load_avg_cfs_rq(u64 now, struct cfs_rq *cfs_rq)

/*更新load_sum */

___update_load_sum(u64 now, struct sched_avg *sa,unsigned long load, unsigned long runnable, int running)

/*更新load_avg */

___update_load_avg(struct sched_avg *sa, unsigned long load, unsigned long runnable)

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/bin_linux96/article/details/100163241

智能推荐

SAP 消息 有关成本控制范围 XXXX的控制标志不存在_有关成本控制范围的控制标志不存在-程序员宅基地

文章浏览阅读3.5k次。此错误问题解决路径如下:点开后编辑:再去做凭证发现错误消除了。_有关成本控制范围的控制标志不存在

IT运维的365天--009微信双开批处理文件运行出错(当前目录无效)的解决_微信多开bat找不到文件-程序员宅基地

文章浏览阅读848次。微信双开批处理,文件编码格式,ANSI_微信多开bat找不到文件

python 协程库gevent学习 -- 超时、互斥锁(BoundedSemaphore)、local_python gevent.lock-程序员宅基地

文章浏览阅读3.8k次。当其他greenlet去访问它的时候是无法访问到的,它只在自己的greenlet的命名空间中有效。这里Mylocal继承了gevent的local,这里重点介绍一下__slots__在这里的用法,我们知道在常规的类里面指定__slots__的意思往往是只允许该类下的属性只允许有__slots__里面这些,超出的就会报出Attribute error的错误。但是继承了local的__slots__在这里却是指,申明了的属性将会穿透所有greenlet变成一个全局可读的,并不再是线程本地的,这里注意下。_python gevent.lock

【nginx】如何解决使用nginx作为反向代理端口耗尽问题?_连接数过多导致nginx服务器端口数不足-程序员宅基地

文章浏览阅读2.4k次。TCP 长连接负载均衡问题(10W 用户) ----- TCP 长连接 ----- Nginx/HAproxy/LVS(软件负载) ------ TCP 长连接 ----- (实际业务,多台业务服务器)客户端 TCP 10W 长连接到 Nginx/HAproxy 这一步,没有问题。软件负载到实际业务这里,由于负载均衡(nginx) 是采用转发的方式进行处理的,本地会创建连接,当转发超出 65535 时,(nginx)就不能建立长连接了。Linux 系统调优参数基本已经设置过了,应该不是这_连接数过多导致nginx服务器端口数不足

html的tab页面切换刷新,切换tab页,页面局部刷新,地址栏路径修改-程序员宅基地

文章浏览阅读2.1k次。需求:做一个类似百度这种,切换tab,页面展示局部刷新的效果。思路:tab展示的切换,使用display控制。但是,如果页面刷新,则无法保留显示在tab2的效果,因而在地址栏加参数标记。但如果用a的href或者location.href 均会将整个页面刷新,体验很差,故需只修改地址栏路径,但不刷新页面。解决方案:在切换tab时,先处理隐藏显示区域的内容,再将地址栏的内容改掉,如下:window.h..._html tab 刷新

事后诸葛亮-程序员宅基地

文章浏览阅读44次。参考各个小组的评论和总结队友的意见:### ‘简阅’ 在beta阶段需要改进的地方1.字体大小不合适,需要调整2.欢迎界面的背景比较模糊,需要更换3.在用户向下滑动阅读时,标题可以变小或者隐藏4.加入收藏,分享等功能5.文章来源需要改进,数量不够6.兴趣标签比较少,分类不够仔细,可以考虑改进### 团队的分工协作现在的分工情况还是很理想的,所以应该不会有人员的调整..._字体设计事后诸葛亮

随便推点

Git基础语法-程序员宅基地

文章浏览阅读465次。git的基础语法_git基础语法

Java基于注解实现日志记录模块,超详细注释!_java如何使用注解记录日志-程序员宅基地

文章浏览阅读810次,点赞15次,收藏17次。在项目开发过程中,日志记录是一个至关重要的环节,它能够帮助开发人员追踪用户的重要操作,如新增、删除、修改等,从而有效监控系统的运行状态。通过日志记录,我们可以深入了解系统的运行情况,及时发现并解决问题,优化性能,提高用户体验。_java如何使用注解记录日志

Cisco 构建小型局域网络(三层交换机和路由器、ospf 动态路由配置)_思科中小型企业网络拓扑图及配置-程序员宅基地

文章浏览阅读1.2w次,点赞31次,收藏264次。一、实训内容:架构分析(1)需求分析本实验的目的在于建立小型局域网。由于公司由不同部门组成,并分布在不同地点,因此需要划分不同网络实现互联互通。设计以下网络:两个部门各使用一台交换机连接,然后连接到总交换机,再通过路由器与外网以及其他部门网络相连。为了控制网络上的广播风暴,增加网络的安全性,在交换机上需要设置VLAN,在路由器与交换机之间需要设置动态路由OSPF协议。(2)环境要求Cisco模拟器规划拓扑(1)拓扑描述地点1包括部门1和部门2;地点2包括部门3。部门1网络为子网3:172_思科中小型企业网络拓扑图及配置

vlan的学习笔记2(vlan间通信)

R1使用一个物理接口(GE0/0/1)与交换机SW1对接,并基于该物理接口创建两个子接口:GE0/0/1.10及GE0/0/1.20,分别使用这两个子接口作为VLAN 10及VLAN 20的默认网关。在二层交换机上配置VLAN,每个VLAN单独使用一个交换机接口与路由器互联。路由器使用两个物理接口,分别作为VLAN 10及VLAN 20内PC的默认网关,使用路由器的物理接口实现VLAN之间的通信。:1.路由器的一个物理接口作为一个VLAN的网关,因此存在一个VLAN就需要占用一个路由器物理接口。

SpringBoot相关知识点总结

总的来说,`@SpringBootApplication` 注解标记了一个类作为 Spring Boot 应用程序的主类,并启用了 Spring Boot 的自动配置机制和组件扫描机制,简化了应用程序的配置和启动过程,提高了开发效率。:Spring Boot Starters 遵循 Spring Boot 的约定优于配置的设计原则,通过预定义好的依赖项和配置,简化了应用程序的配置过程,使得开发者可以更专注于业务逻辑的实现,而无需过多地关注底层技术细节。这样的配置类通常会被。

什么时候用List、Set或Map(Java中的集合框架体系)_业务开发什么时候使用list-程序员宅基地

文章浏览阅读2.3k次,点赞15次,收藏42次。集合框架体系集合是Java中提供的一种容器,可以用来存储多个数据;而由于存储的方式不同,就形成了很多不同的体系结构,统称为集合框架体系。归为两大类 : Conllection 和 Map Collection List ArrayList 1、排序有序,可重复 2、底层使用数组 3、查询快......_业务开发什么时候使用list

推荐文章

热门文章

相关标签