相信很多人都对Linux中top命令里“load average”这一栏困惑过,到底什么是Load,Load代表了什么含义,Load高会有什么后果?“%CPU”这一栏为什么会超过100%,它是如何计算的?
带着这些问题,我们通过一些测试,来探索下其中的不解之处。

首先,我们通过实验来大概确定其计算方式:
测试服务器:4核Xeon处理器
测试软件:MySQL 5.1.40
服务器上除了mysql没有运行其他任何非系统自带软件。因为MySQL只能单线程运行单条SQL,所以可以很好的通过增加查询并发来控制使用的CPU核数。

空载时,top的信息为:

top – :: up  days, :,  user, load average: 0.00, 0.00, 0.00
Tasks: total, running, sleeping, stopped, zombie
Cpu(s): 0.0%us, 0.0%sy, 0.0%ni, 99.5%id, 0.1%wa, 0.2%hi, 0.2%si, 0.0%st

数据库中启动一个大查询:

top – :: up  days, :,  users, load average: 0.99, 0.92, 0.67
Tasks: total, running, sleeping, stopped, zombie
Cpu0 : 0.0%us, 0.0%sy, 0.0%ni, 96.3%id, 0.0%wa, 1.3%hi, 2.3%si, 0.0%st
Cpu1 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu2 : 98.7%us, 1.3%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu3 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

同时可以看到%CPU也是在100%

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
mysql 308m 137m S 99.9 6.8 :13.28 mysqld

然后开启第二个大查询,不久就可以看到top信息的变化,Load到了2:

top – :: up  days, :,  users, load average: 1.99, 1.62, 1.08
Tasks: total, running, sleeping, stopped, zombie
Cpu0 : 0.0%us, 0.0%sy, 0.0%ni, 97.7%id, 0.0%wa, 1.0%hi, 1.3%si, 0.0%st
Cpu1 : 99.0%us, 1.0%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu2 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu3 : 99.0%us, 1.0%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

也可以观察到%CPU增加到了200%:

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
mysql 312m 141m S 199.8 7.0 :31.27 mysqld

由此可以简单的做出如下临时结论:
1. %CPU是由每个核的CPU占用律之和算出来的。
2. load跟执行的任务数有关
不过要想准确的知道其含义,还是必须从源码入手。

CPU利用率的计算方法

下载busybox的源码,在procps目录下有top.c的源码,查看第293行附近(1.17.1版),可以看到

if (prev_hist_count) do {
if (prev_hist[i].pid == pid) {
cur->pcpu = cur->ticks - prev_hist[i].ticks;
total_pcpu += cur->pcpu;
break;
}
i = (i+) % prev_hist_count;
/* hist_iterations++; */
} while (i != last_i);

这就是计算%CPU的代码,很明显total_pcpu就是累加了每个线程对每个核的使用率,所以%CPU的最大值就是核数*100%。

而CPU利用率又是怎么计算的呢,跟踪代码可以发现,是从系统的/proc/stat这里读取的,这个文件的格式可以参考:http://www.linuxhowtos.org/System/procstat.htm,下面是我笔记本上读出来的内容。

plx@plinux-Laptop:~/busybox-1.17.$ cat /proc/stat
cpu
cpu0
cpu1
intr
ctxt
btime
processes
procs_running
procs_blocked
softirq

cpuN的含义从左到右分别是:user、system、nice、idle、iowait、irq、softirq,具体含义可以看文档。
在下面几行的含义是:
“intr”这行给出中断的信息,第一个为自系统启动以来,发生的所有的中断的次数;然后每个数对应一个特定的中断自系统启动以来所发生的次数。
“ctxt”给出了自系统启动以来CPU发生的上下文交换的次数。
“btime”给出了从系统启动到现在为止的时间,单位为秒。
“processes (total_forks) 自系统启动以来所创建的任务的个数目。
“procs_running”:当前运行队列的任务的数目。
“procs_blocked”:当前被阻塞的任务的数目。
那么CPU利用率可以使用以下方法,先取两个采样点,然后计算其差值:

cpu usage=(idle2-idle1)/(cpu2-cpu1)* cpu usage=[(user_2 +sys_2+nice_2) - (user_1 + sys_1+nice_1)]/(total_2 - total_1)*;

这是一段Bash代码采集利用率的,摘自网络:

