分享

Linux IO工具 iotop的替代品iopp

 点点阅 2020-02-26

iotop无疑在linux IO检测上是个不错的工具,但苦于要求内核版本和Python版本,不少朋友放弃了,我也是。偶然间找到了iopp,用c写的,这个跟iotop是一个作用,nice!给大家分享下

安装方法很简单,首先复制下面源代码保存为iopp.c文件

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <dirent.h>
  4. #include <ctype.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h>
  7. #include <unistd.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <getopt.h>
  11. #define PROC "/proc"
  12. #define GET_VALUE(v) \
  13. p = strchr(p, ':'); \
  14. ++p; \
  15. ++p; \
  16. q = strchr(p, '\n'); \
  17. length = q - p; \
  18. if (length >= BUFFERLEN) \
  19. { \
  20. printf("ERROR - value is larger than the buffer: %d\n", __LINE__); \
  21. exit(1); \
  22. } \
  23. strncpy(value, p, length); \
  24. value[length] = '\0'; \
  25. v = atoll(value);
  26. #define BTOKB(b) b >> 10
  27. #define BTOMB(b) b >> 20
  28. #define BUFFERLEN 255
  29. #define COMMANDLEN 1024
  30. #define VALUELEN 63
  31. #define NUM_STRINGS 8
  32. struct io_node
  33. {
  34. int pid;
  35. long long rchar;
  36. long long wchar;
  37. long long syscr;
  38. long long syscw;
  39. long long read_bytes;
  40. long long write_bytes;
  41. long long cancelled_write_bytes;
  42. char command[COMMANDLEN + 1];
  43. struct io_node *next;
  44. };
  45. struct io_node *head = NULL;
  46. int command_flag = 0;
  47. int idle_flag = 0;
  48. int mb_flag = 0;
  49. int kb_flag = 0;
  50. int hr_flag = 0;
  51. /* Prototypes */
  52. char *format_b(long long);
  53. struct io_node *get_ion(int);
  54. struct io_node *new_ion(char *);
  55. void upsert_data(struct io_node *);
  56. char *
  57. format_b(long long amt)
  58. {
  59. static char retarray[NUM_STRINGS][16];
  60. static int index = 0;
  61. register char *ret;
  62. register char tag = 'B';
  63. ret = retarray[index];
  64. index = (index + 1) % NUM_STRINGS;
  65. if (amt >= 10000) {
  66. amt = (amt + 512) / 1024;
  67. tag = 'K';
  68. if (amt >= 10000) {
  69. amt = (amt + 512) / 1024;
  70. tag = 'B';
  71. if (amt >= 10000) {
  72. amt = (amt + 512) / 1024;
  73. tag = 'G';
  74. }
  75. }
  76. }
  77. snprintf(ret, sizeof(retarray[index]) - 1, "%lld%c", amt, tag);
  78. return (ret);
  79. }
  80. int
  81. get_cmdline(struct io_node *ion)
  82. {
  83. int fd;
  84. int length;
  85. char filename[BUFFERLEN + 1];
  86. char buffer[COMMANDLEN + 1];
  87. char *p;
  88. char *q;
  89. length = snprintf(filename, BUFFERLEN, "%s/%d/cmdline", PROC, ion->pid);
  90. if (length == BUFFERLEN)
  91. printf("WARNING - filename length may be too big for buffer: %d\n",
  92. __LINE__);
  93. fd = open(filename, O_RDONLY);
  94. if (fd == -1)
  95. return 1;
  96. length = read(fd, buffer, sizeof(buffer) - 1);
  97. close(fd);
  98. buffer[length] = '\0';
  99. if (length == 0)
  100. return 2;
  101. if (command_flag == 0)
  102. {
  103. /*
  104. * The command is near the beginning; we don't need to be able to
  105. * the entire stat file.
  106. */
  107. p = strchr(buffer, '(');
  108. ++p;
  109. q = strchr(p, ')');
  110. length = q - p;
  111. }
  112. else
  113. p = buffer;
  114. length = length < COMMANDLEN ? length : COMMANDLEN;
  115. strncpy(ion->command, p, length);
  116. ion->command[length] = '\0';
  117. return 0;
  118. }
  119. struct io_node *
  120. get_ion(int pid)
  121. {
  122. struct io_node *c = head;
  123. while (c != NULL)
  124. {
  125. if (c->pid == pid)
  126. break;
  127. c = c->next;
  128. }
  129. return c;
  130. }
  131. int
  132. get_tcomm(struct io_node *ion)
  133. {
  134. int fd;
  135. int length;
  136. char filename[BUFFERLEN + 1];
  137. char buffer[BUFFERLEN + 1];
  138. char *p;
  139. char *q;
  140. length = snprintf(filename, BUFFERLEN, "%s/%d/stat", PROC, ion->pid);
  141. if (length == BUFFERLEN)
  142. printf("WARNING - filename length may be too big for buffer: %d\n",
  143. __LINE__);
  144. fd = open(filename, O_RDONLY);
  145. if (fd == -1)
  146. return 1;
  147. length = read(fd, buffer, sizeof(buffer) - 1);
  148. close(fd);
  149. /*
  150. * The command is near the beginning; we don't need to be able to
  151. * the entire stat file.
  152. */
  153. p = strchr(buffer, '(');
  154. ++p;
  155. q = strchr(p, ')');
  156. length = q - p;
  157. length = length < BUFFERLEN ? length : BUFFERLEN;
  158. strncpy(ion->command, p, length);
  159. ion->command[length] = '\0';
  160. return 0;
  161. }
  162. struct io_node *
  163. insert_ion(struct io_node *ion)
  164. {
  165. struct io_node *c;
  166. struct io_node *p;
  167. /* Check the head of the list as a special case. */
  168. if (ion->pid < head->pid)
  169. {
  170. ion->next = head;
  171. head = ion;
  172. return head;
  173. }
  174. c = head->next;
  175. p = head;
  176. while (c != NULL)
  177. {
  178. if (ion->pid < c->pid)
  179. {
  180. ion->next = c;
  181. p->next = ion;
  182. return head;
  183. }
  184. p = c;
  185. c = c->next;
  186. }
  187. /* Append to the end of the list. */
  188. if (c == NULL)
  189. p->next = ion;
  190. return head;
  191. }
  192. void
  193. get_stats()
  194. {
  195. DIR *dir = opendir(PROC);
  196. struct dirent *ent;
  197. char filename[BUFFERLEN + 1];
  198. char buffer[BUFFERLEN + 1];
  199. char value[BUFFERLEN + 1];
  200. /* Display column headers. */
  201. if (hr_flag == 1)
  202. printf("%5s %5s %5s %8s %8s %5s %6s %7s %s\n", "pid", "rchar", "wchar",
  203. "syscr", "syscw", "reads", "writes", "cwrites", "command");
  204. else if (kb_flag == 1)
  205. printf("%5s %8s %8s %8s %8s %8s %8s %8s %s\n", "pid", "rchar", "wchar",
  206. "syscr", "syscw", "rkb", "wkb", "cwkb", "command");
  207. else if (mb_flag == 1)
  208. printf("%5s %8s %8s %8s %8s %8s %8s %8s %s\n", "pid", "rchar", "wchar",
  209. "syscr", "syscw", "rmb", "wmb", "cwmb", "command");
  210. else
  211. printf("%5s %8s %8s %8s %8s %8s %8s %8s %s\n", "pid", "rchar", "wchar",
  212. "syscr", "syscw", "rbytes", "wbytes", "cwbytes", "command");
  213. /* Loop through the process table and display a line per pid. */
  214. while ((ent = readdir(dir)) != NULL)
  215. {
  216. int rc;
  217. int fd;
  218. int length;
  219. char *p;
  220. char *q;
  221. struct io_node *ion;
  222. struct io_node *old_ion;
  223. long long rchar;
  224. long long wchar;
  225. long long syscr;
  226. long long syscw;
  227. long long read_bytes;
  228. long long write_bytes;
  229. long long cancelled_write_bytes;
  230. if (!isdigit(ent->d_name[0]))
  231. continue;
  232. ion = new_ion(ent->d_name);
  233. if (command_flag == 1)
  234. rc = get_cmdline(ion);
  235. if (command_flag == 0 || rc != 0)
  236. /* If the full command line is not asked for or is empty... */
  237. rc = get_tcomm(ion);
  238. if (rc != 0)
  239. {
  240. free(ion);
  241. continue;
  242. }
  243. /* Read 'io' file. */
  244. length = snprintf(filename, BUFFERLEN, "%s/%s/io", PROC, ent->d_name);
  245. if (length == BUFFERLEN)
  246. printf("WARNING - filename length may be too big for buffer: %d\n",
  247. __LINE__);
  248. fd = open(filename, O_RDONLY);
  249. if (fd == -1)
  250. {
  251. free(ion);
  252. continue;
  253. }
  254. length = read(fd, buffer, sizeof(buffer) - 1);
  255. close(fd);
  256. buffer[length] = '\0';
  257. /* Parsing the io file data. */
  258. p = buffer;
  259. GET_VALUE(ion->rchar);
  260. GET_VALUE(ion->wchar);
  261. GET_VALUE(ion->syscr);
  262. GET_VALUE(ion->syscw);
  263. GET_VALUE(ion->read_bytes);
  264. GET_VALUE(ion->write_bytes);
  265. GET_VALUE(ion->cancelled_write_bytes);
  266. old_ion = get_ion(ion->pid);
  267. /* Display the pid's io data. */
  268. if (old_ion != NULL)
  269. {
  270. rchar = ion->rchar - old_ion->rchar;
  271. wchar = ion->wchar - old_ion->wchar;
  272. syscr = ion->syscr - old_ion->syscr;
  273. syscw = ion->syscw - old_ion->syscw;
  274. read_bytes = ion->read_bytes - old_ion->read_bytes;
  275. write_bytes = ion->write_bytes - old_ion->write_bytes;
  276. cancelled_write_bytes = ion->cancelled_write_bytes -
  277. old_ion->cancelled_write_bytes;
  278. if (kb_flag == 1 && hr_flag == 0)
  279. {
  280. rchar = BTOKB(rchar);
  281. wchar = BTOKB(wchar);
  282. syscr = BTOKB(syscr);
  283. syscw = BTOKB(syscw);
  284. read_bytes = BTOKB(read_bytes);
  285. write_bytes = BTOKB(write_bytes);
  286. cancelled_write_bytes = BTOKB(cancelled_write_bytes);
  287. }
  288. else if (mb_flag == 1 && hr_flag == 0)
  289. {
  290. rchar = BTOMB(rchar);
  291. wchar = BTOMB(wchar);
  292. syscr = BTOMB(syscr);
  293. syscw = BTOMB(syscw);
  294. read_bytes = BTOMB(read_bytes);
  295. write_bytes = BTOMB(write_bytes);
  296. cancelled_write_bytes = BTOMB(cancelled_write_bytes);
  297. }
  298. if (!(idle_flag == 1 && rchar == 0 && wchar == 0 && syscr == 0 &&
  299. syscw == 0 && read_bytes == 0 && write_bytes == 0 &&
  300. cancelled_write_bytes == 0)) {
  301. if (hr_flag == 0)
  302. printf("%5d %8lld %8lld %8lld %8lld %8lld %8lld %8lld %s\n",
  303. ion->pid,
  304. rchar,
  305. wchar,
  306. syscr,
  307. syscw,
  308. read_bytes,
  309. write_bytes,
  310. cancelled_write_bytes,
  311. ion->command);
  312. else
  313. printf("%5d %5s %5s %8lld %8lld %5s %6s %7s %s\n",
  314. ion->pid,
  315. format_b(rchar),
  316. format_b(wchar),
  317. syscr,
  318. syscw,
  319. format_b(read_bytes),
  320. format_b(write_bytes),
  321. format_b(cancelled_write_bytes),
  322. ion->command);
  323. }
  324. }
  325. else if (idle_flag != 1)
  326. /*
  327. * No previous data, show 0's instead of calculating negatives
  328. * only if we are shoring idle processes.
  329. */
  330. printf("%5d %8d %8d %8d %8d %8d %8d %8d %s\n",
  331. ion->pid, 0, 0, 0, 0, 0, 0, 0, ion->command);
  332. upsert_data(ion);
  333. }
  334. closedir(dir);
  335. return;
  336. }
  337. struct io_node *
  338. new_ion(char *pid)
  339. {
  340. struct io_node *ion;
  341. ion = (struct io_node *) malloc(sizeof(struct io_node));
  342. bzero(ion, sizeof(struct io_node));
  343. ion->pid = atoi(pid);
  344. return ion;
  345. }
  346. void
  347. upsert_data(struct io_node *ion)
  348. {
  349. struct io_node *n;
  350. /* List is empty. */
  351. if (head == NULL)
  352. {
  353. head = ion;
  354. return;
  355. }
  356. /* Check if we have seen this pid before. */
  357. n = head;
  358. while (n != NULL)
  359. {
  360. if (n->pid == ion->pid)
  361. {
  362. n->rchar = ion->rchar;
  363. n->wchar = ion->wchar;
  364. n->syscr = ion->syscr;
  365. n->syscw = ion->syscw;
  366. n->read_bytes = ion->read_bytes;
  367. n->write_bytes = ion->write_bytes;
  368. n->cancelled_write_bytes = ion->cancelled_write_bytes;
  369. /*
  370. * If the pids wrap, then the command may be different then before.
  371. */
  372. strcpy(n->command, ion->command);
  373. free(ion);
  374. return;
  375. }
  376. n = n->next;
  377. }
  378. /* Add this pid to the list. */
  379. head = insert_ion(ion);
  380. return;
  381. }
  382. void
  383. usage()
  384. {
  385. printf("usage: iopp -h|--help\n");
  386. printf("usage: iopp [-ci] [-k|-m] [delay [count]]\n");
  387. printf(" -c, --command display full command line\n");
  388. printf(" -h, --help display help\n");
  389. printf(" -i, --idle hides idle processes\n");
  390. printf(" -k, --kilobytes display data in kilobytes\n");
  391. printf(" -m, --megabytes display data in megabytes\n");
  392. printf(" -u, --human-readable display data in kilo-, mega-, or giga-bytes\n");
  393. }
  394. int
  395. main(int argc, char *argv[])
  396. {
  397. int c;
  398. int delay = 0;
  399. int count = 0;
  400. int max_count = 1;
  401. while (1)
  402. {
  403. int option_index = 0;
  404. static struct option long_options[] = {
  405. { "command", no_argument, 0, 'c' },
  406. { "help", no_argument, 0, 'h' },
  407. { "human-readable", no_argument, 0, 'u' },
  408. { "idle", no_argument, 0, 'i' },
  409. { "kilobytes", no_argument, 0, 'k' },
  410. { "megabytes", no_argument, 0, 'm' },
  411. { 0, 0, 0, 0 }
  412. };
  413. c = getopt_long(argc, argv, "chikmu", long_options, &option_index);
  414. if (c == -1)
  415. {
  416. /* Handle delay and count arguments. */
  417. if (argc == optind)
  418. break; /* No additional arguments. */
  419. else if ((argc - optind) == 1)
  420. {
  421. delay = atoi(argv[optind]);
  422. max_count = -1;
  423. }
  424. else if ((argc - optind) == 2)
  425. {
  426. delay = atoi(argv[optind]);
  427. max_count = atoi(argv[optind + 1]);
  428. }
  429. else
  430. {
  431. /* Too many additional arguments. */
  432. usage();
  433. return 3;
  434. }
  435. break;
  436. }
  437. switch (c)
  438. {
  439. case 'c':
  440. command_flag = 1;
  441. break;
  442. case 'h':
  443. usage();
  444. return 0;
  445. case 'i':
  446. idle_flag = 1;
  447. break;
  448. case 'k':
  449. kb_flag = 1;
  450. break;
  451. case 'm':
  452. mb_flag = 1;
  453. break;
  454. case 'u':
  455. hr_flag = 1;
  456. break;
  457. default:
  458. usage();
  459. return 2;
  460. }
  461. }
  462. while (max_count == -1 || count++ < max_count)
  463. {
  464. get_stats();
  465. if (count != max_count)
  466. sleep(delay);
  467. }
  468. return 0;
  469. }
然后放到服务器上,gcc -o iopp iopp.c 编译一下

运行  ./iopp -i -k -c 1 > io.log 这个命令就可以把实时的io信息打印出来啦

打印出来的各项含义:

  • pid 进程ID
  • rchar 将要从磁盘读取的字节数
  • wchar 已经写入或应该要写入磁盘的字节数
  • syscr 读I/O数
  • syscw 写I/O数
  • rbytes 真正从磁盘读取的字节数
  • wbytes 真正写入到磁盘的字节数
  • cwbytes 因为清空页面缓存而导致没有发生操作的字节数
  • command 执行的命令

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多