一次和圈子里的朋友群聊的时候,谈到了vmstat的实现机制。我当时正在轻轨上,幻想着从轻轨飞下去的快感。在轻轨上我发表了自己的一些看法,不过都是意淫。
现在,已经过去半周了,今天终于闲下来把vmstat的源代码翻出来。vmstat其实只是一个简单的统计显示工具,早期NetBSD版本的vmstat实现总共才不到1500行。所以,也不用期望本文会有多么高深。
完整的源文件(加注释)在附件中。(到现在为止,CSDN的blog似乎还没有上传附件的功能)
函数调用栈如下:
核心的代码段如下:
fill_vmmeter(&sum); //vm信息获取
fill_vmtotal(&total); //vm信息汇总
(void)printf("%2d %1d %1d",
total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw);//显示t_rq,t_dw,t_sw三个值
#define vmstat_pgtok(a) ((a) * (sum.v_page_size >> 10))
#define rate(x) (((x) + halfuptime) / uptime) /* round */
if (hflag) { //如果设置了hflag
printf(" ");
prthuman(total.t_avm * (u_int64_t)sum.v_page_size, 7); //使用humanize_number格式显示v_page_size
printf(" ");
prthuman(total.t_free * (u_int64_t)sum.v_page_size, 6);
printf(" ");
} else {
printf(" %7d ", vmstat_pgtok(total.t_avm)); //使用一般格式显示t_avm
printf(" %6d ", vmstat_pgtok(total.t_free));
}
(void)printf("%5lu ",
(unsigned long)rate(sum.v_vm_faults - osum.v_vm_faults));//显示vm错误比率
(void)printf("%3lu ",
(unsigned long)rate(sum.v_reactivated - osum.v_reactivated));//显示v_reactivated比值
(void)printf("%3lu ",
(unsigned long)rate(sum.v_swapin + sum.v_vnodein -
(osum.v_swapin + osum.v_vnodein)));//显示v_swapin比值
(void)printf("%3lu ",
(unsigned long)rate(sum.v_swapout + sum.v_vnodeout -
(osum.v_swapout + osum.v_vnodeout)));//显示v_vnodeout比值
(void)printf("%5lu ",
(unsigned long)rate(sum.v_tfree - osum.v_tfree));//显示v_tfree比值
(void)printf("%3lu ",
(unsigned long)rate(sum.v_pdpages - osum.v_pdpages));//显示v_pdpages比值
devstats();
(void)printf("%4lu %4lu %4lu",
(unsigned long)rate(sum.v_intr - osum.v_intr),//显示v_intr比值
(unsigned long)rate(sum.v_syscall - osum.v_syscall),//显示v_syscall比值
(unsigned long)rate(sum.v_swtch - osum.v_swtch)); //显示v_swtch比值
if (Pflag)
pcpustats(ncpus, cpumask, maxid);
else
cpustats(); //这里会显示CPU的user时间、sys时间、Idle时间——百分比格式
(void)printf("\n");
(void)fflush(stdout);
if (reps >= 0 && --reps <= 0)
break;
osum = sum;
uptime = interval;
/*
* We round upward to avoid losing low-frequency events
* (i.e., >= 1 per interval but < 1 per second).
*/
if (interval != 1)
halfuptime = (uptime + 1) / 2;
else
halfuptime = 0;
(void)sleep(interval);//睡眠inteval长的时间