linux负载率Load Average分析及负载率监测驱动的实现

0、引入

CPU负载率一定程度上反映了系统CPU的繁忙程度,且在多核cpu下与负载均衡,进程调度关系密切。实现对CPU负载率的监测有利于实现一套稳定可靠适用的系统。

1、负载率相关定义

1.1 平均负载的定义

1.1.1 Load average理解:

  • 在特定时间间隔运行队列中的平均进程数,内核一般取5、10、15分钟。

  • 单位时间内,系统处于可运行状态和不可中断状态的平均进程数,即平均活跃进程数

1.1.2 可运行状态和不可中断状态的进程

  • 可运行状态的进程:正在使用cpu或者正在等待cpu的进程,ps命令看到的,处于R状态(Running或Runnable)的进程

  • 不可中断状态的进程:正处于内核态关键流程中的进程,并且这些流程是不可打断的,比如最常见的是等待硬件设备的I/O响应,也就是我们在ps命令中看到的D状态(UninterruptibleSleep,也称为Disk Sleep)的进程。不可中断状态实际上是系统对进程和硬件设备的一种保护机制。

1.1.3 运行队列

它没有在等待I/O操作的结果、它没有主动进入等待状态(也就是没有调用'wait')、没有被停止(例如:等待终止)则处于运行队列之中,即以上描述的可运行态和不可中断态的进程。

1.2 Linux下如何查看平均负载

1.2.1 uptime命令

fengyuwuzu@fengyuwuzu:~$ uptime
 13:04:33 up 2 min,  2 users,  load average: 1.96, 1.09, 0.44

当前时间、系统运行时间、当前用户数、1分钟平均负载、5分钟平均负载、15分钟平均负载 

1.2.2 cat /proc/loadavg

fengyuwuzu@fengyuwuzu:~$ cat /proc/loadavg
0.07 0.02 0.00 1/424 7819

前三个数同上loadavg的值。第4个参数:分子是当前正在运行的进程数,分母是总的进程数。第5个参数:最近运行进程的ID。

1.2.3 w命令和top命令

fengyuwuzu@fengyuwuzu:~$ w
 11:22:14 up 22:20,  2 users,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
fengyuwu tty7     :0               六13   22:20m 47.66s  0.20s /sbin/upstart --user
fengyuwu pts/19   192.168.0.1      六13    0.00s  0.12s  0.01s w
fengyuwuzu@fengyuwuzu:~$ top
top - 11:25:36 up 22:24,  2 users,  load average: 0.00, 0.00, 0.00
Tasks: 238 total,   1 running, 169 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.2 us,  0.2 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  1951332 total,   221652 free,   681956 used,  1047724 buff/cache
KiB Swap:  2094076 total,  2091504 free,     2572 used.  1022792 avail Mem

2、Linux内核负载率分析(内核版本 4.1.15)

2.1 内核相关负载率计算

2.1.1 kernel/fs/proc/loadavg.c

实现对外的提供读取loadavg接口。

#include <linux/fs.h>
#include <linux/init.h>
#include <linux/pid_namespace.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/seqlock.h>
#include <linux/time.h>

#define LOAD_INT(x) ((x) >> FSHIFT)
#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)

static int loadavg_proc_show(struct seq_file *m, void *v)
{
        unsigned long avnrun[3];

        get_avenrun(avnrun, FIXED_1/200, 0);

        seq_printf(m, "%lu.%02lu %lu.%02lu %lu.%02lu %ld/%d %d\n",
                LOAD_INT(avnrun[0]), LOAD_FRAC(avnrun[0]),
                LOAD_INT(avnrun[1]), LOAD_FRAC(avnrun[1]),
                LOAD_INT(avnrun[2]), LOAD_FRAC(avnrun[2]),
                nr_running(), nr_threads,
                task_active_pid_ns(current)->last_pid);
        return 0;
}

static int loadavg_proc_open(struct inode *inode, struct file *file)
{
        return single_open(file, loadavg_proc_show, NULL);
}

static const struct file_operations loadavg_proc_fops = {
        .open           = loadavg_proc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
        .release        = single_release,
};

static int __init proc_loadavg_init(void)
{
        proc_create("loadavg", 0, NULL, &loadavg_proc_fops);
        return 0;
}
fs_initcall(proc_loadavg_init);

loadavg_proc_show调用get_avenrun获取最新的负载率数组。

2.1.2  kernel/sched/proc.c

查看源码:https://elixir.bootlin.com/linux/v4.1.15/source/kernel/sched/proc.c#L98

/* Variables and functions for calc_load */
atomic_long_t calc_load_tasks;
unsigned long calc_load_update;
unsigned long avenrun[3];
EXPORT_SYMBOL(avenrun); /* should be removed */

/**
 * get_avenrun - get the load average array
 * @loads:      pointer to dest load array
 * @offset:     offset to add
 * @shift:      shift count to shift the result left
 *
 * These values are estimates at best, so no need for locking.
 */
void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
{
        loads[0] = (avenrun[0] + offset) << shift;
        loads[1] = (avenrun[1] + offset) << shift;
        loads[2] = (avenrun[2] + offset) << shift;
}

 * calc_load - update the avenrun load estimates 10 ticks after the
 * CPUs have updated calc_load_tasks.
 */
void calc_global_load(unsigned long ticks)
{
        long active, delta;

        if (time_before(jiffies, calc_load_update + 10))
                return;

        /*
         * Fold the 'old' idle-delta to include all NO_HZ cpus.
         */
        delta = calc_load_fold_idle();
        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);

        calc_load_update += LOAD_FREQ;

        /*
         * In case we idled for multiple LOAD_FREQ intervals, catch up in bulk.
         */
        calc_global_nohz();
}
/*
 * a1 = a0 * e + a * (1 - e)
 */
static unsigned long
calc_load(unsigned long load, unsigned long exp, unsigned long active)
{
        load *= exp;
        load += active * (FIXED_1 - exp);
        load += 1UL << (FSHIFT - 1);
        return load >> FSHIFT;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值