Linux系统平均负载是如何计算的?[通俗易懂]

Linux系统平均负载是如何计算的?[通俗易懂]关于负载的计算,它的结果是包含有小数的一个浮点数,内核中是不能使用float变量的,那么这里就采用了一个整型变量的低11位来表示小数部分。那么对于数值1来说,它就是FIXED_1,也就是需要对1进行左移11bit。实际上此时这个整型变量保存的值是1024。cat/proc/loadavg0.430.580.655/701045102那么我们通过cat命令查看负载值如上说是,它显示的是带有两个小数表示的一个浮点数,所以最后在输出这个数值时还需要做一个转换,如果从1024个值中得出这100小数

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

关于负载的计算,它的结果是包含有小数的一个浮点数,内核中是不能使用float变量的,那么这里就采用了一个整型变量的低11位来表示小数部分。那么对于数值1来说,它就是FIXED_1,也就是需要对1进行左移11bit。实际上此时这个整型变量保存的值是1024。

cat /proc/loadavg
0.43 0.58 0.65 5/7010 45102

我们通过cat命令查看负载值如上所示,它显示的是带有两个小数表示的一个浮点数,所以最后在输出这个数值时还需要做一个转换,如果从1024个值中得出这100小数部分,实际上也很简单,小学生都会计算,公式如下:

小数部分 = 低11位的值 / 1024  * 100

内核中为了实现这个功能定义了一些宏如下所示:

#define FSHIFT      11      /* nr of bits of precision */
#define FIXED_1     (1<<FSHIFT) /* 1.0 as fixed-point */
#define LOAD_FREQ   (5*HZ+1)    /* 5 sec intervals */
#define EXP_1       1884        /* 1/exp(5sec/1min) as fixed-point */
#define EXP_5       2014        /* 1/exp(5sec/5min) */
#define EXP_15      2037        /* 1/exp(5sec/15min) */

前面介绍了单位换算的问题,后面就开始真正的主题,对于平均负载,它是如何计算的呢?

首先要先搞清楚这个概念意味着什么,实际上系统负载这个指标表示的是系统中当前正在运行的进程数量,它等于running状态的进程数 + uninterrupt状态的进程数:

load = runing tasks num + uninterrupt tasks num

那么问题来了,这个值一直都是动态变化的每秒钟都不一样,如果我们仅仅是要求平均值,那么能够想到的比较容易算的方式,假如以5秒为采样单位:

第5秒 active nr
第10秒 active nr

然后每次计算都累加在一起,最后除以采样次数,这样就获取到了一个平均负载值。

这样计算有一个缺点,就是我们获取到的负载值实际上并不能反应当下系统中的负载情况,因为它计算了从系统启动开始以来的平均值,无法反应当下系统的运行情况,因此系统中实际并不是这样计算的,会求最近1min,5min和15min之内的平均值,那么计算方法是怎样的呢?

对于平均算法来说有很多种实现,比如:
(1)可以使用所有数据相加后处于数据个数,缺点是实时性不够好;
(2)也可以去除过时数据,只保存最近的多个数据做加权平均。

前面已经介绍了第一种方式的实现缺点,那么根据平均负载的需求来看,应该要使用第2种方法才行,每次计算时需要丢弃掉1min、5min、和15min之前的数据,记录最近的数据来计算平均值,但是这种算法依然不够好,它维护的数据太多了。

因此内核采用了另外一种维护数据量更少的算法,一次指数平滑法,感兴趣的可以去网上搜索了解更多的信息。

内核在实现时引入了一个衰减系数(小于1的值),利用这个衰减系数,来达到丢弃旧数据的目的。只需要知道衰减因子、上一次计算的平均值、本次采样的值,这三个就可以计算出最新的平均值了。主要原理就是使用一个小数作为衰减系数e,从开始计算的时刻a0开始,不做衰减,那么存在如下公式:

a1 = a0 * e + a * (1 - e)
a2 = a1 * e + a * (1 - e)
a3 = a2 * e + a * (1 - e)
an = an-1 * e + a * (1 - e)

我们来看如何做到的,举个例子,如果衰减系数为0.3,那么每次在计算平均负载时,都会对旧数据乘以衰减系数,也就是上一时刻的数据占比30%,当前数据占比70%,这样就相当于是更能反映当下的系统运行情况了,每次计算周期都进行这个衰减计算,可以想象的到,距离当前2个周期的数据衰减了两次,相当于乘以30%的2次方,反复如此计算下去,那么很久远的采样数据就在当前的计算结果中无限趋近于0了。

内核中的代码实现在:

