llhuii's Blog

Happy coding

Load

Let's dive into load average.

Sample output of `uptime':
 18:38:47 up 28 days,  9:15,  9 users,  load average: 2.63, 2.67, 2.50
当前时间, 系统运行时间, 目前登录用户数, 过去1/5/15 min的平均负载

什么是load average?  
来自于uptime(1)
System load averages is the average number of processes that are either
        in a runnable or uninterruptable state.  A process in a runnable  state
        is  either using the CPU or waiting to use the CPU.  A process in unin‐
        terruptable state is waiting for some I/O access, eg waiting for  disk.
        The  averages  are  taken over the three time intervals.  Load averages
        are not normalized for the number of CPUs in a system, so a load  aver‐
        age  of 1 means a single CPU system is loaded all the time while on a 4
        CPU system it means it was idle 75% of the time.

Kernel magic:
source code in kernel/sched.c, include/linux/sched.h

/* calc_global_load function */
3252   avenrun[0] = calc_load(avenrun[0], EXP_1, active); /* 1min */
3253   avenrun[1] = calc_load(avenrun[1], EXP_5, active); /* 5min */
3254   avenrun[2] = calc_load(avenrun[2], EXP_15, active);/* 15min */

3256   calc_load_update += LOAD_FREQ;

而calc_load 的定义:

3046 static unsigned long
3047 calc_load(unsigned long load, unsigned long exp, unsigned long active)
3048 {
3049   load *= exp;;
3050   load += active * (FIXED_1 - exp);
3051   load += 1UL << (FSHIFT - 1);
3052   return load >> FSHIFT;
3053 }

故计算公式:
load(t1) = (load(t0)*exp + active*(FIXED_1-exp)) >> FSHIFT

exp 有EXP_1, EXP_5, EXP_15, 对应1min, 5min, 15min.
但EXP_*, FSHIFT, FIXED_1 又是什么?

/*
* 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.
*/
125 #define FSHIFT    11    /* nr of bits of precision */
126 #define FIXED_1   (1<<FSHIFT) /* 1.0 as fixed-point */
127 #define LOAD_FREQ (5*HZ+1)  /* 5 sec intervals */
128 #define EXP_1   1884    /* 1/exp(5sec/1min) as fixed-point */
129 #define EXP_5   2014    /* 1/exp(5sec/5min) */
130 #define EXP_15    2037    /* 1/exp(5sec/15min) */

由此可知真正的计算公式:
load(t1) = load(t0) * exp_m + active * (1 - exp_m)
其中exp_m 对应于EXP_M, 是小于1的常量, 称之为负载因子, 作为前次负载的比重。

EPX_* 是如何计算的?

代码实现的exp_m = exp(-load_freq/m), load_freq 为更新频率
由于每隔5s进行负载计算的更新, 过去 m min的负载因子
exp_m = exp(-5s/60ms), 所以
EXP_M = exp_m << FSHIFT
                        = 2**11 * exp(-5/60m)
                        = 2**(11 - 5*log2(e)/60m)

EXP_1 = 2**(11 - 5*log2(e)/60) = 1884
同理EXP_5 = 2014, EXP_15 = 2037

reference:
http://en.wikipedia.org/wiki/Load_(computing)
http://www.teamquest.com/pdfs/whitepaper/ldavg1.pdf