本文系统版本:
[root@localhost ~]# cat /proc/version
Linux version 4.18.0-348.el8.x86_64 (mockbuild@kbuilder.bsys.centos.org) (gcc version 8.5.0 20210514 (Red Hat 8.5.0-3) (GCC)) #1 SMP Tue Oct 19 15:14:17 UTC 2021
下载链接:http://mirrors.aliyun.com/centos/8.5.2111/isos/x86_64/CentOS-8.5.2111-x86_64-dvd1.iso
本文引用内核代码文档版本:Linux-4.18.0-348.2.1.el8_5
源码路径:include\linux\sched\loadavg.h
下载链接:https://vault.centos.org/8.5.2111/BaseOS/Source/SPackages/kernel-4.18.0-348.2.1.el8_5.src.rpm
什么是负载平均值
两个关键词,其一是“负载”,即task(进程或线程,对应用户空间的treads)运行所需的系统资源(包括CPU、内存等),另一个是“平均”,某一段时间的平均值,Linux默认为1、5和15分钟的值。
怎么查看
较为常见的命令有uptime,top。
uptime
[root@localhost ~]# uptime
07:00:33 up 27 min, 1 user, load average: 0.06, 0.03, 0.00
由当前时间,系统运行时间,用户数和1、5、15分钟负载平均值组成。
top
top包含的信息非常多,较为全面,如果仅查看负载,第一行即可。
[root@localhost ~]# top | head -n 1
top - 07:00:51 up 27, 1 user, load average: 0.06, 0.03, 0.00
包含信息与uptime一样。
从何来
负载平均值的数据都来自于/proc/loadavg文件。
[root@localhost ~]# cat /proc/loadavg
0.06 0.03 0.00 4/170 2468
所含信息包括三个时间段的负载平均值,正在运行的tasks数/tasks总数,最近运行的task的pid。
怎么来
采取指数加权移动平均法,直接上内核源码。
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_SCHED_LOADAVG_H
#define _LINUX_SCHED_LOADAVG_H
/*
* These are the constant used to fake the fixed-point load-average
* counting. Some notes:
* - 11 bit fractions expand to 22 bits by the multiplies: this gives
* a load-average precision of 10 bits integer + 11 bits fractional
* - if you want to count load-averages more often, you need more
* precision, or rounding will get you. With 2-second counting freq,
* the EXP_n values would be 1981, 2034 and 2043 if still using only
* 11 bit fractions.
*/
extern unsigned long avenrun[]; /* Load averages */
extern void get_avenrun(unsigned long *loads, unsigned long offset, int shift);
#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) */
/*
* 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);
if (active >= load)
newload += FIXED_1-1;
return newload / FIXED_1;
}
extern unsigned long calc_load_n(unsigned long load, unsigned long exp,
unsigned long active, unsigned int n);
#define LOAD_INT(x) ((x) >> FSHIFT)
#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
extern void calc_global_load(void);
#endif /* _LINUX_SCHED_LOADAVG_H */
可以看到源码中已经给出了计算公式,a1=a0e+a(1-e)。
a1指当前时间的负载平均值;
a0指上一时刻的负载平均值;
a指某个指标的采样值;
e是一个常量系数,在计算不同时间时使用不同的常量系数,及源码中的EXP_1(1884)、EXP_5(2014)和EXP_15(2037),计算公式为1/exp(5/对应的时间数,单位为秒),exp()为求以自然常数e(值为2.71828)为底的指数函数。至于为什么选择e,这就是数学问题了,此处暂不拓展。
有什么用
负载平均值可以看出当前系统的负载情况。
如果load接近0,则意味着系统处于空闲状态,
如果1分钟的load高于5或15分钟的则说明负载在增加,低于则说明在减小。
如果load高于CPU核心数(如果使用了超线程技术),那么系统可能遇到了性能问题(当然,这也要看具体情况)。