本文中的代码分析基于 linux-2.6.32.67

在哪儿

load average可以在以下的命令输出中找到

  • uptime
  • w
  • top

这些输入中包含的例如 load average: 0.00, 0.00, 0.08 的字段就是 load average 了
三个数字分别代表系统最近1/5/15分钟的负载

有什么用

load average是系统负荷的一个参考, 简单来讲, 对于单核单CPU的系统, load为 1 表示系统正好能够处理当前所有的任务, 再多就得有任务要等待. 要系统提供正常流畅的服务, 通常需要保持 load 在一个合理的范围

多少是合理范围?

基准

当前系统认为有多少个 CPU 的 core, 就认为 load 达到这个值是”满载”. 例如:

grep -c  "model name" /proc/cpuinfo 
28

那么这个系统在 load 为 28 时”满载”, 如果把这个 CPU 超线程到 56 个逻辑核, 那么就是 56 满载.

合理范围

大多数系统管理员都使用 70% 这个比例来界定. 当系统的负荷持续达到满载的 70%, 就应该着手查找提高系统负载的原因.

系统怎么算的

这里尝试从内核角度来大概看一下系统的 load 是怎么计算出来的.
首先, 直观的, 这个值计算是在sched.c 中进行

void calc_global_load(void)
{
    unsigned long upd = calc_load_update + 10;
    long active;
    // 如果没有到时间, 不进行刷新
    if (time_before(jiffies, upd))
        return;
    //取数据
    active = atomic_long_read(&calc_load_tasks);
    active = active > 0 ? active * FIXED_1 : 0;

    avenrun[0] = calc_load(avenrun[0], EXP_1, active);//1分钟
    avenrun[1] = calc_load(avenrun[1], EXP_5, active);//5分钟
    avenrun[2] = calc_load(avenrun[2], EXP_15, active);//15分钟
    //设定下一次更新的时间
    calc_load_update += LOAD_FREQ;
}

sched.h 中定义了刷新间隔

#define LOAD_FREQ   (5*HZ+1)    /* 5 sec intervals */

这个里面用到的calc_load_tasks是经由下面调用栈每1ms进行计算的

calc_load_tasks ->
scheduler_tick -> 
update_cpu_load -> 
static void calc_load_account_active(struct rq *this_rq)
{
    long nr_active, delta;
    // 从这里可以看出,linux计算load是包含running和uninterruptible的任务
    nr_active = this_rq->nr_running;
    nr_active += (long) this_rq->nr_uninterruptible;

    if (nr_active != this_rq->calc_load_active) {
        delta = nr_active - this_rq->calc_load_active;
        this_rq->calc_load_active = nr_active;
        atomic_long_add(delta, &calc_load_tasks);
    }
}

这里进行负载的计算比上面提到的 5s 频繁的多, 实际上这里的计算不只为了输出 load average 的数据, 主要是为 CPU 的负载均衡提供数据, 负载均衡的东西又是一块骨头, 下次再啃.

参考
1. Understanding Linux CPU Load
2. UNIX Load Average Part 1:How It Works
3. Unix/Linux 的 Load 初级解释
4. 系统管理员工具包: 监视运行缓慢的系统
5. 理解Linux系统负荷
6. Load computing

本文地址 load average 转载请注明出处