Ticket #9019: 0001-iotop-Add-an-iotop-utility.patch

File 0001-iotop-Add-an-iotop-utility.patch, 24.3 KB (added by Prasad, 12 years ago)
  • build/jam/HaikuImage

    From 30a9cee60ef431340728f0d5789d1529c7f47c7d Mon Sep 17 00:00:00 2001
    From: Prasad Joshi <prasadjoshi.linux@gmail.com>
    Date: Sun, 23 Sep 2012 20:50:52 +0530
    Subject: [PATCH] iotop: Add an iotop utility
    
    iotop is a simple top like utility for monitoring IOs. For utility to
    work, kernel must do IO accounting for each process. The patch adds
    struct io_accounting in the kernel account for IOs performed by each
    process.
    
    The accounting for IO is performed in various version of read and
    write system calls.
    
    The userland part (iotop command) uses team_info mechanism to get
    the accounting information in the userland. The utility provides user
    with lots of options like
    	- monitoring processes of particular user
    	- monitoring processes based on process ids
    	- only showing processes doing actual IOs
    	- configuration refreshing delay
    
    iotop also allows user to sort the output on various parameters
    dynamically while running.
    
    The utility also checks the visible terminal co-ordinates and updates
    the output accordingly.
    
    Here is a sample output of the iotop:
    ~> ./iotop
    
    Total Disk Reads:    2.00 B/s | Total Disk Writes:    0.00 B/s
    
        TID     USER     READ BW    WRITE BW      IO %   Command
        114     user    2.00 B/s    0.00 B/s  100.00 %   /boot/system/servers/power_daemon
         48     user    0.00 B/s    0.00 B/s    0.00 %   /boot/system/servers/registrar
         55     user    0.00 B/s    0.00 B/s    0.00 %   /boot/system/servers/debug_server
         56     user    0.00 B/s    0.00 B/s    0.00 %   /boot/system/servers/net_server
         57     user    0.00 B/s    0.00 B/s    0.00 %   /boot/system/servers/app_server
         72     user    0.00 B/s    0.00 B/s    0.00 %   /boot/system/servers/syslog_daemon
         84     user    0.00 B/s    0.00 B/s    0.00 %   /boot/system/servers/input_server
         94     user    0.00 B/s    0.00 B/s    0.00 %   /boot/system/servers/mount_server
        106     user    0.00 B/s    0.00 B/s    0.00 %   /boot/system/Tracker
        107     user    0.00 B/s    0.00 B/s    0.00 %   /boot/system/Deskbar
        108     user    0.00 B/s    0.00 B/s    0.00 %   /boot/system/servers/media_server
        109     user    0.00 B/s    0.00 B/s    0.00 %   /boot/system/servers/midi_server
        110     user    0.00 B/s    0.00 B/s    0.00 %   /boot/system/servers/print_server
        112     user    0.00 B/s    0.00 B/s    0.00 %   /boot/system/servers/cddb_daemon
        113     user    0.00 B/s    0.00 B/s    0.00 %   /boot/system/servers/notification_server
        143     user    0.00 B/s    0.00 B/s    0.00 %   /boot/system/servers/media_addon_server
        193     user    0.00 B/s    0.00 B/s    0.00 %   /boot/system/apps/Terminal
        197     user    0.00 B/s    0.00 B/s    0.00 %   /bin/bash -l
          1     user    0.00 B/s    0.00 B/s    0.00 %   kernel_team
        212     user    0.00 B/s    0.00 B/s    0.00 %   ./iotop
    -----------------------------------------------------------------------
    User: all
    Processes: all
    Sorted according to 'Percentage of total IOs'.  Reverse Sorting: false
    Refreshing every 3 seconds.
    
    ~> ./iotop -o
    
    Total Disk Reads:    2.00 B/s | Total Disk Writes:    0.00 B/s
    
        TID     USER     READ BW    WRITE BW      IO %   Command
        114     user    2.00 B/s    0.00 B/s  100.00 %   /boot/system/servers/power_daemon
    -----------------------------------------------------------------------
    User: all
    Processes: all
    Only showing processes doing IOs.
    Sorted according to 'Percentage of total IOs'.  Reverse Sorting: false
    Refreshing every 3 seconds.
    
    Signed-off-by: Prasad Joshi <prasadjoshi.linux@gmail.com>
    ---
     build/jam/HaikuImage                  |    2 +-
     headers/os/kernel/OS.h                |    4 +
     headers/private/kernel/thread_types.h |   26 ++
     src/bin/Jamfile                       |    1 +
     src/bin/iotop.c                       |  761 +++++++++++++++++++++++++++++++++
     src/system/kernel/fs/fd.cpp           |   49 ++-
     src/system/kernel/team.cpp            |   14 +-
     7 files changed, 851 insertions(+), 6 deletions(-)
     create mode 100644 src/bin/iotop.c
    
    diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage
    index 67fc612..c902c58 100644
    a b SYSTEM_BIN = "[" addattr alert arp base64 basename bash bc beep bfsinfo  
    5858    setversion setvolume seq sha1sum shar shred shuf shutdown sleep sort
    5959    spamdbm
    6060    split stat strace stty su sum sync sysinfo
    61     tac tail tcpdump tcptester tee telnet telnetd test timeout top touch
     61    tac tail tcpdump tcptester tee telnet telnetd test timeout top iotop touch
    6262    tput tr traceroute translate trash true truncate tsort tty
    6363    uname unchop unexpand unmount uniq unlink unrar unshar unzip unzipsfx
    6464    <bin>updatedb uptime urlwrapper useradd uudecode uuencode
  • headers/os/kernel/OS.h

    diff --git a/headers/os/kernel/OS.h b/headers/os/kernel/OS.h
    index 1f921f9..1aba5d3 100644
    a b typedef struct {  
    236236    char            args[64];
    237237    uid_t           uid;
    238238    gid_t           gid;
     239    int64           read_sys_calls;
     240    int64           write_sys_calls;
     241    int64           read_bytes;
     242    int64           write_bytes;
    239243} team_info;
    240244
    241245#define B_CURRENT_TEAM  0
  • headers/private/kernel/thread_types.h

    diff --git a/headers/private/kernel/thread_types.h b/headers/private/kernel/thread_types.h
    index 017da64..6810b94 100644
    a b typedef bool (*page_fault_callback)(addr_t address, addr_t faultAddress,  
    193193
    194194namespace BKernel {
    195195
     196struct io_accounting {
     197    vint64          read_sys_calls;
     198    vint64          write_sys_calls;
     199
     200    vint64          write;
     201    vint64          read;
     202
     203public:
     204    vint64 get_read_syscalls(void)  { return atomic_get64(&read_sys_calls);  }
     205
     206    vint64 get_write_syscalls(void) { return atomic_get64(&write_sys_calls); }
     207
     208    vint64 get_wrote_bytes(void)    { return atomic_get64(&write);     }
     209
     210    vint64 get_read_bytes(void) { return atomic_get64(&read);      }
     211
     212    void read_syscall(void)     { atomic_add64(&read_sys_calls, 1);  }
     213
     214    void write_syscall(void)    { atomic_add64(&write_sys_calls, 1); }
     215
     216    void read_bytes(ssize_t bytes)  { atomic_add64(&read, bytes); }
     217
     218    void write_bytes(ssize_t bytes) { atomic_add64(&write, bytes); }
     219};
    196220
    197221template<typename IDType>
    198222struct TeamThreadIteratorEntry
    struct Team : TeamThreadIteratorEntry<team_id>, KernelReferenceable,  
    280304    gid_t*          supplementary_groups;
    281305    int             supplementary_group_count;
    282306
     307    struct io_accounting    io_acc;
     308
    283309    // Exit status information. Set when the first terminal event occurs,
    284310    // immutable afterwards. Protected by fLock.
    285311    struct {
  • src/bin/Jamfile

    diff --git a/src/bin/Jamfile b/src/bin/Jamfile
    index 2a59586..bc58cb7 100644
    a b StdBinCommands  
    7171
    7272# standard commands that need libtermcap.a
    7373StdBinCommands
     74    iotop.c
    7475    top.c
    7576    tput.c
    7677    : libtermcap.a : $(haiku-utils_rsrc) ;
  • new file src/bin/iotop.c

    diff --git a/src/bin/iotop.c b/src/bin/iotop.c
    new file mode 100644
    index 0000000..6613446
    - +  
     1/*
     2 * Copyright 2012 Haiku, Inc. All rights reserved.
     3 * Distributed under the terms of the MIT License.
     4 *
     5 * Authors:
     6 *          Prasad Joshi <prasadjoshi.linux@gmail.com>
     7 */
     8
     9#include <stdio.h>
     10#include <stdarg.h>
     11#include <string.h>
     12#include <stdlib.h>
     13#include <termcap.h>
     14#include <termios.h>
     15#include <sys/types.h>
     16#include <pwd.h>
     17#include <errno.h>
     18#include <sys/select.h>
     19#include <sys/time.h>
     20#include <unistd.h>
     21#include <fcntl.h>
     22#include <OS.h>
     23
     24#define ALL "all"
     25
     26typedef struct {
     27    team_id     tid;
     28    uid_t       uid;
     29    int64       read;
     30    int64       wrote;
     31    double      percent;
     32    char        cmd[64];
     33} team_ios_t;
     34
     35typedef struct {
     36    int         nthreads;
     37    team_ios_t  *threads;
     38} team_ios_list_t;
     39
     40typedef enum {
     41    TID = 0,
     42    UID,
     43    READ,
     44    WRITE,
     45    PERCENT,
     46    CMD
     47} SORT_KEY;
     48
     49static char *sort_keys[] = {
     50    "Proccesses ID",
     51    "User ID",
     52    "Read Bandwidth",
     53    "Write Bandwidth",
     54    "Percentage of total IOs",
     55    "Process Name",
     56};
     57
     58static int      rows;             /* # rows on the screen */
     59static int      cols;             /* # columns on the screen */
     60static char     *clear_screen = NULL;
     61static bool     screen_size_changed = false; /* set in signal handler */
     62static SORT_KEY sort_key = PERCENT;     /* default key for sorting data */
     63static bool     reverse = false;     /* reverse sorting */
     64static tcflag_t tty_local_modes = 0;     /* saved terminal mode */
     65static char     *program = NULL;
     66
     67/* program parameters */
     68static int  delay       = 3;
     69static int  iter        = 0;
     70
     71static char *user       = "all";
     72static uid_t user_uid   = 0;
     73static bool user_filter = false;
     74
     75static char     *proc   = "all";
     76static team_id  *tids   = NULL;
     77
     78static bool only_ios    = false;
     79
     80static void usage(void)
     81{
     82    printf( "Usage: %s\n"
     83        "-d <delay in seconds (default = 3)>\n"
     84        "-i <# iterations (default = 0)>\n"
     85        "-u <monitor processes of user (default = all)>\n"
     86        "-p <comma separated list of pids to monitor (default = all)>\n"
     87        "-o only show processes doing ios (default = false)\n"
     88        "-h show this message\n", program);
     89}
     90
     91static void end(const char *msg, int rc)
     92{
     93    if (msg)
     94        fprintf(stderr, "%s: %s", msg, strerror(rc));
     95
     96    if (strcmp(user, ALL))
     97        free(user);
     98
     99    if (strcmp(proc, ALL))
     100        free(proc);
     101
     102    exit(rc);
     103}
     104
     105/*
     106 * Converts uid to user name.
     107 * Caller is supposed to free the memory allocated for user name.
     108 */
     109static char *user_name(uid_t uid)
     110{
     111    struct passwd *b;
     112
     113    b = getpwuid(uid);
     114    if (!b)
     115        return NULL;
     116    return strdup(b->pw_name);
     117}
     118
     119/*
     120 * Convert user id to user name
     121 */
     122static int user_id(const char *name, uid_t *uid)
     123{
     124    struct passwd *b;
     125
     126    b = getpwnam(name);
     127    if (!b)
     128        return -1;
     129    *uid = b->pw_uid;
     130    return 0;
     131}
     132
     133static bool match_tid(team_id tid, team_id *tids)
     134{
     135    team_id *t;
     136
     137    t = tids;
     138    while (*t) {
     139        if (*t == tid)
     140            return true;
     141        t++;
     142    }
     143    return false;
     144}
     145
     146static void xtract_team_list(char *proc)
     147{
     148    char    *s;
     149    int     count;
     150    int     no_tids;
     151    char    *x;
     152    char    *s1;
     153    int     i;
     154    bool    done = false;
     155    team_id tid;
     156
     157    s = proc;
     158    count = 0;
     159    while (s) {
     160        s = strchr(s, ',');
     161        count++;
     162        if (!s)
     163            break;
     164        s++;
     165    }
     166
     167    /*
     168     * Since the list of tids is delimted with 0 tid, we need to allocate
     169     * memory for an additional tid. For example if user input is 1,2,3,4
     170     * then count will be 3 and memory for 5 tids will be allocated.
     171     */
     172    no_tids = count + 2;
     173
     174    tids = calloc(no_tids, sizeof(team_id));
     175    if (!tids) {
     176        fprintf(stderr, "Memory Allocation Failed.\n");
     177        end(__func__, ENOMEM);
     178    }
     179
     180    x = s1 = s = strdup(proc);
     181    i = 0;
     182    while (!done) {
     183        s1 = strchr(s, ',');
     184
     185        if (!s1)
     186            done = true;
     187        else
     188            *s1 = 0;
     189
     190        tid = atol(s);
     191        if (tid) {
     192            tids[i] = tid;
     193            i++;
     194        }
     195
     196        s = s1 + 1;
     197    }
     198    tids[i] = 0;
     199    free(x);
     200}
     201
     202static int parse_arguments(int argc, char *argv[])
     203{
     204    int opt;
     205    bool invalid = false;
     206
     207    while ((opt = getopt(argc, argv, "d:i:u:p:oh")) != -1) {
     208        switch (opt) {
     209        case 'd':
     210            delay = atoi(optarg);
     211            if (!delay || delay < 0) {
     212                fprintf(stderr, "Invalid argument to -- d\n");
     213                invalid = true;
     214            }
     215            break;
     216        case 'i':
     217            iter = atoi(optarg);
     218            if (!iter || iter < 0) {
     219                fprintf(stderr, "Invalid argument to -- i\n");
     220                invalid = true;
     221            }
     222            break;
     223        case 'u': {
     224            char *u = strdup(optarg);
     225            if (strcmp(u, "all")) {
     226                int rc = user_id(u, &user_uid);
     227                if (rc < 0) {
     228                    fprintf(stderr, "No such user '%s'\n", u);
     229                    free(u);
     230                    invalid = true;
     231                }
     232                user = u;
     233                user_filter = true;
     234            } else {
     235                /* TODO: Handle user with name all */
     236                free(u);
     237            }
     238            break;
     239        }
     240        case 'p':
     241            proc = strdup(optarg);
     242            break;
     243        case 'o':
     244            only_ios = true;
     245            break;
     246        case 'h':
     247            usage();
     248            end(NULL, 0);
     249        default:
     250            usage();
     251            end(NULL, EINVAL);
     252        }
     253    }
     254
     255    if (invalid) {
     256        usage();
     257        end(NULL, EINVAL);
     258    }
     259
     260    if (!strcmp(proc, "all"))
     261        return 0;
     262
     263    /* proc must be comma separated list of pids */
     264    xtract_team_list(proc);
     265
     266    return 0;
     267}
     268
     269static void window_changed(int unused)
     270{
     271    screen_size_changed = true;
     272}
     273
     274static void clear(void)
     275{
     276    if (clear_screen) {
     277        printf(clear_screen);
     278        fflush(stdout);
     279    }
     280}
     281
     282static void cleanup(void)
     283{
     284    struct termios    tty;
     285
     286    free(clear_screen);
     287
     288    /* restore the terminal setting */
     289    tcgetattr(STDIN_FILENO, &tty);
     290    tty.c_lflag = tty_local_modes;
     291    tcsetattr(STDIN_FILENO, TCSAFLUSH, &tty);
     292}
     293
     294static int setup_term(bool only_rows, bool set_tty)
     295{
     296    struct termios    tty;
     297    struct winsize    ws;
     298    char        *term;
     299    char        *str;
     300    char        buf[2048];
     301    char        *entries;
     302
     303    if (set_tty) {
     304        errno = 0;
     305        if (tcgetattr(STDIN_FILENO, &tty) < 0)
     306            return -errno;
     307
     308        tty_local_modes = tty.c_lflag;
     309        tty.c_lflag &= ~(ECHO | ICANON);
     310
     311        errno = 0;
     312        if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tty) < 0)
     313            return -errno;
     314    }
     315
     316    if (ioctl(1, TIOCGWINSZ, &ws) < 0)
     317        return 0;
     318
     319    if (ws.ws_row <= 0)
     320        return 0;
     321    rows = ws.ws_row;
     322
     323    if (ws.ws_col <= 0)
     324        return 0;
     325    cols = ws.ws_col;
     326
     327    if (only_rows)
     328        return 1;
     329
     330    term = getenv("TERM");
     331    if (term == NULL)
     332        return 0;
     333
     334    if (tgetent(buf, term) <= 0)
     335        return 0;
     336
     337    entries = &buf[0];
     338    str = tgetstr("cl", &entries);
     339    if (str == NULL)
     340        return 0;
     341
     342    clear_screen = strdup(str);
     343    return 1;
     344}
     345
     346/*
     347 * Convert bytes into more user readable form of KB, MB, or GB
     348 */
     349static inline void bandwidth(char *buf, int size, int64 bytes)
     350{
     351    double bw  = bytes;
     352    double bw1 = 0;
     353    int i;
     354    char unit[] = { 'B', 'K', 'M', 'G', 'T' };
     355
     356    i = 0;
     357    while ((int) bw) {
     358        bw1 = bw;
     359        bw /= 1024;
     360        i++;
     361    }
     362
     363    if (!i)
     364        i++;
     365
     366    snprintf(buf, size, "%0.2f %c/s", bw1, unit[i - 1]);
     367    return;
     368}
     369
     370/*
     371 * Display a line on terminal, limit to available characters in column
     372 */
     373static int display_line(const char *f, ...)
     374{
     375    va_list ap;
     376    char line[cols];
     377    int n;
     378
     379    va_start(ap, f);
     380    /* sizeof(line) - 1 since we need to add a trailing newline */
     381    n = vsnprintf(line, sizeof(line) - 1, f, ap);
     382    va_end(ap);
     383
     384    if (n < 0)
     385        return -1;
     386
     387    printf("%s\n", line);
     388    return 0;
     389}
     390
     391static void char_repeat(char *buf, char ch, int count)
     392{
     393    buf[count--] = 0;
     394    for (; count >= 0; count--)
     395        buf[count] = ch;
     396}
     397
     398static void display_preferences(void)
     399{
     400    char buf[cols];
     401    char_repeat(buf, '-', cols - 1);
     402    display_line("%s", buf);    // Line 1
     403
     404    display_line("User: %s", user); // Line 2
     405    display_line("Processes: %s", proc);    // Line 3
     406    if (only_ios)
     407        display_line("Only showing processes doing IOs."); // Line 4
     408
     409    display_line("Sorted according to '%s'.\tReverse Sorting: %s",
     410            sort_keys[sort_key], reverse ? "true" : "false");// Line 5
     411    display_line("Refreshing every %d seconds.", delay); // Line 6
     412    if (iter)
     413        display_line("Iterations still remaining: %d.", iter);
     414}
     415
     416static void display_delta(team_ios_t *d, int teams, int64 total_reads,
     417        int64 total_writes)
     418{
     419    char        rbw[256];
     420    char        wbw[256];
     421    team_ios_t  *t;
     422    int         i;
     423    char        *n;
     424
     425    clear();
     426
     427    bandwidth(rbw, sizeof(rbw), total_reads);
     428    bandwidth(wbw, sizeof(wbw), total_writes);
     429
     430    display_line("Total Disk Reads: %11s | Total Disk Writes: %11s", rbw,
     431            wbw);
     432    display_line("\n%7s %8s %11s %11s %9s   %s", "TID", "USER",
     433            "READ BW", "WRITE BW", "IO %", "Command");
     434
     435    t = d;
     436    for (i = 0; i < teams; i++, t++) {
     437        if (i + 8 > rows) {
     438            /*
     439             * maximum rows can only be disaplyed on terminal.
     440             * Additional 8 rows are left for displaying user
     441             * preferences and title.
     442             */
     443            continue;
     444        }
     445
     446        if (only_ios && (!(t->read + t->wrote))) {
     447            /* skip: user has asked for processes doing IOs */
     448            continue;
     449        }
     450
     451        if (user_filter && (user_uid != t->uid)) {
     452            /* skip: looking for processes of a selected user */
     453            continue;
     454        }
     455
     456        if (tids) {
     457            /* must be the last condition for better performance */
     458            if (!match_tid(t->tid, tids)) {
     459                /* skip: looking for processes with specific tids */
     460                continue;
     461            }
     462        }
     463
     464        n = user_name(t->uid);
     465        bandwidth(rbw, sizeof(rbw), t->read);
     466        bandwidth(wbw, sizeof(wbw), t->wrote);
     467
     468
     469        display_line("%7d %8s %11s %11s %7.2f %%   %s", t->tid, n,
     470                rbw, wbw, t->percent, t->cmd);
     471
     472        free(n);
     473    }
     474
     475    display_preferences();
     476}
     477
     478static int compare_ios(const void *a, const void *b)
     479{
     480    const team_ios_t *d1 = a;
     481    const team_ios_t *d2 = b;
     482    int rc;
     483
     484    switch (sort_key) {
     485    case TID:
     486        rc = d1->tid - d2->tid;
     487        break;
     488    case UID:
     489        rc = d2->uid - d1->uid;
     490        break;
     491    case READ:
     492        rc = d2->read - d1->read;
     493        break;
     494    case WRITE:
     495        rc = d2->wrote - d1->wrote;
     496        break;
     497    case PERCENT:
     498        rc = d2->percent - d1->percent;
     499        break;
     500    case CMD:
     501        rc = strcmp(d1->cmd, d2->cmd);
     502        break;
     503    default:
     504        end("compare_ios", 1);
     505    }
     506
     507    if (!rc) {
     508        /* use ios performed for deciding order */
     509        rc = (d2->read + d2->wrote) - (d1->read + d1->wrote);
     510    }
     511
     512    return reverse? 0 - rc : rc;
     513}
     514
     515static void cal_io_percent(team_ios_t *d, int teams, int64 total_ios)
     516{
     517    team_ios_t  *t;
     518    int         i;
     519
     520    t = d;
     521    for (i = 0; i < teams; i++, t++)
     522        t->percent = (100 * (t->wrote + t->read)) / (double) total_ios;
     523}
     524
     525static int grow(team_ios_list_t *l)
     526{
     527    l->nthreads++;
     528    l->threads = realloc(l->threads, sizeof(*l->threads) * l->nthreads);
     529
     530    if (!l->threads)
     531        return -1;
     532    return 0;
     533}
     534
     535static team_ios_list_t *gather(team_ios_list_t *old)
     536{
     537    team_ios_list_t *l;
     538    int32           c = 0;    // cookie
     539    team_info       tm;
     540    int             no;
     541    team_ios_t      *t;
     542    team_ios_t      *delta;
     543    int             i;
     544    team_ios_t      *ot;
     545    team_ios_t      *dt;
     546    int64           total_reads  = 0;
     547    int64           total_writes = 0;
     548
     549    l = malloc(sizeof(*l));
     550    if (!l) {
     551        fprintf(stderr, "Memory allocation failed.\n");
     552        return NULL;
     553    }
     554    memset(l, 0, sizeof(*l));
     555
     556    while (get_next_team_info(&c, &tm) == B_NO_ERROR) {
     557        if (grow(l) < 0) {
     558            fprintf(stderr, "Memory allocation failed.\n");
     559            return NULL;
     560        }
     561
     562        no = l->nthreads - 1;
     563        t  = l->threads + no;
     564
     565        t->tid      = tm.team;
     566        t->uid      = tm.uid;
     567        t->read     = tm.read_bytes;
     568        t->wrote    = tm.write_bytes;
     569        strlcpy(t->cmd, tm.args, sizeof(t->cmd));
     570    }
     571
     572    delta = malloc(sizeof(*delta) * (l->nthreads));
     573    if (!delta) {
     574        fprintf(stderr, "Memory allocation failed.\n");
     575        return NULL;
     576    }
     577
     578    for (i = 0; i < l->nthreads; i++) {
     579        t  = l->threads + i;
     580
     581        bool new_process = true;
     582
     583        if (old) {
     584            /* find team in old list */
     585            int j;
     586            for (j = 0; j < old->nthreads; j++) {
     587                ot = old->threads + j;
     588
     589                if (ot->tid == t->tid) {
     590                    /* process was already running */
     591                    new_process = false;
     592                    break;
     593                }
     594            }
     595        }
     596
     597        dt = delta + i;
     598        if (new_process) {
     599            /* a newly process has been started */
     600            dt->read  = t->read;
     601            dt->wrote = t->wrote;
     602        } else {
     603            dt->read  = t->read  - ot->read;
     604            dt->wrote = t->wrote - ot->wrote;
     605        }
     606
     607        dt->tid       = t->tid;
     608        dt->uid       = t->uid;
     609        total_reads  += dt->read;
     610        total_writes += dt->wrote;
     611        strlcpy(dt->cmd, t->cmd, sizeof(dt->cmd));
     612    }
     613
     614    if (old) {
     615        /* calculate percentage of total IOs for each team */
     616        cal_io_percent(delta, l->nthreads, total_reads + total_writes);
     617
     618        /* sort teams */
     619        qsort(delta, l->nthreads, sizeof(*delta), compare_ios);
     620
     621        /* display teams */
     622        display_delta(delta, l->nthreads, total_reads, total_writes);
     623
     624        free(delta);
     625
     626        /* ols list of teams is no longer needed */
     627        free(old->threads);
     628        free(old);
     629    }
     630    return l;
     631}
     632
     633static void handle_key(int key)
     634{
     635    switch (key) {
     636    case 't':
     637        sort_key = TID;
     638        break;
     639    case 'u':
     640        sort_key = UID;
     641        break;
     642    case 'r':
     643        sort_key = READ;
     644        break;
     645    case 'w':
     646        sort_key = WRITE;
     647        break;
     648    case 'p':
     649        sort_key = PERCENT;
     650        break;
     651    case 'c':
     652        sort_key = CMD;
     653        break;
     654    case 'x':
     655        /* toggle the reverse sorting */
     656        reverse = !reverse;
     657        break;
     658    case 'q':
     659        /* gracefully end the program */
     660        end(NULL, 0);
     661    }
     662}
     663
     664static int user_input(void)
     665{
     666    long    file_flags;
     667    int     rc;
     668    char    c;
     669
     670    file_flags = fcntl(STDIN_FILENO, F_GETFL);
     671    if (file_flags < 0)
     672        file_flags = 0;
     673
     674    if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK | file_flags) < 0)
     675        end("fcntl", errno);
     676
     677    rc = read(STDIN_FILENO, &c, 1);
     678
     679    if (fcntl(STDIN_FILENO, F_SETFL, file_flags) < 0)
     680        end("fcntl", errno);
     681
     682    if (rc < 0) {
     683        /* no user input */
     684        return -1;
     685    }
     686
     687    /* user has pressed a key */
     688    return c;
     689}
     690
     691int main(int argc, char *argv[])
     692{
     693    int     rc;
     694    team_ios_list_t *base_line = NULL;
     695    bool        iter_flag;
     696
     697    program = argv[0];
     698    parse_arguments(argc, argv);
     699
     700    rc = setup_term(false, true);
     701    if (rc < 0)
     702        end("setup_term", -rc);
     703
     704    signal(SIGWINCH, window_changed);
     705    atexit(cleanup);
     706
     707    base_line = gather(NULL);
     708    /*
     709     * We should not be displaying zero IOs during first iteration, wait
     710     * for a second so that we will have something to display.
     711     */
     712    sleep(1);
     713
     714    iter_flag = !!iter;
     715    while (!iter_flag || iter--) {
     716        if (screen_size_changed) {
     717            setup_term(true, false);
     718            screen_size_changed = false;
     719        }
     720
     721        base_line = gather(base_line);
     722
     723        rc = user_input();
     724        if (rc <= 0) {
     725            /* no user input, delay the execution */
     726            fd_set fs;
     727            struct timeval tv = {delay, 0};
     728
     729            FD_ZERO(&fs);
     730            FD_SET(STDIN_FILENO, &fs);
     731
     732            /* delay until user input or timeout */
     733            rc = select(1, &fs, NULL, NULL, &tv);
     734            if (rc < 0) {
     735                /*
     736                 * we might have been woken-up because of screen
     737                 * size changed signal. If it was the case then
     738                 * screen must be redrawn immediately.
     739                 */
     740                rc = 0;
     741                if (errno != EINTR)
     742                    end("select", errno);
     743            }
     744
     745            if (rc) {
     746                /* input from user is available */
     747                rc = user_input();
     748                if (rc < 0)
     749                    end("read", 1);
     750                if (rc == 0)
     751                    end(NULL, 0);
     752            }
     753        }
     754
     755        if (rc > 0) {
     756            /* user has pressed a key */
     757            handle_key(rc);
     758        }
     759    }
     760    return 0;
     761}
  • src/system/kernel/fs/fd.cpp

    diff --git a/src/system/kernel/fs/fd.cpp b/src/system/kernel/fs/fd.cpp
    index 04dd45e..047ebab 100644
    a b common_user_io(int fd, off_t pos, void* buffer, size_t length, bool write)  
    748748    else
    749749        status = descriptor->ops->fd_read(descriptor, pos, buffer, &length);
    750750
     751    Thread *thread = thread_get_current_thread();
     752    Team* team = thread->team;
     753    TeamLocker teamLocker(team);
     754    struct BKernel::io_accounting *acc;
     755
     756    acc = &team->io_acc;
     757
     758    /* account of for system call */
     759    if (write)
     760        acc->write_syscall();
     761    else
     762        acc->read_syscall();
     763
    751764    if (status != B_OK)
    752765        return status;
    753766
     767    ssize_t rc = length <= SSIZE_MAX ? (ssize_t)length : SSIZE_MAX;
     768
     769    /* account for IO bytes */
     770    if (write)
     771        acc->write_bytes(rc);
     772    else
     773        acc->read_bytes(rc);
     774
    754775    if (movePosition)
    755776        descriptor->pos = pos + length;
    756 
    757     return length <= SSIZE_MAX ? (ssize_t)length : SSIZE_MAX;
     777    return rc;
    758778}
    759779
    760780
    common_user_vector_io(int fd, off_t pos, const iovec* userVecs, size_t count,  
    816836
    817837        if (status != B_OK) {
    818838            if (bytesTransferred == 0)
    819                 return status;
     839                goto error;
    820840            status = B_OK;
    821841            break;
    822842        }
    common_user_vector_io(int fd, off_t pos, const iovec* userVecs, size_t count,  
    835855    if (movePosition)
    836856        descriptor->pos = pos;
    837857
     858error:
     859    Thread *thread = thread_get_current_thread();
     860    Team* team = thread->team;
     861    TeamLocker teamLocker(team);
     862    struct BKernel::io_accounting *acc;
     863
     864    acc = &team->io_acc;
     865
     866    /* account of for system call */
     867    if (write)
     868        acc->write_syscall();
     869    else
     870        acc->read_syscall();
     871
     872    if (status != B_OK)
     873        return status;
     874
     875    /* account for IO bytes */
     876    if (write)
     877        acc->write_bytes(bytesTransferred);
     878    else
     879        acc->read_bytes(bytesTransferred);
     880
    838881    return bytesTransferred;
    839882}
    840883
  • src/system/kernel/team.cpp

    diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp
    index b794b07..8b3f2f8 100644
    a b Team::Team(team_id id, bool kernel)  
    489489    memset(fSignalActions, 0, sizeof(fSignalActions));
    490490
    491491    fUserDefinedTimerCount = 0;
     492
     493    // initialize all io accounting counters to 0
     494    memset(&io_acc, 0, sizeof(io_acc));
    492495}
    493496
    494497
    fill_team_info(Team* team, team_info* info, size_t size)  
    24942497    //info->area_count =
    24952498    info->debugger_nub_thread = team->debug_info.nub_thread;
    24962499    info->debugger_nub_port = team->debug_info.nub_port;
    2497     //info->uid =
    2498     //info->gid =
     2500    info->uid = team->effective_uid;
     2501    info->gid = team->effective_gid;
     2502
     2503    struct BKernel::io_accounting *acc = &team->io_acc;
     2504
     2505    info->read_sys_calls    = acc->get_read_syscalls();
     2506    info->write_sys_calls   = acc->get_write_syscalls();
     2507    info->read_bytes    = acc->get_read_bytes();
     2508    info->write_bytes   = acc->get_wrote_bytes();
    24992509
    25002510    strlcpy(info->args, team->Args(), sizeof(info->args));
    25012511    info->argc = 1;