#!/bin/sh
##echo user nice system idle iowait irq softirq
CPULOG_1=$(cat /proc/stat | grep 'cpu ' | awk '{print $2" "$3" "$4" "$5" "$6" "$7" "$8}')
SYS_IDLE_1=$(echo $CPULOG_1 | awk '{print $4}')
Total_1=$(echo $CPULOG_1 | awk '{print $1+$2+$3+$4+$5+$6+$7}') sleep CPULOG_2=$(cat /proc/stat | grep 'cpu ' | awk '{print $2" "$3" "$4" "$5" "$6" "$7" "$8}')
SYS_IDLE_2=$(echo $CPULOG_2 | awk '{print $4}')
Total_2=$(echo $CPULOG_2 | awk '{print $1+$2+$3+$4+$5+$6+$7}') SYS_IDLE=`expr $SYS_IDLE_2 - $SYS_IDLE_1` Total=`expr $Total_2 - $Total_1`
SYS_USAGE=`expr $SYS_IDLE/$Total* |bc -l` SYS_Rate=`expr -$SYS_USAGE |bc -l` Disp_SYS_Rate=`expr "scale=3; $SYS_Rate/1" |bc`
echo $Disp_SYS_Rate%

还有一段Perl的代码,也是摘自网络:

#!/usr/bin/perl
use warnings; $SLEEPTIME=; if (-e "/tmp/stat") {
unlink "/tmp/stat";
}
open (JIFF_TMP, ">>/tmp/stat") || die "Can't open /proc/stat file!\n";
open (JIFF, "/proc/stat") || die "Can't open /proc/stat file!\n";
@jiff_0=;
print JIFF_TMP $jiff_0[] ;
close (JIFF); sleep $SLEEPTIME; open (JIFF, "/proc/stat") || die "Can't open /proc/stat file!\n"; @jiff_1=;
print JIFF_TMP $jiff_1[];
close (JIFF);
close (JIFF_TMP); @USER=`awk '{print \$2}' "/tmp/stat"`;
@NICE=`awk '{print \$3}' "/tmp/stat"`;
@SYSTEM=`awk '{print \$4}' "/tmp/stat"`;
@IDLE=`awk '{print \$5}' "/tmp/stat"`;
@IOWAIT=`awk '{print \$6}' "/tmp/stat"`;
@IRQ=`awk '{print \$7}' "/tmp/stat"`;
@SOFTIRQ=`awk '{print \$8}' "/tmp/stat"`; $JIFF_0=$USER[]+$NICE[]+$SYSTEM[]+$IDLE[]+$IOWAIT[]+$IRQ[]+$SOFTIRQ[];
$JIFF_1=$USER[]+$NICE[]+$SYSTEM[]+$IDLE[]+$IOWAIT[]+$IRQ[]+$SOFTIRQ[];
$SYS_IDLE=($IDLE[]-$IDLE[]) / ($JIFF_0-$JIFF_1) * ; $SYS_USAGE= - $SYS_IDLE; printf ("The CPU usage is %1.2f%%\n",$SYS_USAGE);

Load的计算方法

跟踪busybox的代码可以知道,load是从/proc/loadavg中读取的。
我本机的一次抓取内容如下:

plx@plinux-Laptop:~/busybox-1.17.$ cat /proc/loadavg
0.64 0.81 0.86 /

每个值的含义依次为:
lavg_1 (0.64) 1-分钟平均负载
lavg_5 (0.81) 5-分钟平均负载
lavg_15(0.86) 15-分钟平均负载
nr_running (3) 在采样时刻,运行队列的任务的数目,与/proc/stat的procs_running表示相同意思
nr_threads (364) 在采样时刻,系统中活跃的任务的个数(不包括运行已经结束的任务)
last_pid(6930) 最大的pid值,包括轻量级进程,即线程。
假设当前有两个CPU,则每个CPU的当前任务数为0.64/2=0.32

我们可以在linux内核中找到loadavg文件的源码:

tatic int loadavg_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int a, b, c;
int len;
# a = avenrun[] + (FIXED_1/);
b = avenrun[] + (FIXED_1/);
c = avenrun[] + (FIXED_1/);
len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n",
LOAD_INT(a), LOAD_FRAC(a),
LOAD_INT(b), LOAD_FRAC(b),
LOAD_INT(c), LOAD_FRAC(c),
nr_running(), nr_threads, last_pid);
return proc_calc_metrics(page, start, off, count, eof, len);
}

