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)

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • privacypolicy什么意思_privacyversion

    privacypolicy什么意思_privacyversion隐私政策网址(URL)移动APP应用尊重和保护利用用户的隐私所有的服务。为了向您提供更准确,更人性化的服务,将移动APP应用使用和披露按照本隐私政策您的个人信息。但是移动APP应用将是一个高度的勤勉,审慎义务对待这些信息。除本隐私政策另有规定外,未经您的许可之前,移动APP应用信息将不会被披露或向第三方提供。移动APP应用更新本隐私政策不时。当您同意移动APP应用服务协议,您将被视为……

    2022年9月2日
    2
  • 解决Pycharm无法显示matplotlib绘图问题(ubuntu环境)「建议收藏」

    解决Pycharm无法显示matplotlib绘图问题(ubuntu环境)「建议收藏」1.首先,确保环境(虚拟环境)中已经安装了matplotlib模块首先切换到虚拟环境中,然后安装安装命令:condainstallmatplotlib2.确定你的pycharm使用的环境是你的虚拟环境(1)在pycharm中添加虚拟环境pycharm默认使用的环境可能并不是你想用的虚拟环境:如图在file->settings里面可以找到配置虚拟环境的窗口。点1,…

    2022年8月28日
    2
  • 治疗治愈埃博拉病毒(非科幻)

    治疗治愈埃博拉病毒(非科幻)

    2022年1月2日
    64
  • PyCharm激活码永久有效PyCharm2021.1.2激活码教程-持续更新,一步到位

    PyCharm激活码永久有效PyCharm2021.1.2激活码教程-持续更新,一步到位PyCharm激活码永久有效2021.1.2激活码教程-Windows版永久激活-持续更新,Idea激活码2021.1.2成功激活

    2022年6月19日
    40
  • 免费已备案二级域名_二级免备案域名

    免费已备案二级域名_二级免备案域名今天给大家推荐一个免备案的免费二级域名注册平台。DYUNS域名网-永久免费域名_免备案域名只需要一个邮箱,就能注册到自己的二级域名,非常方便。提供”icu.ltd”等超短域名注册服务,非常有利于用户访问与记忆。平台还提供了免费的CDN+防御+免备案服务,这是其他平台都没有的,也是我选择它的理由之一。管理也非常方便,后台一键就能完成自助删改解析等操作。官方客服的服务也是十分的到位,体验很好。大家也可以自行注册体验哦!…

    2022年9月10日
    0
  • PAT备考经验&相关信息[通俗易懂]

    在9月8号下午的PAT考试中,我幸运的拿到了满分,用时1小时45分钟,排名第五,算是成功迈出了转专业的第一步。按照惯例应该嘚瑟一波,然而身边并没有人考这个,转念一想,不如把考试日志和备考经验教训记录下来,以期看见此文的后来者能少走一些弯路,更加高效的刷题学习(虽然可能并没有人能看到 _(:△」∠)_)。当然,在科班大佬面前我只是个尚未入门的弱鸡,因此这篇经验主要针对有意转行/业余爱好编程/基…

    2022年4月7日
    104

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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