atop分析小记

  1. atop这个工具相当NB
  2. 项目中需要用到它的磁盘使用率统计值,为了一探究竟,挖了下它的代码

atopsar

atopsar实际就是atop的一个链接指向。

从atop.c的main源码可以看到

int
main(int argc, char *argv[])
{
char *p;
if ((p = strrchr(argv[0], '/')))
p++;
else
p = argv[0]; if (memcmp(p, "atopsar", 7) == 0)
return atopsar(argc, argv);
}

源码编译

实际读起代码来,还比较繁琐,为了快速找到我关注的东西,考虑干脆自己编译一份可执行文件,然后通过gdb单步跟踪,一步到位。

可惜实际结果并不是很理想,还是坑了好一会儿……

源码编译步骤

虽然README介绍的相当干练:

For interactive use, it is sufficient to install ATOP with the command
(as root): make systemdinstall or make sysvinstall

可惜我make直接报错(大意如此):

no rule to make version.h needed by version.c ...

发现需要通过mkversion脚本生成 version.h,

实际,项目需要的 version.c 也木有。

附上我的

// version.h
#define ATOPVERS "ATOP3"
#define ATOPDATE "2017/07/18 22:24:58"
//version.c
char *getstrvers(void) {
return "Version 3.2.0";
}
unsigned short getnumvers(void) {
return (0x1313);
}

第二件坑爹的事情

虽然README提到这句,可是,它完全没提是必须的啊。

我想偷个懒,直接注释相关引用,却发现进了另一个坑。

最后老实下载了这个包,注意官网提供的netatop对内核有要求,

我为了匹配内核版本号,下载了netatop-0.3.tar.gz

The kernel module 'netatop' can be downloaded and installed separately from www.atoptool.nl/downloadnetatop.php

第三件事

netatop-0.3.tar.gz 下载好了,解压缩后,一定要重命名到Netatop.

主要原因是: atop源码里面的两个依赖文件是做了链接的。。。

lrwxrwxrwx 1 ubuntu ubuntu     21 Mar 24 15:54 netatopd.h -> ../Netatop/netatopd.h
lrwxrwxrwx 1 ubuntu ubuntu 20 Mar 24 15:54 netatop.h -> ../Netatop/netatop.h

编译

修改 Makefile

CFLAGS  += -O2 -I.
# 改成
CFLAGS += -O0 -g -I.

编译 make

源码小小分析

一路从 main函数追踪的话,大概是这么一条路

main() -> atopsar() -> engine()
-> reportheader()
-> photosyst()

主要的逻辑在 photosyst 这个函数里。

里面罗列了读取系统的各种信息。

CPU,内存,磁盘,网络、、、

我关注的地方

    // 这里是实际读取磁盘信息的部分
