iopp替换iotop工具

复制下面代码 iopp.cc

然后放到服务器上,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 执行的命令

代码如下:

#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;  
}  

程序git地址:git@code.youkuaiyun.com:snippets/406028.git

代码地址:https://code.youkuaiyun.com/snippets/406028#nogo

转载于:https://my.oschina.net/zhangxc73912/blog/755183

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值