Linux主机load average的概念计算过程注意事项

最近开发的一个模块需要根据机房各节点的负载情况(如网卡IO、load average等指标)做任务调度,刚开始对Linux机器load average这项指标不是很清楚,经过调研,终于搞清楚了其计算方法和影响因素,作为笔记,记录于此。

1. load average

当在shell终端键入top命令时,默认情况下,在输出内容的第一行会有load average这项指标值,如下所示:

top - 19:10:32 up 626 days,  4:58,  1 user,  load average: 7.74, 5.62, 6.51
Tasks: 181 total,  8 running, 173 sleeping,  0 stopped,  0 zombie
Cpu(s):  4.0% us,  0.5% sy,  0.0% ni, 95.4% id,  0.0% wa,  0.0% hi,  0.0% si

同样,输入uptime命令,load average也会被输出:

19:15:10 up 129 days,  5:12, 15 users,  load average: 0.01, 0.09, 0.05 

根据man uptime的说明可知,load average包含的3个值分别表示past 1, 5 and 15 minutes内的系统平均负载。

那么,这3个值是怎么计算出来的?下面从Linux源码中寻找答案。

2. linux机器load average的计算过程

wikipedia在对load的解释(参见这里)中,提到了linux系统对load的计算方法,为亲自验证,我check了linux源码(linux kernel 2.6.9)中的相关代码,自顶向下的验证过程如下。

在源码树kernel/timer.c文件中,计算系统load的函数代码如下:

// 源码树路径:kernel/timer.c
/*
 * Hmm.. Changed this, as the GNU make sources (load.c) seems to
 * imply that avenrun[] is the standard name for this kind of thing.
 * Nothing else seems to be standardized: the fractional size etc
 * all seem to differ on different machines.
 *
 * Requires xtime_lock to access.
 */
unsigned long avenrun[3];

/*
 * 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 < 0) {
  count += LOAD_FREQ;
  active_tasks = count_active_tasks();
  CALC_LOAD(avenrun[0], EXP_1, active_tasks);
  CALC_LOAD(avenrun[1], EXP_5, active_tasks);
  CALC_LOAD(avenrun[2], EXP_15, active_tasks);
 }
}

从上面的代码可知,定义的数组avenrun[]包含3个元素,分别用于存放past 1, 5 and 15 minutes的load average值。calc_load则是具体的计算函数,其参数ticks表示采样间隔。函数体中,获取当前的活跃进程数(active tasks),然后以其为参数,调用CALC_LOAD分别计算3种load average。

沿着函数调用链,可以看到count_active_tasks()定义如下(也在kernel/timer.c文件中):

/* 
 * Nr of active tasks - counted in fixed-point numbers
 */
static unsigned long count_active_tasks(void)
{
 return (nr_running() + nr_uninterruptible()) * FIXED_1;
}

由源码可见,count_active_tasks()返回当前的活跃进程数,其中活跃进程包括:1)当前正在运行的进程(nr_running);2)不可中断的sleeping进程(如正在执行IO操作的被挂起进程)。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/f49109bb91268166548df00f920822b4.html