以及计算load的代码:

#define FSHIFT      11          /* nr of bits of precision */
#define FIXED_1 (1<<FSHIFT) /* 1.0 as fixed-point(定点) */
#define LOAD_FREQ (5*HZ) /* 5 sec intervals,每隔5秒计算一次平均负载值 */
#define CALC_LOAD(load, exp, n) \
load *= exp; \
load += n*(FIXED_1 - exp); \
load >>= FSHIFT; unsigned long avenrun[]; EXPORT_SYMBOL(avenrun); /*
* calc_load - given tick count, update the avenrun load estimates.
* This is called while holding a write_lock on xtime_lock.
*/
static inline void calc_load(unsigned long ticks)
{
unsigned long active_tasks; /* fixed-point */
static int count = LOAD_FREQ;
count -= ticks;
if (count < ) {
count += LOAD_FREQ;
active_tasks = count_active_tasks();
CALC_LOAD(avenrun[], EXP_1, active_tasks);
CALC_LOAD(avenrun[], EXP_5, active_tasks);
CALC_LOAD(avenrun[], EXP_15, active_tasks);
}
}

看了大师的文章,理解了这些代码。

所以可以明白:Linux的系统负载指运行队列的平均长度,也就是等待CPU的平均进程数。 Linux的系统负载指运行队列的平均长度,也就是等待CPU的平均进程数。因为Linux内禁止浮点运算,因此系统的负载只能通过计算变化的次数这一修正值来计算。Linux内核定义一个长度为3的双字数组avenrun,双字的低11位用于存放负载的小数部分,高21位用于存放整数部分。当进程所耗的 CPU时间片数超过CPU在5秒内能够提供的时间片数时,内核计算上述的三个负载。负载初始化为0,假设最近1、5、15分钟内的平均负载分别为 load1、load5和load15,那么下一个计算时刻到来时,内核通过下面的算式计算负载:

load1 -= load1 -* exp(- / ) -+ n * ( – exp(- /  ))
load5 -= load5 -* exp(- / ) + n * ( – exp(- / ))
load15 = load15 * exp(- / ) + n * ( – exp(- / ))

其中,exp(x)为e的x次幂,n为当前运行队列的长度。Linux内核认为进程的生存时间服从参数为1的指数分布,指数分布的概率密度为:以内核计算负载load1为例,设相邻两个计算时刻之间系统活动的进程集合为S0。从1分钟前到当前计算时刻这段时间里面活动的load1个进程,设他们的集合是 S1,内核认为的概率密度是:λe-λx,而在当前时刻活动的n个进程,设他们的集合是Sn内核认为的概率密度是1-λe-λx。其中x = 5 / 60,因为相邻两个计算时刻之间进程所耗的CPU时间为5秒,而考虑的时间段是1分钟(60秒)。那么可以求出最近1分钟系统运行队列的长度:

load1 = |S1| -* λe-λx + |Sn| * (-λe-λx) = load1 * λe-λx + n * (-λe-λx)

其中λ = 1, x = 5 / 60, |S1|和|Sn|是集合元素的个数,这就是Linux内核源文件shed.c的函数calc_load()计算负载的数学依据。

所以“Load值=CPU核数”,这是最理想的状态,没有任何竞争,一个任务分配一个核。
由于数据是每隔5秒钟检查一次活跃的进程数,然后根据这个数值算出来的。如果这个数除以CPU的核数,结果高于5的时候就表明系统在超负荷运转了。

 
 
 

