Linux IO工具 iotop备择方案iopp

iotop毫无疑问linux IO检测上是一个很好的工具,但苦于要求和内核版本Python版本号。我的很多朋友放弃了。我也是。无意中发现iopp,使用c书面,与此iotop它是一个作用。nice!

一起分享


安装方法非常easy。首先复制以下源码保存为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, '
'); 
		length = q - p; 
		if (length >= BUFFERLEN) 
		{ 
			printf("ERROR - value is larger than the buffer: %d
", __LINE__); 
			exit(1); 
		} 
		strncpy(value, p, length); 
		value[length] = ''; 
		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
",
				__LINE__);
	fd = open(filename, O_RDONLY);
	if (fd == -1)
		return 1;
	length = read(fd, buffer, sizeof(buffer) - 1);
	close(fd);
	buffer[length] = '';
	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] = '';
	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
",
				__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] = ''; 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 ", "pid", "rchar", "wchar", "syscr", "syscw", "reads", "writes", "cwrites", "command"); else if (kb_flag == 1) printf("%5s %8s %8s %8s %8s %8s %8s %8s %s ", "pid", "rchar", "wchar", "syscr", "syscw", "rkb", "wkb", "cwkb", "command"); else if (mb_flag == 1) printf("%5s %8s %8s %8s %8s %8s %8s %8s %s ", "pid", "rchar", "wchar", "syscr", "syscw", "rmb", "wmb", "cwmb", "command"); else printf("%5s %8s %8s %8s %8s %8s %8s %8s %s ", "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 ", __LINE__); fd = open(filename, O_RDONLY); if (fd == -1) { free(ion); continue; } length = read(fd, buffer, sizeof(buffer) - 1); close(fd); buffer[length] = ''; /* 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 ", 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 ", 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 ", 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 "); printf("usage: iopp [-ci] [-k|-m] [delay [count]] "); printf(" -c, --command display full command line "); printf(" -h, --help display help "); printf(" -i, --idle hides idle processes "); printf(" -k, --kilobytes display data in kilobytes "); printf(" -m, --megabytes display data in megabytes "); printf(" -u, --human-readable display data in kilo-, mega-, or giga-bytes "); } 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; }


然后放到server上,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 运行的命令


版权声明:本文博客原创文章,博客,未经同意,不得转载。

原文地址:https://www.cnblogs.com/blfshiye/p/4642122.html