讀取系統(tǒng) load average
uptime 或者 top 可以顯示系統(tǒng)的 load average. 比如:
[root@localhost ~]# uptime
15:54:04 up 106 days, 6:35, 7 users, load average: 1.45, 1.76, 2.02
三個(gè)數(shù)字分別表示1,5,15分鐘的數(shù)據(jù)崖堤。
load average 中的 load
load average 顯示的并不是cpu 使用百分比馋缅。這也許是最容易產(chǎn)生的誤解磅网。這個(gè)誤解有兩方面的問題:
- load average 并非指 cpu load average 而是 system load average绳匀。遠(yuǎn)古時(shí)代(1993年之前)的確是指cpu load粒竖,也就是統(tǒng)計(jì)系統(tǒng)中處于 runnable 的線程照捡。后來uninterruptible 的線程被計(jì)入統(tǒng)計(jì)叮贩,為了同時(shí)體現(xiàn) I/O 或者 lock 的 wait 情況击狮,此種情況系統(tǒng)并沒有真正的 idle。此后這個(gè)指標(biāo)的名字就由 cpu load average 改成了 system load average益老。
- 并非百分比彪蓬,而是所有非 idle 線程的總數(shù)。需要提醒的是該數(shù)字并沒有對(duì)系統(tǒng)核數(shù)做歸一化捺萌,如果系統(tǒng)中有48個(gè)核而你看到的 load average 是20档冬,那么系統(tǒng)基本是比較輕松的。也許當(dāng)數(shù)值突破50之后才會(huì)感到壓力山大,當(dāng)然 it depends酷誓。
load average 中的 average
這個(gè) average 并不是真的 average披坏,而是采用一種指數(shù)阻尼的算法。Linux 引入了一些 magic number 簡化計(jì)算盐数。直接上代碼:
// include/linux/sched/loadavg.h
#define FSHIFT 11 /* nr of bits of precision */
#define FIXED_1 (1<<FSHIFT) /* 1.0 as fixed-point */
/* 每5秒采樣一次 */
#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) */
/* n 表示 active task 的數(shù)量棒拂,也就是非 idle 線程的數(shù)量 */
#define CALC_LOAD(load,exp,n) \
load *= exp; \
load += n*(FIXED_1-exp); \
load >>= FSHIFT;
extern void calc_global_load(unsigned long ticks);
// kernel/sched/loadavg.c
/*
* 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);
if (time_before(jiffies, sample_window + 10))
return;
/*
* Fold the 'old' NO_HZ-delta to include all NO_HZ cpus.
*/
delta = calc_load_nohz_fold();
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);
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.
*/
calc_global_nohz();
}
直觀的講,如果之前系統(tǒng)一直處于 idle 狀態(tài)娘扩,在單核系統(tǒng)下增加一個(gè)100% load 的線程着茸,一分鐘之后的 load average (1min) 為 0.62 而不是線性 average 的結(jié)果 1。
Load average experiment to visualize exponential damping
參考
http://www.brendangregg.com/blog/2017-08-08/linux-load-averages.html