Load和CPU利用率是如何算出来的的更多相关文章

  1. [进程管理]Load和CPU利用率是如何算出来的

    本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明 网址: http://www.penglixun.com/tech/system/how_to_ca ...

  2. Load和CPU利用率是如何算出来的 (转发)

    本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/system/how_to_cal ...

  3. 系统服务监控指标--load、CPU利用率、磁盘剩余空间、磁盘I/O、内存使用情况等

    介绍 大型互联网企业的背后,依靠的是成千上万台服务器日夜不停的运转,以支撑其业务的运转.宕机对于互联网企业来说,代价是沉重的,轻则影响用户体验,重则直接影响交易,导致交易下跌,并且给企业声誉造成不可挽 ...

  4. CPU利用率和CPU负荷(CPU usage vs CPU load)

    对于CPU的性能监测,通常用top指令能显示出两个指标:cpu 利用率和cpu负荷. 其中%Cpu相关的内容: us表示用户进程cpu利用率,sy表示系统内核进程cpu利用率,ni表示运行正常进程消耗 ...

  5. CPU利用率与Load Average的区别?

    CPU利用率,是对一个时间段内CPU使用状况的统计,通过这个指标可以看出在某一个时间段内CPU被占用的情况,如果CPU被占用时间很高,那么就需要考虑CPU是否已经处于超负荷运作,长期超负荷运作对于机器 ...

  6. Linux下如何查看高CPU占用率线程 LINUX CPU利用率计算

    目录(?)[-] proc文件系统 proccpuinfo文件 procstat文件 procpidstat文件 procpidtasktidstat文件 系统中有关进程cpu使用率的常用命令 ps ...

  7. 浅谈Linux下CPU利用率和CPU负载【转】

    转自:https://blog.csdn.net/Alisa_xf/article/details/71430406 在Linux/Unix下,CPU利用率(CPU utilization)分为用户态 ...

  8. cpu利用率和cpu 队列

    SIP的第四期结束了,因为控制策略的丰富,早先的的压力测试结果已经无法反映在高并发和高压力下SIP的运行状况,因此需要重新作压力测试.跟在测试人员后面做了快一周的压力测试,压力测试的报告也正式出炉,本 ...

  9. linux系统性能监控--CPU利用率

    在对系统的方法化分析中,首要且最基本的工具之一常常是对系统的 CPU利用率进行简单测量. Linux以及大多数基于 UNIX的操作系统都提供了一条命令来显示系统的平均负荷(loadaverage) . ...

随机推荐

  1. PhotoZoom Pro 7怎么进行参数设置

    每个用户在使用PhotoZoom时,在针对不同的图片,我们处理的方式也不同.所以在参数设置会因图片不同而不同.那么在PhotoZoom中参数究竟如何设置呢? 首先,我们先打开[参数设置],点击后会弹出 ...

  2. UWP添加数字证书导出安装包本地安装

    先生成一个简单的HelloWorld应用程序 <Page x:Class="HelloWorld.MainPage" xmlns="http://schemas.m ...

  3. JS 封装一个显示时间的函数

    s(); function s (){ var mydate=new Date(); var y = mydate.getFullYear(); var m = mydate.getMonth(); ...

  4. 路飞学城Python-Day151

    sprapy框架能够在pycharm中调试的方式 需要在配置文件中加上一个文件,文件的内容为 start.py #!/usr/bin/env python # -*- coding:utf-8 -*- ...

  5. 路飞学城Python-Day115

    个人博客搭建 from django.db import models from django.contrib.auth.models import User, AbstractUser # Crea ...

  6. centos7.XXX配置python3环境

    众做周知,centos 是自带python2.7的.可是随着社会的进步,科技的发展,技术一步步更新换代,python2.7已经不足以满足项目的需求.这时候python3横空出世. 下面跟着我来一起实现 ...

  7. Project Euler 48 Self powers( 大数求余 )

    题意: 项的自幂级数求和为 11 + 22 + 33 + - + 1010 = 10405071317. 求如下一千项的自幂级数求和的最后10位数字:11 + 22 + 33 + - + 100010 ...

  8. [NoiPlus2016]天天爱跑步

    巨坑 树剖学的好啊!---sfailsth 把一段路径拆成两段,向上和S->LCA,向下LCA->T 用维护重链什么的操作搞一下. sfailsth学长真不容易啊...考场上rush了4. ...

  9. 无edu邮箱如何申请onedirve 5T账户

    如何申请onedirve 5T账户 要申请onedrive的教育版,一般是需要教育邮箱的.但如果没有教育邮箱,则需要找一些学校的漏洞来申请. 第一个方法是申请国外学校的校友邮箱,这就需要相应的校友信息 ...

  10. 关于NumPy的坑

         初次接触NumPy的时候,感叹这个功能的强大,实现了Python对矩阵的运算,但在写一个项目的时候,发现了一个巨坑无比的情况     分隔符=================     对于被 ...