// 实际是读取了 /proc/diskstats文件
/*
** check if disk-statistics are provided (kernel 2.6 onwards)
*/
if ( (fp = fopen("diskstats", "r")) != NULL)
{
char diskname[256];
struct perdsk tmpdsk; si->dsk.ndsk = 0;
si->dsk.nmdd = 0;
si->dsk.nlvm = 0; while ( fgets(linebuf, sizeof(linebuf), fp) )
{
nr = sscanf(linebuf,
"%d %d %255s %lld %*d %lld %*d "
"%lld %*d %lld %*d %*d %lld %lld",
&major, &minor, diskname,
&tmpdsk.nread, &tmpdsk.nrsect,
&tmpdsk.nwrite, &tmpdsk.nwsect,
&tmpdsk.io_ms, &tmpdsk.avque ); /*
** check if this line concerns the entire disk
** or just one of the partitions of a disk (to be
** skipped)
*/
if (nr == 9) /* full stats-line ? */
{
switch ( isdisk(major, minor, diskname,
&tmpdsk, MAXDKNAM) )
{
case NONTYPE:
continue; case DSKTYPE:
if (si->dsk.ndsk < MAXDSK-1)
si->dsk.dsk[si->dsk.ndsk++] = tmpdsk;
break; case MDDTYPE:
if (si->dsk.nmdd < MAXMDD-1)
si->dsk.mdd[si->dsk.nmdd++] = tmpdsk;
break; case LVMTYPE:
if (si->dsk.nlvm < MAXLVM-1)
si->dsk.lvm[si->dsk.nlvm++] = tmpdsk;
break;
}
}
} /*
** set terminator for table
*/
si->dsk.dsk[si->dsk.ndsk].name[0] = '\0';
si->dsk.mdd[si->dsk.nmdd].name[0] = '\0';
si->dsk.lvm[si->dsk.nlvm].name[0] = '\0'; fclose(fp);
} static struct {
char *regexp;
regex_t compreg;
void (*modname)(unsigned int, unsigned int,
char *, struct perdsk *, int);
int retval;
} validdisk[] = {
{ "^ram[0-9][0-9]*$", {0}, (void *)0, NONTYPE, },
{ "^loop[0-9][0-9]*$", {0}, (void *)0, NONTYPE, },
{ "^sd[a-z][a-z]*$", {0}, nullmodname, DSKTYPE, },
{ "^dm-[0-9][0-9]*$", {0}, lvmmapname, LVMTYPE, },
{ "^md[0-9][0-9]*$", {0}, nullmodname, MDDTYPE, },
{ "^vd[a-z][a-z]*$", {0}, nullmodname, DSKTYPE, },
{ "^hd[a-z]$", {0}, nullmodname, DSKTYPE, },
{ "^rd/c[0-9][0-9]*d[0-9][0-9]*$", {0}, nullmodname, DSKTYPE, },
{ "^cciss/c[0-9][0-9]*d[0-9][0-9]*$", {0}, nullmodname, DSKTYPE, },
{ "^fio[a-z][a-z]*$", {0}, nullmodname, DSKTYPE, },
{ "/host.*/bus.*/target.*/lun.*/disc", {0}, abbrevname1, DSKTYPE, },
{ "^xvd[a-z][a-z]*[0-9]*$", {0}, nullmodname, DSKTYPE, },
{ "^dasd[a-z][a-z]*$", {0}, nullmodname, DSKTYPE, },
{ "^mmcblk[0-9][0-9]*$", {0}, nullmodname, DSKTYPE, },
{ "^emcpower[a-z][a-z]*$", {0}, nullmodname, DSKTYPE, },
}; // isdisk 通过预设的正则表达式过滤规则
// 判断 /proc/diskstats 里的信息到底是不是磁盘
// 正则在上文列出
static int
isdisk(unsigned int major, unsigned int minor,
char *curname, struct perdsk *px, int maxlen)
{
static int firstcall = 1;
register int i; if (firstcall) /* compile the regular expressions */
{
for (i=0; i < sizeof validdisk/sizeof validdisk[0]; i++)
regcomp(&validdisk[i].compreg, validdisk[i].regexp,
REG_NOSUB);
firstcall = 0;
} /*
** try to recognize one of the compiled regular expressions
*/
for (i=0; i < sizeof validdisk/sizeof validdisk[0]; i++)
{
if (regexec(&validdisk[i].compreg, curname, 0, NULL, 0) == 0)
{
/*
** name-string recognized; modify name-string
*/
if (validdisk[i].retval != NONTYPE)
(*validdisk[i].modname)(major, minor,
curname, px, maxlen); return validdisk[i].retval;
}
} return NONTYPE;
}