void calc_global_load(unsigned long ticks)
{ 
   
    long active, delta;

    if (time_before(jiffies, calc_load_update + 10))
        return;

    /* * Fold the 'old' idle-delta to include all NO_HZ cpus. */
    delta = calc_load_fold_idle();
    if (delta)
        atomic_long_add(delta, &calc_load_tasks);

    active = atomic_long_read(&calc_load_tasks);
    active = active > 0 ? active * FIXED_1 : 0;

    avenrun[0] = calc_load(avenrun[0], EXP_1, active);
    avenrun[1] = calc_load(avenrun[1], EXP_5, active);
    avenrun[2] = calc_load(avenrun[2], EXP_15, active);

    calc_load_update += LOAD_FREQ;

    /* * In case we idled for multiple LOAD_FREQ intervals, catch up in bulk. */
    calc_global_nohz();
}

其中的:

  1. calc_load_tasks就是上面介绍时所说的runnable进程数量和uninterruptable进程数量之和。因为是SMP系统可能涉及到同步问题,因此采用atomic原子变量来保存。
  2. calc_load_update为下次采样时间,每次都需要加5*HZ,因此系统每5秒进行一次更新计算
  3. avenrun数组中保存的是1min,5min,15min时间所计算的平均值,实际上就是通过调整衰减因子来达到目的的,衰减因子越小,那么衰减越快。

在calc_load中进行一次指数平滑算法的计算:

static unsigned long
calc_load(unsigned long load, unsigned long exp, unsigned long active)
{ 
   
    load *= exp;
    load += active * (FIXED_1 - exp);
    load += 1UL << (FSHIFT - 1);
    return load >> FSHIFT;
}

而更新平均负载是在一个系统周期timer中实现的:

void do_timer(unsigned long ticks)
1576 { 
   
1577     jiffies_64 += ticks;
1578     update_wall_time();
1579     calc_global_load(ticks);
1580 }

计算 calc_load_tasks 的地方:

calc_load_fold_idle()                                       //CPU进入nohz之前会把数据进行保存
calc_load_migrate()-->calc_load_fold_active()               //CPU hotplug时,如果下线CPU需要做记录保存,加入最后更新时计算
calc_load_account_active()-->calc_load_fold_active()        //CPU没有idle,那么会执行定期更新,在每个CPU都会执行这个计算

在计算负载时:
1.每个CPU都需要定时更新 calc_load_tasks的数值,该值记录的是所有CPU上可运行和uninterruptable数量的总和(calc_load_account_active)
2.处理idle的情况,进入idle前需要保存(calc_load_fold_idle)
3.处理CPUhotplug情况,下线前需要保存值(calc_load_migrate)

最后根据calc_load_tasks执行一次global平均值计算:

1.timer中触发5HZ周期的平均值计算(calc_global_load)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/194528.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • java代码运行简单js方法案例

    java代码运行简单js方法案例java代码运行简单js方法案例

  • 指令重排详解_cpu指令重排序

    指令重排详解_cpu指令重排序指令重排:编译器指令重排,cpu指令重排,内存指令重排。编译器可能会调整顺序,如下图,左边是c++源码,右边是优化后顺序一条汇编指令的执行是可以分为很多步骤的,分为不同的硬件执行取指IF译码和取寄存器操作数ID执行或者有效地址计算EX(ALU逻辑计算单元)存储器访问MEM写回WB(寄存器)指令重排只可能发生在毫无关系的指令之间,如果指令之间存在依赖关系,则不会重排。单线程内程序的执行结果不能被改变。1原子性是指一个操作是不可中断的.

    2022年10月17日
  • 查询各种数据的网站_中国最全的数据网站

    查询各种数据的网站_中国最全的数据网站1、国家数据——主要用户:社会情况研究人员国家统计局开设网站,公布我国各个领域的宏观经济情况,权威度高2、中国裁判文书网——主要用户:法律从业/学习/爱好者中国最高人民法院开设,权威可信,可用于查询国内裁判文书,可作数据统计来源3、中国互联网数据平台——主要用户:互联网研究人员经国家主管部门批准组建的管理和服务机构,经常发布一些有价值的互联网信息报告4、中国信通院——主要用户:互…

  • matlab空间计量模型AIC和SC,空间计量模型[通俗易懂]

    matlab空间计量模型AIC和SC,空间计量模型[通俗易懂]回归分析中LMlag,LMerror后面的DFvaluefrob代表什么,哪一个是概率值?这个表的结论是所有的spatiallag都不显著,不要用spatialmodel,一般的OLS就行这一列(MI/DF这列)读下来就是Moran’sI的均值之类的东西(MI)等于-0.17,下面是各个LM检验的自由度,(LM检验是卡方分部所以有不同自由度)。第二列(value)是各个统计量的值,…

    2022年10月23日
  • 从【MySQL server has gone away】说起[通俗易懂]

    从【MySQL server has gone away】说起

  • Java安全之JNDI注入

    Java安全之JNDI注入

    2020年11月20日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号