Iopp, a replacement for Linux I/O tool iotop

Source: Internet
Author: User

Iotop is undoubtedly a good tool for linux I/O detection. However, many of my friends have abandoned the kernel version and Python version. I found iopp by accident and wrote it in c. It works with iotop, nice! Share with you


The installation method is simple. First, copy the following source code and save it as an iopp. c file.

#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 intindex = 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);} intget_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;}elsep = 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;} intget_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;} voidget_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");elseprintf("%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);elseprintf("%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;} voidupsert_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;} voidusage(){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");} intmain(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;}


Then put it on the server and compile gcc-o iopp. c.

Run the./iopp-I-k-c 1> io. log command to print the Real-Time io information.

Meaning:

  • Pid process ID
  • The number of bytes that rchar will read from the disk
  • Number of bytes that wchar has written or should be written to the disk
  • Syscr read I/O count
  • Syscw write I/O count
  • The number of bytes that rbytes actually reads from the disk
  • Number of bytes that wbytes actually writes to the disk
  • The number of bytes that are not operated by cwbytes because the page cache is cleared
  • Command


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.