iotop无疑在linux IO检测上是个不错的工具,但苦于要求内核版本和Python版本,不少朋友放弃了,我也是。偶然间找到了iopp,用c写的,这个跟iotop是一个作用,nice!给大家分享下
安装方法很简单,首先复制下面源代码保存为iopp.c文件
- #include <stdio.h>
- #include <sys/types.h>
- #include <dirent.h>
- #include <ctype.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
- #include <getopt.h>
- #define PROC "/proc"
- #define GET_VALUE(v) \
- p = strchr(p, ':'); \
- ++p; \
- ++p; \
- q = strchr(p, '\n'); \
- length = q - p; \
- if (length >= BUFFERLEN) \
- { \
- printf("ERROR - value is larger than the buffer: %d\n", __LINE__); \
- exit(1); \
- } \
- strncpy(value, p, length); \
- value[length] = '\0'; \
- v = atoll(value);
- #define BTOKB(b) b >> 10
- #define BTOMB(b) b >> 20
- #define BUFFERLEN 255
- #define COMMANDLEN 1024
- #define VALUELEN 63
- #define NUM_STRINGS 8
- struct io_node
- {
- int pid;
- long long rchar;
- long long wchar;
- long long syscr;
- long long syscw;
- long long read_bytes;
- long long write_bytes;
- long long cancelled_write_bytes;
- char command[COMMANDLEN + 1];
- struct io_node *next;
- };
- struct io_node *head = NULL;
- int command_flag = 0;
- int idle_flag = 0;
- int mb_flag = 0;
- int kb_flag = 0;
- int hr_flag = 0;
- /* Prototypes */
- char *format_b(long long);
- struct io_node *get_ion(int);
- struct io_node *new_ion(char *);
- void upsert_data(struct io_node *);
- char *
- format_b(long long amt)
- {
- static char retarray[NUM_STRINGS][16];
- static int index = 0;
- register char *ret;
- register char tag = 'B';
- ret = retarray[index];
- index = (index + 1) % NUM_STRINGS;
- if (amt >= 10000) {
- amt = (amt + 512) / 1024;
- tag = 'K';
- if (amt >= 10000) {
- amt = (amt + 512) / 1024;
- tag = 'B';
- if (amt >= 10000) {
- amt = (amt + 512) / 1024;
- tag = 'G';
- }
- }
- }
- snprintf(ret, sizeof(retarray[index]) - 1, "%lld%c", amt, tag);
- return (ret);
- }
- int
- get_cmdline(struct io_node *ion)
- {
- int fd;
- int length;
- char filename[BUFFERLEN + 1];
- char buffer[COMMANDLEN + 1];
- char *p;
- char *q;
- length = snprintf(filename, BUFFERLEN, "%s/%d/cmdline", PROC, ion->pid);
- if (length == BUFFERLEN)
- printf("WARNING - filename length may be too big for buffer: %d\n",
- __LINE__);
- fd = open(filename, O_RDONLY);
- if (fd == -1)
- return 1;
- length = read(fd, buffer, sizeof(buffer) - 1);
- close(fd);
- buffer[length] = '\0';
- if (length == 0)
- return 2;
- if (command_flag == 0)
- {
- /*
- * The command is near the beginning; we don't need to be able to
- * the entire stat file.
- */
- p = strchr(buffer, '(');
- ++p;
- q = strchr(p, ')');
- length = q - p;
- }
- else
- p = buffer;
- length = length < COMMANDLEN ? length : COMMANDLEN;
- strncpy(ion->command, p, length);
- ion->command[length] = '\0';
- return 0;
- }
- struct io_node *
- get_ion(int pid)
- {
- struct io_node *c = head;
- while (c != NULL)
- {
- if (c->pid == pid)
- break;
- c = c->next;
- }
- return c;
- }
- int
- get_tcomm(struct io_node *ion)
- {
- int fd;
- int length;
- char filename[BUFFERLEN + 1];
- char buffer[BUFFERLEN + 1];
- char *p;
- char *q;
- length = snprintf(filename, BUFFERLEN, "%s/%d/stat", PROC, ion->pid);
- if (length == BUFFERLEN)
- printf("WARNING - filename length may be too big for buffer: %d\n",
- __LINE__);
- fd = open(filename, O_RDONLY);
- if (fd == -1)
- return 1;
- length = read(fd, buffer, sizeof(buffer) - 1);
- close(fd);
- /*
- * The command is near the beginning; we don't need to be able to
- * the entire stat file.
- */
- p = strchr(buffer, '(');
- ++p;
- q = strchr(p, ')');
- length = q - p;
- length = length < BUFFERLEN ? length : BUFFERLEN;
- strncpy(ion->command, p, length);
- ion->command[length] = '\0';
- return 0;
- }
- struct io_node *
- insert_ion(struct io_node *ion)
- {
- struct io_node *c;
- struct io_node *p;
- /* Check the head of the list as a special case. */
- if (ion->pid < head->pid)
- {
- ion->next = head;
- head = ion;
- return head;
- }
- c = head->next;
- p = head;
- while (c != NULL)
- {
- if (ion->pid < c->pid)
- {
- ion->next = c;
- p->next = ion;
- return head;
- }
- p = c;
- c = c->next;
- }
- /* Append to the end of the list. */
- if (c == NULL)
- p->next = ion;
- return head;
- }
- void
- get_stats()
- {
- DIR *dir = opendir(PROC);
- struct dirent *ent;
- char filename[BUFFERLEN + 1];
- char buffer[BUFFERLEN + 1];
- char value[BUFFERLEN + 1];
- /* Display column headers. */
- if (hr_flag == 1)
- printf("%5s %5s %5s %8s %8s %5s %6s %7s %s\n", "pid", "rchar", "wchar",
- "syscr", "syscw", "reads", "writes", "cwrites", "command");
- else if (kb_flag == 1)
- printf("%5s %8s %8s %8s %8s %8s %8s %8s %s\n", "pid", "rchar", "wchar",
- "syscr", "syscw", "rkb", "wkb", "cwkb", "command");
- else if (mb_flag == 1)
- printf("%5s %8s %8s %8s %8s %8s %8s %8s %s\n", "pid", "rchar", "wchar",
- "syscr", "syscw", "rmb", "wmb", "cwmb", "command");
- else
- printf("%5s %8s %8s %8s %8s %8s %8s %8s %s\n", "pid", "rchar", "wchar",
- "syscr", "syscw", "rbytes", "wbytes", "cwbytes", "command");
- /* Loop through the process table and display a line per pid. */
- while ((ent = readdir(dir)) != NULL)
- {
- int rc;
- int fd;
- int length;
- char *p;
- char *q;
- struct io_node *ion;
- struct io_node *old_ion;
- long long rchar;
- long long wchar;
- long long syscr;
- long long syscw;
- long long read_bytes;
- long long write_bytes;
- long long cancelled_write_bytes;
- if (!isdigit(ent->d_name[0]))
- continue;
- ion = new_ion(ent->d_name);
- if (command_flag == 1)
- rc = get_cmdline(ion);
- if (command_flag == 0 || rc != 0)
- /* If the full command line is not asked for or is empty... */
- rc = get_tcomm(ion);
- if (rc != 0)
- {
- free(ion);
- continue;
- }
- /* Read 'io' file. */
- length = snprintf(filename, BUFFERLEN, "%s/%s/io", PROC, ent->d_name);
- if (length == BUFFERLEN)
- printf("WARNING - filename length may be too big for buffer: %d\n",
- __LINE__);
- fd = open(filename, O_RDONLY);
- if (fd == -1)
- {
- free(ion);
- continue;
- }
- length = read(fd, buffer, sizeof(buffer) - 1);
- close(fd);
- buffer[length] = '\0';
- /* Parsing the io file data. */
- p = buffer;
- GET_VALUE(ion->rchar);
- GET_VALUE(ion->wchar);
- GET_VALUE(ion->syscr);
- GET_VALUE(ion->syscw);
- GET_VALUE(ion->read_bytes);
- GET_VALUE(ion->write_bytes);
- GET_VALUE(ion->cancelled_write_bytes);
- old_ion = get_ion(ion->pid);
- /* Display the pid's io data. */
- if (old_ion != NULL)
- {
- rchar = ion->rchar - old_ion->rchar;
- wchar = ion->wchar - old_ion->wchar;
- syscr = ion->syscr - old_ion->syscr;
- syscw = ion->syscw - old_ion->syscw;
- read_bytes = ion->read_bytes - old_ion->read_bytes;
- write_bytes = ion->write_bytes - old_ion->write_bytes;
- cancelled_write_bytes = ion->cancelled_write_bytes -
- old_ion->cancelled_write_bytes;
- if (kb_flag == 1 && hr_flag == 0)
- {
- rchar = BTOKB(rchar);
- wchar = BTOKB(wchar);
- syscr = BTOKB(syscr);
- syscw = BTOKB(syscw);
- read_bytes = BTOKB(read_bytes);
- write_bytes = BTOKB(write_bytes);
- cancelled_write_bytes = BTOKB(cancelled_write_bytes);
- }
- else if (mb_flag == 1 && hr_flag == 0)
- {
- rchar = BTOMB(rchar);
- wchar = BTOMB(wchar);
- syscr = BTOMB(syscr);
- syscw = BTOMB(syscw);
- read_bytes = BTOMB(read_bytes);
- write_bytes = BTOMB(write_bytes);
- cancelled_write_bytes = BTOMB(cancelled_write_bytes);
- }
- if (!(idle_flag == 1 && rchar == 0 && wchar == 0 && syscr == 0 &&
- syscw == 0 && read_bytes == 0 && write_bytes == 0 &&
- cancelled_write_bytes == 0)) {
- if (hr_flag == 0)
- printf("%5d %8lld %8lld %8lld %8lld %8lld %8lld %8lld %s\n",
- ion->pid,
- rchar,
- wchar,
- syscr,
- syscw,
- read_bytes,
- write_bytes,
- cancelled_write_bytes,
- ion->command);
- else
- printf("%5d %5s %5s %8lld %8lld %5s %6s %7s %s\n",
- ion->pid,
- format_b(rchar),
- format_b(wchar),
- syscr,
- syscw,
- format_b(read_bytes),
- format_b(write_bytes),
- format_b(cancelled_write_bytes),
- ion->command);
- }
- }
- else if (idle_flag != 1)
- /*
- * No previous data, show 0's instead of calculating negatives
- * only if we are shoring idle processes.
- */
- printf("%5d %8d %8d %8d %8d %8d %8d %8d %s\n",
- ion->pid, 0, 0, 0, 0, 0, 0, 0, ion->command);
- upsert_data(ion);
- }
- closedir(dir);
- return;
- }
- struct io_node *
- new_ion(char *pid)
- {
- struct io_node *ion;
- ion = (struct io_node *) malloc(sizeof(struct io_node));
- bzero(ion, sizeof(struct io_node));
- ion->pid = atoi(pid);
- return ion;
- }
- void
- upsert_data(struct io_node *ion)
- {
- struct io_node *n;
- /* List is empty. */
- if (head == NULL)
- {
- head = ion;
- return;
- }
- /* Check if we have seen this pid before. */
- n = head;
- while (n != NULL)
- {
- if (n->pid == ion->pid)
- {
- n->rchar = ion->rchar;
- n->wchar = ion->wchar;
- n->syscr = ion->syscr;
- n->syscw = ion->syscw;
- n->read_bytes = ion->read_bytes;
- n->write_bytes = ion->write_bytes;
- n->cancelled_write_bytes = ion->cancelled_write_bytes;
- /*
- * If the pids wrap, then the command may be different then before.
- */
- strcpy(n->command, ion->command);
- free(ion);
- return;
- }
- n = n->next;
- }
- /* Add this pid to the list. */
- head = insert_ion(ion);
- return;
- }
- void
- usage()
- {
- printf("usage: iopp -h|--help\n");
- printf("usage: iopp [-ci] [-k|-m] [delay [count]]\n");
- printf(" -c, --command display full command line\n");
- printf(" -h, --help display help\n");
- printf(" -i, --idle hides idle processes\n");
- printf(" -k, --kilobytes display data in kilobytes\n");
- printf(" -m, --megabytes display data in megabytes\n");
- printf(" -u, --human-readable display data in kilo-, mega-, or giga-bytes\n");
- }
- int
- main(int argc, char *argv[])
- {
- int c;
- int delay = 0;
- int count = 0;
- int max_count = 1;
- while (1)
- {
- int option_index = 0;
- static struct option long_options[] = {
- { "command", no_argument, 0, 'c' },
- { "help", no_argument, 0, 'h' },
- { "human-readable", no_argument, 0, 'u' },
- { "idle", no_argument, 0, 'i' },
- { "kilobytes", no_argument, 0, 'k' },
- { "megabytes", no_argument, 0, 'm' },
- { 0, 0, 0, 0 }
- };
- c = getopt_long(argc, argv, "chikmu", long_options, &option_index);
- if (c == -1)
- {
- /* Handle delay and count arguments. */
- if (argc == optind)
- break; /* No additional arguments. */
- else if ((argc - optind) == 1)
- {
- delay = atoi(argv[optind]);
- max_count = -1;
- }
- else if ((argc - optind) == 2)
- {
- delay = atoi(argv[optind]);
- max_count = atoi(argv[optind + 1]);
- }
- else
- {
- /* Too many additional arguments. */
- usage();
- return 3;
- }
- break;
- }
- switch (c)
- {
- case 'c':
- command_flag = 1;
- break;
- case 'h':
- usage();
- return 0;
- case 'i':
- idle_flag = 1;
- break;
- case 'k':
- kb_flag = 1;
- break;
- case 'm':
- mb_flag = 1;
- break;
- case 'u':
- hr_flag = 1;
- break;
- default:
- usage();
- return 2;
- }
- }
- while (max_count == -1 || count++ < max_count)
- {
- get_stats();
- if (count != max_count)
- sleep(delay);
- }
- return 0;
- }
然后放到服务器上,gcc -o iopp iopp.c 编译一下运行 ./iopp -i -k -c 1 > io.log 这个命令就可以把实时的io信息打印出来啦
打印出来的各项含义:
联系客服