人生就是如此
===========================================================
linux loadavg 算法
===========================================================
今天读linux  source  code关于cpu  load 的计算方法,同时在google上搜索到处参考,晕乎了半天,终于弄明白cpu  load 的计算方法了,并不是简单的移动算术平均。

对于linux来说,采样计算load时间间隔为5秒,这都是在source code里面定义的固定数字,其采样结构通过动态内存文件系统  /proc/loadavg 可以动态的得到适时数据,其他工具的输出,比如 uptime / top/sar 等都是读该内存数据所产生的。我们在这里主要考究kernel的算法。

对于5秒的间隔,是动态地采样cpu状态数据,也就是run queue size ,这包括正在cpu中running的进程数量以及在cpu等待队列里面的进程数量。对于linux来说,实际上会计算1分钟、5分钟、15分钟的移动平均。为此首先我们要介绍linux 里面定义的3个常量:

 #define EXP_1           1884            /* 1/exp(5sec/1min)  */
 #define EXP_5           2014            /* 1/exp(5sec/5min)  */
 #define EXP_15          2037            /* 1/exp(5sec/15min) */

三个常量分别表示1/5/15分钟的常量,计算方法是:

1884 = 2048/(power(e,(5/(60*1))))   /* e = 2.71828 */

2014 = 2048/(power(e,(5/(60*5))))  

2037 = 2048/(power(e,(5/(60*15))))  

我们假定前一时刻按常量1884计算的load为 load1(t-1),当前采样run queue size 为 rq1,则当前load1(t) = ((load1(t-1) * 1884) + rq1 * (2048 - 1884))/2048

同理可以5分钟和15分钟移动平均的算法分别为 load5(t) =  ((load5(t-1) * 2014) + rq1 * (2048 - 2014))/2048和load_15(t) =  ((load15(t-1) * 2037) + rq1 * (2048 - 2037))/2048

由此可以看出,移动平均间隔越大,当前run queue size 对移动平均的影响趋向减小。

至于为什么取这个数,涉及到微积分方面的知识了,这样做出的图象更平滑。

bitirainy 发表于:2004.11.22 21:37 ::分类: ( Oracle is anything ) ::阅读:(2669次) :: 评论 (6)
[回复]


biti_rainy 评论于: 2004.11.24 12:07
建议 [回复]

建议biti改用 OLDRAIN上传的两栏模版,这样文章格式就不会乱了。呵呵
他的模版叫什么 pub v5什么的。记不清了。

CrazyCpy 评论于: 2004.11.28 21:23
biti_rainy [回复]

你好,因为在做关于cpu load的一个作业,找到你的blog上来了smile

这是我找到的唯一清楚讲解计算这个东东的地方,呵呵
不过,还是有些疑问.比如我现在自己要定义一个取样时间和总时间,例如在十分钟内10秒钟一次.那首先是不是要算常量:
@ = 2048/(power(e,(10/(600)))) /* e = 2.71828 */

然后带入公式load10(t) = ((load1(t-1) * @) + rq1 * (2048 - @))/2048

我是这么算的,可是不对啊.请指教一下

raully 评论于: 2004.12.27 15:57
[回复]

这个东西,是在 source code 里面定义的,在编译时就定义好的,个人无法控制。我们通过 工具所获得的 load 值,即使可以调整时间间隔,也不过是简单地计算了 内核的这个输出值。

biti_rainy 评论于: 2004.12.27 17:47
谢谢 [回复]

"我们通过 工具所获得的 load 值,即使可以调整时间间隔,也不过是简单地计算了 内核的这个输出值。"

我的理解是 利用拿到1/5/15这三个值来计算不同时间间隔的cpu load.
您知道这个计算如何实现吗

raully 评论于: 2004.12.28 10:08
[回复]

我一开始是考究 linux sar source code ,结果发现不过是对 /proc/load 做了简单的均值计算,才去找 kernel source code的。

void read_proc_loadavg(void)
{
FILE *loadfp;
int load_tmp[2];

/* Open loadavg file */
if ((loadfp = fopen(LOADAVG, "r")) == NULL) {
file_stats.nr_running = 0;
file_stats.nr_threads = 0;
file_stats.load_avg_1 = file_stats.load_avg_5 = 0;
}
else {
/* Read load averages and queue length */
fscanf(loadfp, "%d.%d %d.%d %*d.%*d %d/%d %*dn",
&(load_tmp[0]), &(file_stats.load_avg_1),
&(load_tmp[1]), &(file_stats.load_avg_5),
&(file_stats.nr_running),
&(file_stats.nr_threads));
fclose(loadfp);

file_stats.load_avg_1 += load_tmp[0] * 100;
file_stats.load_avg_5 += load_tmp[1] * 100;
if (file_stats.nr_running)
/* Do not take current process into account */
file_stats.nr_running--;
}
}

if (GET_QUEUE(act)) {
if (dis)
printf(_("n%-11s runq-sz plist-sz ldavg-1 ldavg-5n"), cur_time[!curr]);

printf("%-11s %9u %9u %9.2f %9.2fn", cur_time[curr],
file_stats[curr].nr_running,
file_stats[curr].nr_threads,
(double) file_stats[curr].load_avg_1 / 100,
(double) file_stats[curr].load_avg_5 / 100);

/* Will be used to compute the average */
asum.nr_running += file_stats[curr].nr_running;
asum.nr_threads += file_stats[curr].nr_threads;
asum.load_avg_1 += file_stats[curr].load_avg_1;
asum.load_avg_5 += file_stats[curr].load_avg_5;
}

if (GET_QUEUE(act)) {
if (dis)
printf(_("nAverage: runq-sz plist-sz ldavg-1 ldavg-5n"));

printf(_("Average: %9.0f %9.0f %9.2f %9.2fn"),
(double) asum.nr_running / asum.count,
(double) asum.nr_threads / asum.count,
(double) asum.load_avg_1 / (asum.count * 100),
(double) asum.load_avg_5 / (asum.count * 100));
}

biti_rainy 评论于: 2004.12.28 13:15

发表评论
标题

在此添加评论
表情符号: smile laughing tongue angry crying sad wassat wink

称呼

邮箱地址(可选)

个人主页(可选)




切换风格
新闻聚合
博客日历
文章归档...
最新发表...
博客统计...
网站链接...