精华内容
下载资源
问答
  • CPU负载

    千次阅读 2017-02-08 16:04:26
    确定cpu的负载的定义,帮助管理员设置cpu负载阀值,推测可能的导致cpu负载过高的原因,进而保证服务器的正常运行。
    以下内容转载于 http://blog.chinaunix.net/uid-12693781-id-368837.html,如有问题,请联系本人删除。

    1.cpu负载的定义
       首先,看看cpu负载的定义。在一般情况下可以将单核心cpu的负载看成是一条单行的桥,数字1代表cpu刚好能够处理过来,即桥上能够顺利通过所有的车辆,
    桥外没有等待的车辆,桥是畅通的。当超过1时表示有等待上桥的车辆,小于1时表示车辆能够快速的通过。单核心cpu就表示该cpu能够处理的事务数是1,在多核
    cpu中cpu能够并行处理的事务的数量应该是cpu个数*cpu核数,而且负载数最好不要超过这个数值。例如一个4核cpu,则cpu_load最大值为4,不能长期超过4,否则会有任务没有得到及时的处理,而使系统的负载累积增高,导致系统运行缓慢。
       大多数的Unix系统中的负载只是记录那些处在运行状态和可运行状态的进程,但是Linux有所不同,它会包含那些不可中断的处于睡眠状态的进程。这时当这些进程由于I/O的阻塞而不能够运行,就可能显著的增加cpu的负载。所以在Unix和Linux下的cpu的负载的计算方法是不一样的,在设定监测值的时候也需要特别考率。
       下面从内核源码中分析cpu负载的计算根源,这里能够给出cpu负载的完整计算方法。下面的代码是是在kernel-2.6.32中的kernel/shed.c中截取的,用来计算cpu的平均负载。
    /* Variables and functions for calc_load */
    static atomic_long_t calc_load_tasks;
    static unsigned long calc_load_update;
    unsigned long avenrun[3];
    EXPORT_SYMBOL(avenrun);

    /**
     * get_avenrun - get the load average array
     * @loads: pointer to dest load array
     * @offset: offset to add
     * @shift: shift count to shift the result left
     *
     * These values are estimates at best, so no need for locking.
     */
    void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
    {
    loads[0] = (avenrun[0] + offset) << shift;
    loads[1] = (avenrun[1] + offset) << shift;
    loads[2] = (avenrun[2] + offset) << shift;
    }

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

    /*
     * calc_load - update the avenrun load estimates 10 ticks after the
     * CPUs have updated calc_load_tasks.
     */
    void calc_global_load(void)
    {
    unsigned long upd = calc_load_update + 10;
    long active;

    if (time_before(jiffies, upd))
    return;

    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;
    }

    /*
     * Either called from update_cpu_load() or from a cpu going idle
     */
    static void calc_load_account_active(struct rq *this_rq)
    {
    long nr_active, delta;

    nr_active = this_rq->nr_running;  //记录在cpu上运行的进程数
    nr_active += (long) this_rq->nr_uninterruptible;  //记录不可中断的进程数

    if (nr_active != this_rq->calc_load_active) {
    delta = nr_active - this_rq->calc_load_active;
    this_rq->calc_load_active = nr_active;
    atomic_long_add(delta, &calc_load_tasks);
    }
    }
       从上面的代码特别是注释的两行可以看出,Linux记录cpu负载的时候是将cpu队列中的运行进程数和不可中断进程数都统计在内的,这样在对cpu负载分析的时候就需要考虑不可中断的进程的情况


    2.影响cpu负载的进程
      从定义可以看出cpu的负载主要来自在cpu运行的进程数,队列中准备就绪的进程数和不可中断进程数。那么当cpu负载过高的时候如果能够知道当前运行的进程的状态那么就能够判断是哪些进程的运行导致了问题。刚好,在Linux中ps可以帮助查找当前在运行的进程的状态,通过对这些进程的状态的了解,就能够很好的查找问题的真正原因。
      #ps aux可以显示进程的运行状态
      USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
      当使用ps aux后就可以得知一个进程的11项参数,其中STAT是显示进程的运行状态。
      进程的状态有以下几种。
      =================进程STAT状态==================== 
      D 无法中断的休眠状态(通常 IO 的进程)
      R 正在运行,在可中断队列中; 
      S 处于休眠状态,静止状态; 
      T 停止或被追踪,暂停执行; 
      W 进入内存交换(从内核2.6开始无效); 
      X 死掉的进程; 
      Z 僵尸进程不存在但暂时无法消除;
      W: 没有足够的记忆体分页可分配
      WCHAN 正在等待的进程资源;

      <:高优先级进程
      N: 低优先序进程
      L: 有记忆体分页分配并锁在记忆体内 (即时系统或捱A I/O),即,有些页被锁进内存
      s 进程的领导者(在它之下有子进程);
      l 多进程的(使用 CLONE_THREAD, 类似 NPTL pthreads);
      + 位于后台的进程组;

    3.防止cpu负载过高的方法
      短期来看,可以通过kill和killall来杀死一些影响cpu负载的进程,达到降低cpu负载的目的。
      这些进程的状态是可以利用ps 显示出来的,然后对相关的进程采取一定的措施就能在短时间内降低cpu的负载。
      关于kill和killall的用法,这里不做详细的介绍。

    4.cpu负载过高的进一步分析
      长远来看,要想cpu的负载不高,就要从cpu的利用率和当前的服务来进行分析。
      下面以具体的案例进行分析:
      我们有台服务器,当服务器的链接数过高时,就会导致nfs阻塞(该台服务器和另外一台服务采用nfs共享文件),这时wa为95.8%,负载马上就上升到180.

    server1:~$ est
        467 connections established
    当服务器有大量的链接数时会发生nfs阻塞的问题:
    root      2631  0.2  0.0      0     0 ?        D    Jul20  50:28 [nfsd]
    root      2632  0.2  0.0      0     0 ?        D    Jul20  49:24 [nfsd]
    root      2633  0.2  0.0      0     0 ?        S    Jul20  49:27 [nfsd]
    root      2634  0.2  0.0      0     0 ?        S    Jul20  49:47 [nfsd]
    root      2635  0.2  0.0      0     0 ?        S    Jul20  51:12 [nfsd]
    root      2636  0.2  0.0      0     0 ?        S    Jul20  49:00 [nfsd]
    root      2637  0.2  0.0      0     0 ?        S    Jul20  49:39 [nfsd]
    root      2638  0.2  0.0      0     0 ?        D    Jul20  50:24 [nfsd]

    server1:~$ top

    top - 16:13:12 up 14 days, 21:21,  2 users,  load average: 180.20, 59.85, 22.61
    Tasks: 125 total,   1 running, 124 sleeping,   0 stopped,   0 zombie
    Cpu :  2.3%us,  1.3%sy,  0.0%ni,  0.0%id, 95.8%wa,  0.0%hi,  0.5%si,  0.0%st
    Mem:   2076212k total,  2028752k used,    47460k free,     1804k buffers
    Swap:  2104472k total,  1089140k used,  1015332k free,   244076k cached

    通过这种简单的分析,就基本上可以断定问题处在nfs处,需要调整文件共享的方式。



    以下内容转载于http://www.blogjava.net/cenwenchu/archive/2008/06/30/211712.html,如有问题,请联系本人删除。

    CPU时间片

           为了提高程序执行效率,大家在很多应用中都采用了多线程模式,这样可以将原来的序列化执行变为并行执行,任务的分解以及并行执行能够极大地提高程序的运行效率。但这都是代码级别的表现,而硬件是如何支持的呢?那就要靠CPU的时间片模式来说明这一切。程序的任何指令的执行往往都会要竞争CPU这个最宝贵的资源,不论你的程序分成了多少个线程去执行不同的任务,他们都必须排队等待获取这个资源来计算和处理命令。先看看单CPU的情况。下面两图描述了时间片模式和非时间片模式下的线程执行的情况:


     1 非时间片线程执行情况


     2 非时间片线程执行情况

           在图一中可以看到,任何线程如果都排队等待CPU资源的获取,那么所谓的多线程就没有任何实际意义。图二中的CPU Manager只是我虚拟的一个角色,由它来分配和管理CPU的使用状况,此时多线程将会在运行过程中都有机会得到CPU资源,也真正实现了在单CPU的情况下实现多线程并行处理。

           CPU的情况只是单CPU的扩展,当所有的CPU都满负荷运作的时候,就会对每一个CPU采用时间片的方式来提高效率。

           Linux的内核处理过程中,每一个进程默认会有一个固定的时间片来执行命令(默认为1/100秒),这段时间内进程被分配到CPU,然后独占使用。如果使用完,同时未到时间片的规定时间,那么就主动放弃CPU的占用,如果到时间片尚未完成工作,那么CPU的使用权也会被收回,进程将会被中断挂起等待下一个时间片。

    CPU利用率和Load Average的区别

           压力测试不仅需要对业务场景的并发用户等压力参数作模拟,同时也需要在压力测试过程中随时关注机器的性能情况,来确保压力测试的有效性。当服务器长期处于一种超负荷的情况下运行,所能接收的压力并不是我们所认为的可接受的压力。就好比项目经理在给一个人估工作量的时候,每天都让这个人工作12个小时,那么所制定的项目计划就不是一个合理的计划,那个人迟早会垮掉,而影响整体的项目进度。

    CPU利用率在过去常常被我们这些外行认为是判断机器是否已经到了满负荷的一个标准,看到50%-60%的使用率就认为机器就已经压到了临界了。CPU利用率,顾名思义就是对于CPU的使用状况,这是对一个时间段内CPU使用状况的统计,通过这个指标可以看出在某一个时间段内CPU被占用的情况,如果被占用时间很高,那么就需要考虑CPU是否已经处于超负荷运作,长期超负荷运作对于机器本身来说是一种损害,因此必须将CPU的利用率控制在一定的比例下,以保证机器的正常运作。

    Load AverageCPULoad,它所包含的信息不是CPU的使用率状况,而是在一段时间内CPU正在处理以及等待CPU处理的进程数之和的统计信息,也就是CPU使用队列的长度的统计信息。为什么要统计这个信息,这个信息的对于压力测试的影响究竟是怎么样的,那就通过一个类比来解释CPU利用率和Load Average的区别以及对于压力测试的指导意义。

    我们将CPU就类比为电话亭,每一个进程都是一个需要打电话的人。现在一共有4个电话亭(就好比我们的机器有4核),有10个人需要打电话。现在使用电话的规则是管理员会按照顺序给每一个人轮流分配1分钟的使用电话时间,如果使用者在1分钟内使用完毕,那么可以立刻将电话使用权返还给管理员,如果到了1分钟电话使用者还没有使用完毕,那么需要重新排队,等待再次分配使用。


     3 电话使用场景

           上图中对于使用电话的用户又作了一次分类,1min的代表这些使用者占用电话时间小于等于1min2min表示使用者占用电话时间小于等于2min,以此类推。根据电话使用规则,1min的用户只需要得到一次分配即可完成通话,而其他两类用户需要排队两次到三次。

           电话的利用率 = sum (active use cpu time)/period

    每一个分配到电话的使用者使用电话时间的总和去除以统计的时间段。这里需要注意的是是使用电话的时间总和(sum(active use cpu time)),这与占用时间的总和(sum(occupy cpu time))是有区别的。(例如一个用户得到了一分钟的使用权,在10秒钟内打了电话,然后去查询号码本花了20秒钟,再用剩下的30秒打了另一个电话,那么占用了电话1分钟,实际只是使用了40秒)

    电话的Average Load体现的是在某一统计时间段内,所有使用电话的人加上等待电话分配的人一个平均统计。

    电话利用率的统计能够反映的是电话被使用的情况,当电话长期处于被使用而没有的到足够的时间休息间歇,那么对于电话硬件来说是一种超负荷的运作,需要调整使用频度。而电话Average Load却从另一个角度来展现对于电话使用状态的描述,Average Load越高说明对于电话资源的竞争越激烈,电话资源比较短缺。对于资源的申请和维护其实也是需要很大的成本,所以在这种高Average Load的情况下电话资源的长期“热竞争”也是对于硬件的一种损害。

    低利用率的情况下是否会有高Load Average的情况产生呢?理解占有时间和使用时间就可以知道,当分配时间片以后,是否使用完全取决于使用者,因此完全可能出现低利用率高Load Average的情况。由此来看,仅仅从CPU的使用率来判断CPU是否处于一种超负荷的工作状态还是不够的,必须结合Load Average来全局的看CPU的使用情况和申请情况。

    所以回过头来再看测试部对于Load Average的要求,在我们机器为8CPU的情况下,控制在10 Load左右,也就是每一个CPU正在处理一个请求,同时还有2个在等待处理。看了看网上很多人的介绍一般来说Load简单的计算就是2* CPU个数减去1-2左右(这个只是网上看来的,未必是一个标准)。

    补充几点:

    1.对于CPU利用率和CPU Load Average的结果来判断性能问题。首先低CPU利用率不表明CPU不是瓶颈,竞争CPU的队列长期保持较长也是CPU超负荷的一种表现。对于应用来说可能会去花时间在I/O,Socket等方面,那么可以考虑是否后这些硬件的速度影响了整体的效率。

    这里最好的样板范例就是我在测试中发现的一个现象:SIP当前在处理过程中,为了提高处理效率,将控制策略以及计数信息都放置在Memcached Cache里面,当我将Memcached Cache配置扩容一倍以后,CPU的利用率以及Load都有所下降,其实也就是在处理任务的过程中,等待Socket的返回对于CPU的竞争也产生了影响。

    2.未来多CPU编程的重要性。现在服务器的CPU都是多CPU了,我们的服务器处理能力已经不再按照摩尔定律来发展。就我上面提到的电话亭场景来看,对于三种不同时间需求的用户来说,采用不同的分配顺序,我们可看到的Load Average就会有不同。假设我们统计Load的时间段为2分钟,如果将电话分配的顺序按照:1min的用户,2min的用户,3min的用户来分配,那么我们的Load Average将会最低,采用其他顺序将会有不同的结果。所以未来的多CPU编程可以更好的提高CPU的利用率,让程序跑的更快。




    展开全文
  • CPU负载和 CPU使用率 这两个从一定程度上都可以反映一台机器的繁忙程度. cpu使用率反映的是当前cpu的繁忙程度,忽高忽低的原因在于占用cpu处理时间的进程可能处于io等待状态但却还未释放进入wait。 平均负载(load ...
  • CPU负载监控脚本代码

    2020-09-15 22:52:18
    CPU负载监控脚本代码,需要的朋友可以参考下
  • CPU负载生成器(Python 2) 该脚本允许在有限的时间段内生成固定的CPU负载。 为此,采用了PI控制器。 该脚本输入所需的CPU负载,实验的持续时间以及必须在其上生成负载的CPU内核。 控制器和CPU监视器在两个不同的...
  • CPU负载 没有依赖性。 let cpu = require ( 'cpu-load' ) // track the CPU load over the next 1 second cpu ( 1000 , function ( load ) { load //=> 0.03 (3%) } ) CPU 负载在多核机器上平均。 无需将 CPU ...
  • cpu负载判断

    2019-03-14 16:34:50
    实际上网上有很多不错的文章,但是个人还是喜欢用自己的语言简洁的描述一下,下面介绍的就是对于cpu负载的判断方法。 什么是cpu的负载? 我们都知道cpu是服务器的核心处理器。它就像是一条单向的道路,而...

    前言


    关于cpu的负载到底是什么?怎样判断cpu的负载到底是高还是低呢?实际上网上有很多不错的文章,但是个人还是喜欢用自己的语言简洁的描述一下,下面介绍的就是对于cpu负载的判断方法。



    什么是cpu的负载?



    我们都知道cpu是服务器的核心处理器。它就像是一条单向的道路,而系统运行的程序或者说进程就像是奔跑在该道路上的交通工具。

    想象一下,负载就代表着在某一时间段上正在奔跑和准备使用cpu公路的汽车的数量。

    当那些汽车的数量有很多的时候就代表着cpu公路的压力大,负载高,结果就是会造成堵车,大量汽车挤满了公路,得等前面的车跑完了,后面的车才能上,并且移动速度缓慢,这就是系统卡顿。再严重就是公路被压坏了,谁都走不了,这就是死机。而正常情况,应该是那些车辆的数量不高于cpu公路可承担的值,这就是正常的运行。




    如何判断当前系统cpu的负载的高低?



    在这里插入图片描述

    【1】首先,要查看系统的平均负载(load average)。它是某段时间内占用cpu时间的进程和等待cpu时间的进程数,这里等待cpu时间的进程是指等待被唤醒的进程,不包括处于wait状态进程,而后面三个值分别代表系统在1分钟、5分钟和15分钟的负载情况。



    【2】由于我们要查看的当前系统cpu的负载的高低,那么就要考虑cpu的数量及性能问题。这时要遵循两个原则:“有多少核心即为有多少负荷"和"核心的核心”。

    “有多少核心即为有多少负荷”:在多核处理中,你的系统均值不应该高于处理器核心的总数量。

    “核心的核心”: 不论核心分布在哪几颗cpu中,只需要计算核心的总数量即可。例如:两颗四核的cpu: 2*4=8 ,代表八个cpu内核。
    cpu个数 x 核心数 = 总核心数

    查看CPU的总核心数
    grep -c 'model name' /proc/cpuinfo  
    
    更多命令,链接如下:
    https://blog.csdn.net/GX_1_11_real/article/details/81026999
    


    【3】理论上每个核心的负荷不超过1.0,就代表系统在正常运行的范畴内。

    即   平均负载 除以 总核心数 <= 1.0 
    

    但是,实际上当这个值处于在 0.70 左右,为了避免负载持续飙升,怕cpu扛不住,就要开始对问题原因进行调查了;当系统负载时间处于1.00或者以上的时候,那么就应该马上解决这个问题。

    即   平均负载 除以 总核心数 <= 0.7 
    

    我们通常应该观察15分钟系统负载,然后再进行判断。因为如果1分钟的系统负荷大于1.0,而其他两个时间段都小于1.0,那么代表这只是暂时的;而观察15分钟内的系统负载仍大于1.0,则代表这个问题是持续的,需要进行解决。



    备注:

    sar查看cpu操作,请看下列链接:
    https://blog.csdn.net/GX_1_11_real/article/details/81318197

    展开全文
  • 【Linux】Linux查看机器负载-CPU负载 CPU使用率达到100%.pdf
  • CPU负载监控脚本代码.docx
  • linux 排查cpu负载过高异常,找到最耗CPU的进程,找到最耗CPU的线程,将线程PID转化为16进制
  • cpu负载

    2015-02-16 20:08:12
  • cpu_tray 显示Windows托盘中的当前CPU负载
  • 关于linux的CPU负载知识.pdf
  • CPU 负载观察和性能监测.pdf
  • CPU负载均衡之loadavg计算

    千次阅读 2020-06-26 10:10:12
    本文主要介绍如下内容: 1. CPU负载概念说明 2. CPU负载数据使用 3. CPU负载计算方式以及过程

    CPU负载均衡之loadavg计算

    前言

    本文分析关于loadavg 使用、计算相关内容(基于kernel 4.9),如下图:
    行文结构
    其中重点介绍CPU负载计算过程相关内容(源码网站参考:opengrok 和 bootlin);

    1. CPU负载

    负载:当前队列中排队的Task+正在running的Task数量之和与CPU能力的比值
    在这里插入图片描述

    1.1 一个味道很重的比喻

    这个概念又一个很形象的比喻:

    1. 游乐场很好玩,人超多,对应Task;
    2. 只有一个厕所(也可能有2、3、4个),对应CPU的核数;
    3. 一旦节假日去到游乐场,就会发现厕所排了很长的队;

    这种情况就是满负载了,嗯,有内个味儿了!!!

    1.2 核心概念说明

    name说明
    active task对应每个CPU上nr_running和nr_uninterruptible的task,在runqueue结构体中维护
    clac_load_tasks对应所有CPU中active的task之和
    avnrunsched中提供数组,用于记录和计算1、5、15分钟时的平均负载值,与直观的load显示比值为2048
    NO_HZkernel中定义的系统频率,倒数即1s的节拍数,每个节拍提供中断用于各类task使用,NO_HZ即在CPU空闲时关闭周期性的中断

    2. loadavg使用

    2.1 查看CPU 负载

    1. Linux、android的debug系统已经很好的集成了loadavg功能,再出现ANR、SWT等异常时,抓取的log信息中均会有当时loadavg情况;
    2. 可以通过系统提供命令查看
      • cat /proc/loadavg
      • uptime
      • dumpsys cpuinfo
      • top (top中没有显示loadavg)

    2.2 CPU负载数据的分析说明

    1. 三个数值分别代表:1分钟、5分钟、15分钟内的平均负载;
    2. 一个核满负载为1,一般的4核CPU满负载就是4,也存在只有一个核但是负载为3的情况,这说明CPU成为了block点;
    3. 可以看到的是统计的最小粒度为1min,其实这个统计主要代表一个趋势性的说明,即偶尔出现满负载并不可怕,如果一直长时间持续,则说明或者系统出现问题或者系统与HW资源不匹配了;
    4. 按照以往经验,如果负载一直维持在70%以内,那说明系统整体状况还是比较健康的,但是并不说明系统没有问题(可能这70%是异常task造成的)
    5. DVFS就是根据这个负载情况调节频率和电压的;

    3. 负载计算

    核心计算步骤如下三步:

    计算每个CPU当前活跃task数量:active task = nr_running和nr_uninterruptible
    在update的周期到来时,将nr_active更新到全局变量calc_load_tasks中;
    根据oldload和当前活跃task计算新负载:newload = load * exp + active * (FIXED_1 - exp);

    3.1 流程示意

    在这里插入图片描述
    上述图示展示了整个数据更新的过程,如下详细解释说明下:

    1. 涉及的数据:

    active:每个CPU上的运行Task
    calc_load_idle:在cpu进入idle时更新此值,避免进入idle后没有中断,在update周期到来时无法更新
    calc_load_tasks:全局变量,记录所有Task sum,实际做指数平均的active;
    avenrun:每个period计算出来的最终load,/proc/loadavg即读取这个值;

    1. 更新时机

    每次shcedule_tick调用calc_load_fold_active,在到达更新时机(即5s)时获取每个CPU的running和uninterruptible数值,更新每个CPU的active;
    每次tick_nohz_stop_sched_tick()进入Idle时调用calc_load_enter_idle获取当前CPU的active更新到calc_load_idle,提供给到之后使用;
    每次do_timer调用在到达更新时机(即5s+10tick)时根据calc_load_tasks、EXP(权重)、当前load计算新的load值;

    所谓更新时机,可参照这个图:
    在这里插入图片描述

    3.2 code跟踪

    3.2.1 文件目录:

    id路径
    1/kernel/fs/proc/loadavg.c
    2/kernel/kernel/shcedule/loadavg.c
    3/kernel/sched/sched.h
    4/kernel/sched/core.c
    5/kernel/timer/timekeeping.c

    3.2.2 loadavg 显示流程

    所有loadavg的使用其实都是基于/proc/loadavg,首先将这里做为入口:

    //ps:这里应该是基于5.72的,核心步骤不影响
    static int loadavg_proc_show(struct seq_file *m, void *v){
           unsigned long avnrun[3];
           get_avenrun(avnrun, FIXED_1/200, 0);//获取avnrun
      //写入loadavg,分别计算整数部分和小数部分       
           seq_printf(m, "%lu.%02lu %lu.%02lu %lu.%02lu %ld/%d %d\n",
                   LOAD_INT(avnrun[0]), LOAD_FRAC(avnrun[0]),
                   LOAD_INT(avnrun[1]), LOAD_FRAC(avnrun[1]),
                   LOAD_INT(avnrun[2]), LOAD_FRAC(avnrun[2]),
                   nr_running(), nr_threads,
                   idr_get_cursor(&task_active_pid_ns(current)->idr) - 1);//这里就是最后last_pid
           return 0;
           }
    
    static int __init proc_loadavg_init(void){
           proc_create_single("loadavg", 0, NULL, loadavg_proc_show);
           return 0;}//创建节点,显示内容为loadavg_proc_show
    fs_initcall(proc_loadavg_init);//系统启动时fs_initcall中注册init函数
    
    1. 在系统启动的时候将proc_loadavg_init启动起来;
    2. 核心函数为获取avenrun,然后分别计算整数部分和小数部分;

    这里需要理解的几个概念:

    avnrun,这个是从sched中直接获取过来的,中间经过一个简单转换(添加了10.24)
    nr_running 理解为number of runnable task
    LOAD_IN 右移11位,即取高位
    LOAD_FRAC 取低11位,运算乘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) */
    
    #define LOAD_INT(x) ((x) >> FSHIFT) //计算整数
    #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)//计算小数
    

    3.2.3 avenrun 计算

    1. proc下的avenrun数组是从sched下的avenrun经过运算得到的:
    void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
    {
    	loads[0] = (avenrun[0] + offset) << shift;
    	loads[1] = (avenrun[1] + offset) << shift;
    	loads[2] = (avenrun[2] + offset) << shift;
        //则对于运算来说就是添加了一个offset,即2048 / 200 / 2048=0.005 , 负载只取小数点后2位,所以添加了一个类似于四舍五入操作;
    }
    
    1. 在code中搜索,avenrun数组的计算赋值操作,即每个周期的计算load操作:
      • loadavg.c中calc_global_load函数中,完整计算;
        则可以很直观的看到avenrun(load average array)是通过calc_load相关函数更新的,此部分为详细计算过程:
    /*
     * calc_load - update the avenrun load estimates 10 ticks after the
     * CPUs have updated calc_load_tasks.
     *
     * Called from the global timer code.
     */
    void calc_global_load(unsigned long ticks)
    {
    	unsigned long sample_window;
    	long active, delta;
    
    	sample_window = READ_ONCE(calc_load_update);
    //没到更新时间5s + 10tick 则退出	
    	if (time_before(jiffies, sample_window + 10))
    		return;
    
    	/*
    	 * Fold the 'old' NO_HZ-delta to include all NO_HZ CPUs.
    	 */
    //这里首先会去读取load idle 的值,并将其更新到calc_load_tasks;	 
    	delta = calc_load_nohz_read();
    	if (delta)
    		atomic_long_add(delta, &calc_load_tasks);
    //获取active,实质就是读取calc_load_tasks
    	active = atomic_long_read(&calc_load_tasks);
    	active = active > 0 ? active * FIXED_1 : 0;
    //根据权重运算avenrun
    	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);
    //周期更新;
    	WRITE_ONCE(calc_load_update, sample_window + LOAD_FREQ);
    
    	/*
    	 * In case we went to NO_HZ for multiple LOAD_FREQ intervals
    	 * catch up in bulk.
    	 */
    //这里是用来cover一种情况,存在多个周期(n * 5s)在Idle,则一直没有更新;
    	calc_global_nohz();
    }
    
    /*
     * a1 = a0 * e + a * (1 - e)
     */
    static inline unsigned long
    calc_load(unsigned long load, unsigned long exp, unsigned long active)
    {
    	unsigned long newload;
    //核心计算公式:
    	newload = load * exp + active * (FIXED_1 - exp);
    //如果新增active比之前的完整还多,则newload + 1,体现趋势	
    	if (active >= load)
    		newload += FIXED_1-1;
    
    	return newload / FIXED_1;
    }
    

    这里的核心内容就是计算avenrun,即获取到active的和,使用指数平均的公式计算最终的load:

    1. 确认已经达到了统计时间,默认为5*HZ+10tick
    2. 获取active数量,直接读取calc_load_tasks(所有增加的和);
    3. 更新数组内容,通过公式计算:a1 = a0 * e + a * (1 - e) ,则这个公式:
      1. 分别在1、5、15分钟的条件下历史load的权重是不断增加的,也就是说新增加的active数量对于越久时间的统计影响越小(1884、2014、2037)
      2. 新增加的active task的影响是慢慢变缓的,即时间越久,整体计算出来的数据越趋向于active_task

    3.2.4 计算active

    在code中搜索,active的计算赋值操作为:

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

    是直接读取的calc_load_tasks,更新这个变量的位置:

    1. atomic_long_add(delta, &calc_load_tasks),每次scheduler_tick时检测到达更新周期时add;
    2. delta = calc_load_fold_idle(),进入idle更新到数组中,在do_timer进入global计算时更新;
    /*
    * Called from scheduler_tick() to periodically update this CPU's
    * active count.
    */
    void calc_global_load_tick(struct rq *this_rq)
    {
        long delta;
    // now is befor update tick, do nothing
        if (time_before(jiffies, this_rq->calc_load_update))
            return;
    // now is in update tick ,read the per-cpu nr_active
        delta  = calc_load_fold_active(this_rq, 0);
        if (delta)
            atomic_long_add(delta, &calc_load_tasks);
    //normal update, is rq
        this_rq->calc_load_update += LOAD_FREQ;
    }
    

    上述函数是per-cpu更新的位置;

    //进入idle的时候将数据更新到calc_load_idle数组中,需要根据idx和时间判断具体添加位置
    void calc_load_enter_idle(void)
    {
        struct rq *this_rq = this_rq();
        long delta;
    
    // when the cpu is enter idle, update the load to calc_load_idle;
    // we will use idx to choose if this load is used in this update tick;
        delta = calc_load_fold_active(this_rq, 0);
        if (delta) {
            int idx = calc_load_write_idx();
            atomic_long_add(delta, &calc_load_idle[idx]);
        }
    }
    //决策添加的数组,这部分内容看下图理解会更方便
    static inline int calc_load_write_idx(void)
    {
        int idx = calc_load_idx;
        /*
         * See calc_global_nohz(), if we observe the new index, we also
         * need to observe the new update time.
         */
        smp_rmb();
        /*
         * If the folding window started, make sure we start writing in the
         * next idle-delta.
         */
    //qyp :core, if per-cpu is calc load and then this perid idle update is used in next freq
        if (!time_before(jiffies, calc_load_update))
            idx++;
        return idx & 1;
    }
    
    
    //在global更新的时候读取对应的数组内容;
    static long calc_load_fold_idle(void)
    {
        int idx = calc_load_read_idx();
        long delta = 0;
    // use idx to choose the calc_load_idle, and return it
        if (atomic_long_read(&calc_load_idle[idx]))
            delta = atomic_long_xchg(&calc_load_idle[idx], 0);
    
        return delta;
    }
    //读取idx
    static inline int calc_load_read_idx(void)
    {
        return calc_load_idx & 1;
    }
    //退出idle的时候判断当前jiffies,即如果已经进入下个周期,则更新时间点
    void calc_load_exit_idle(void)
    {
        struct rq *this_rq = this_rq();
    // use the globle calc_load_update to forbidden the rq update tick is multi period no update      
        this_rq->calc_load_update = calc_load_update;
    //if now is before per-cpu update tick : return     
        if (time_before(jiffies, this_rq->calc_load_update))
            return;
    //if now is before avnrun update tick : update the update tick,because we can not enter the tick to update it;      
        if (time_before(jiffies, this_rq->calc_load_update + 10))
            this_rq->calc_load_update += LOAD_FREQ;
    }
    

    这个过程比较比较复杂,首先查看比较古老的版本,学习思想,再回来查看其设计方法:

    1. 实质:计算每个CPU上的nr_running和uninterrupt_sleep的数量,并返回;
    2. 过程中添加了一个记录idle状态的全局变量,用于更新当前的active数值,这里搞这么复杂实际上是为了解决进入IDLE后没有中断更新load的情况:
      1. 在进入Idle时,将load 数量更新到idle数组中;
      2. 到达更新点的时候,统一计算完整的idle数组中值,通过数组以及idx自增的方式判断实际的进入Idle时间以及是否需要计算;
      3. 退出idle时需要判断此时是否已经到达cpu计算load的时间点,如果已经到达,则更新update时间,避免重复计算 ;
        在这里插入图片描述

    3.2.4 这里有个很好玩的计算

    对于可能存在的多个周期的idle情况,会调用到这里,这里就是会计算N个周期的load情况
    通过数学公式计算可以发现其实N个周期后的计算公式为:
    an = a0 * e^n + a * (1 - e) * (1 + e + … + e^n-1) [1]
    = a0 * e^n + a * (1 - e) * (1 - e^n)/(1 - e)
    = a0 * e^n + a * (1 - e^n)
    所以这里会直接实现对应en的效果:

    static void calc_global_nohz(void)
    {
        long delta, active, n;
    // in globle update tick
        if (!time_before(jiffies, calc_load_update + 10)) {
            /*
             * Catch-up, fold however many we are behind still
             */
    //calc the period
            delta = jiffies - calc_load_update - 10;
            n = 1 + (delta / LOAD_FREQ);
    
            active = atomic_long_read(&calc_load_tasks);
            active = active > 0 ? active * FIXED_1 : 0;
    //calc the n avenrun
            avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n);
            avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n);
            avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
    //update globle tick
            calc_load_update += n * LOAD_FREQ;
        }
    
    
        /*
         * Flip the idle index...
         *
         * Make sure we first write the new time then flip the index, so that
         * calc_load_write_idx() will see the new time when it reads the new
         * index, this avoids a double flip messing things up.
         */
        smp_wmb();
        calc_load_idx++;
    }
    
    

    上述函数是计算周期N的值,然后调用calc_load_n来计算上述公式:

    static unsigned long
    calc_load_n(unsigned long load, unsigned long exp,
            unsigned long active, unsigned int n)
    {
    // math calc: n period = load * exp ^ n + active * (1-exp^n)
        return calc_load(load, fixed_power_int(exp, FSHIFT, n), active);
    }
    

    那么en是怎么计算的呢?就在下边(通过右移减少计算次数):

    static unsigned long
    fixed_power_int(unsigned long x, unsigned int frac_bits, unsigned int n)
    {
        unsigned long result = 1UL << frac_bits;// * 2048
    //use bit to calc e^n = e^1 * e^2 * e^4
        if (n) {
            for (;;) {
                if (n & 1) {
                //对应bit有则*x
                    result *= x;
                    result += 1UL << (frac_bits - 1);
                    result >>= frac_bits;
                }
                n >>= 1;
                if (!n)
                    break;
            //更新x x^2 x^4 .....        
                x *= x;
                x += 1UL << (frac_bits - 1);
                x >>= frac_bits;
            }
        }
    
        return result;
    }
    

    问题记录

    1. 为什么avenrun计算的三个权重分别为1884、2014、2037,这个是如何决定的?
      在这里插入图片描述
      这里的系数是按照上述公式决定的即:2048 * (1 / e ^ (5s / period) )
    2. 为什么在5s一次的统计过程中要+10 tick,而且核心计算公式其实很简单,为什么流程要搞这么复杂?
      A:
      1. 由于存在多核情况,在计算各个核的load时和整体load更新时存在竞争,所以修改为在5HZ时各个CPU计算,而在+10tick之后更新给到AVGRUN;
      2. 由于存在nohz的情况,即IDLE时不会有中断更新计算load,所以要引入新的计算补足这一部分;
        在这里插入图片描述
    3. 关于do_timer和scheduler_tick相关调度的整体逻辑是怎样的?
      A: 实质就是在周期性中断到来的时候,调度对应函数检测是否到达更新周期进行计算;
    展开全文
  • cpu利用率和cpu负载是什么?

    千次阅读 2018-09-22 18:53:23
    我们经常会听到要好好使用cpu的资源,提高cpu利用率,要学习应对高负载的情况,那这个高负载其实大多数情况指的就是cpu负载。我们还会学习到一个命令是top,这个命令可以得到他们的数值和其他系统指标。那么什么是...
  • CPU负载解决办法

    2019-11-07 16:58:26
    1. 查看CPU负载 使用top 命令 2. 打印出堆栈信息 [root@hadoop ~]# jstack PID > 7669.txt 3.把堆栈信息 [root@hadoop ~]# sz 7669,txt 4.查看线程占用情况 [root@hadoop ~]# top -p 7669 -H PID进制...
  • linux 排查cpu负载过高原因

    千次阅读 2019-11-05 11:37:58
    CPU负载查看方法: 使用vmstat查看系统维度的CPU负载 使用top查看进程维度的CPU负载 使用 vmstat 查看系统纬度的 CPU 负载: 可以通过 vmstat 从系统维度查看 CPU 资源的使用情况。 用法说明: 格式:vmstat -n 1#...
  • CPU 负载CPU 使用率 这两个从一定程度上都可以反映一台机器的繁忙程度。 CPU 使用率反映的是当前 CPU 的繁忙程度,忽高忽低的原因在于占用 CPU 处理时间的进程可能处于 IO 等待状态但却还未释放进入wait。 ...
  • CPU使用率 和 CPU负载 的区别

    千次阅读 2018-06-16 14:47:53
    cpu使用率就是cpu使用的多少。cpu负载就是cpu最大能承载的能力。CPU利用率显示的是程序在运行期间实时占用的CPU百分比,而CPU负载显示的是一段时间内正在使用和等待使用CPU的平均任务数。 ...
  • 服务器程序有时候不知道是什么原因导致CPU异常变高,每次变高都需要手工重启程序或服务,很麻烦,于是我就写了这个程序分享给网友朋友,希望能够帮...使用说明,可自定义CPU负载多少,持续多少秒,执行相关bat或程序。
  • CPU 负载观察和性能监测

    千次阅读 2016-09-28 22:55:39
    CPU负载和利用率CPU 的负载和利用率是两个不同的概念,但是他们都可以在top命令中查看。CPU利用率显示的是程序在运行期间实时占用的CPU百分比,而CPU负载显示的是一段时间内正在使用和等待使用CPU的平均任务数。CPU...
  • CPU负载120%

    2018-12-05 22:39:39
    CPU负载120% 概述 背景:生产环境服务响应缓慢,出现RPC接口超时 排查: 服务双机部署,登录两台日志机器,登录两台部署机器 查看部署机器服务负载, top 查看,同一台机器上部署三个服务 其中A服务,CPU 120% ...
  • 最近服务器的CPU负载经常报警,然而CPU的利用率并不是特别高。这里对这两个概念做一下说明。 CPU负载
  • Linux中CPU负载和CPU使用率表示的含意   机器为CentOS系统,服务器CPU负载信息如下: WARNING - load average: 9.73, 10.67, 10.49   一、警报信息的三个参数到底是什么意思? 9.73、10.67、10.49分别代表前...
  • zabbix cpu负载

    2019-09-11 15:17:49
    标签:zabbix cpu负载值 首先,现在的CPU都是多核的,所以参数里默认显示的一个核心的参数,而不是总和,解决方法。 中文路径:组态--模板,里找个你监控主机使用的模板,我使用的模板是“Template OS Linux” ...
  • cpu负载过高原因

    2020-09-28 09:30:05
    CPU 使用率低高负载的原因,看看这篇! https://segmentfault.com/a/1190000020459073 linux 排查cpu负载过高原因 https://blog.csdn.net/qq_40907977/article/details/102912861
  • 主要介绍了分析MySQL中索引引引发的CPU负载飙升的问题,文中提到了独立索引所带来的巨大CPU负担,以提醒在MySQL中使用索引要注意CPU负载的问题,需要的朋友可以参考下
  • 哪些工具可以查看 CPU 负载? 可以使用 top 命令、uptime 命令,特别是 top 命令,功能强大,不仅仅可以用来查看 CPU 负载CPU 负载怎么理解?是不是 CPU 利用率? 要区别 CPU 负载CPU 利用率,它们是不同...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 269,619
精华内容 107,847
关键字:

CPU负载