atop 分析小记的更多相关文章

  1. Hadoop、Pig、Hive、Storm、NOSQL 学习资源收集

    (一)hadoop 相关安装部署 1.hadoop在windows cygwin下的部署: http://lib.open-open.com/view/1333428291655 http://blo ...

  2. 小记--------spark的worker原理分析及源码分析

     

  3. 小记--------spark资源调度机制源码分析-----Schedule

    Master类位置所在:spark-core_2.11-2.1.0.jar的org.apache.spark.deploy.master下的Master类 /** * driver调度机制原理代码分析 ...

  4. 小记--------spark的Master的Application注册机制源码分析及Master的注册机制原理分析

    原理图解: Master类位置所在:spark-core_2.11-2.1.0.jar的org.apache.spark.deploy.master下的Master类   //截取了部分代码 //处理 ...

  5. 小记--------spark的Master主备切换机制原理分析及源码分析

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABfEAAAJwCAYAAAAp7ysfAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjw

  6. 小记--------spark的宽依赖与窄依赖分析

    窄依赖: Narrow Dependency : 一个RDD对它的父RDD,只有简单的一对一的依赖关系.RDD的每个partition仅仅依赖于父RDD中的一个partition,父RDD和子RDD的 ...

  7. 小记--------spark内核架构原理分析

      首先会将jar包上传到机器(服务器上)     1.在这台机器上会产生一个Application(也就是自己的spark程序)     2.然后通过spark-submit(shell) 提交程序 ...

  8. 使用GDB 追踪依赖poco的so程序,core dump文件分析.

    前言 在windows 下 系统核心态程序蓝屏,会产生dump文件. 用户级程序在设置后,程序崩溃也会产生dump文件.以方便开发者用windbg进行分析. so,linux 系统也有一套这样的东东- ...

  9. 广州PostgreSQL用户会技术交流会小记 2015-9-19

    广州PostgreSQL用户会技术交流会小记 2015-9-19 今天去了广州PostgreSQL用户会组织的技术交流会 分别有两个session 第一个讲师介绍了他公司使用PostgreSQL-X2 ...

随机推荐

  1. IIS+NGINX 负载web服务器

    Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行.其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在 ...

  2. layer中每次用到都要查来查去的功能

    1.关闭当前弹出层 var index = parent.layer.getFrameIndex(window.name); setTimeout(function(){parent.layer.cl ...

  3. 【转载】GET和POST两种基本请求方法的区别

    原文地址:http://www.cnblogs.com/logsharing/p/8448446.html GET和POST是HTTP请求的两种基本方法,要说它们的区别,接触过WEB开发的人都能说出一 ...

  4. JAVA概率实现--一篇最常见、最通用解决方案

    日常场景:某活动抽奖,控制各等奖的出现概率 比如控制A(中奖率):20%:B(获得优惠券率):30%:C(谢谢参与率):50% 下面以封装好在main()函数里,上代码(记得导入相应的包): publ ...

  5. java面向对象编程(二)-构造方法(函数)

    1.类的构造方法介绍 什么是构造方法呢?在回答这个问题之前,我们来看一个需求:我们在创建人类的对象时,是先把一个对象创建好后,再给他的年龄和姓名属性赋值,如果现在我要求,在创建人类的对象时,就直接指定 ...

  6. TestLink测试管理工具的使用举例—第一篇

    本博客用来详细说明TestLink测试管理工具的使用方法,前两篇博客已经详细说明了TestLink工具的下载,安装及基本登录功能,本篇开始说明其工具的具体使用! 下载安装TestLink工具之后,我们 ...

  7. Cordova编译报AAPT错误的解决方法

    因为项目中同时使用cordova-hot-code-push-plugin和phonegap-plugin-barcodescanner,编译时报错:AAPT: error: resource and ...

  8. mysql oracle 数据库备份

    mysql 备份与还原 转载:https://blog.csdn.net/win_turn/article/details/60880990 备份数据库 数据库名叫dddd  mysqldump -u ...

  9. node day1 login

    https://blog.csdn.net/weixin_33901641/article/details/85967847 vue之node.js的简单介绍 http://nodejs.cn/ ht ...

  10. 关于JVM的一些冷知识

    (1) Java加载类的一般顺序: 1.静态属性,静态方法声明,静态块. 2.动态属性,普通方法声明,构造块. 3.构造方法. 当加载一个类时,JVM会根据属性的数据类型第一时间赋默认值(一举生成的) ...