diff options
-rw-r--r-- | procps/iostat.c | 237 |
1 files changed, 117 insertions, 120 deletions
diff --git a/procps/iostat.c b/procps/iostat.c index cd233c72f..51c5fac08 100644 --- a/procps/iostat.c +++ b/procps/iostat.c @@ -7,23 +7,24 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ -//applet:IF_IOSTAT(APPLET(iostat, BB_DIR_BIN, BB_SUID_DROP)) - -//kbuild:lib-$(CONFIG_IOSTAT) += iostat.o - //config:config IOSTAT //config: bool "iostat" //config: default y //config: help //config: Report CPU and I/O statistics +//applet:IF_IOSTAT(APPLET(iostat, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_IOSTAT) += iostat.o + #include "libbb.h" -#include <sys/utsname.h> /* Need struct utsname */ +#include <sys/utsname.h> /* struct utsname */ //#define debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) #define debug(fmt, ...) ((void)0) #define MAX_DEVICE_NAME 12 +#define MAX_DEVICE_NAME_STR "12" #if 1 typedef unsigned long long cputime_t; @@ -64,21 +65,27 @@ typedef struct { cputime_t itv; } stats_cpu_pair_t; -struct stats_dev { - char dname[MAX_DEVICE_NAME]; +typedef struct { unsigned long long rd_sectors; unsigned long long wr_sectors; unsigned long rd_ops; unsigned long wr_ops; -}; +} stats_dev_data_t; + +typedef struct stats_dev { + struct stats_dev *next; + char dname[MAX_DEVICE_NAME + 1]; + stats_dev_data_t prev_data; + stats_dev_data_t curr_data; +} stats_dev_t; /* Globals. Sort by size and access frequency. */ struct globals { smallint show_all; unsigned total_cpus; /* Number of CPUs */ unsigned clk_tck; /* Number of clock ticks per second */ - llist_t *dev_list; /* List of devices entered on the command line */ - struct stats_dev *saved_stats_dev; + llist_t *dev_name_list; /* List of devices entered on the command line */ + stats_dev_t *stats_dev_list; struct tm tmtime; struct { const char *str; @@ -114,7 +121,7 @@ static ALWAYS_INLINE int this_is_smp(void) static void print_header(void) { - char buf[16]; + char buf[32]; struct utsname uts; uname(&uts); /* never fails */ @@ -136,7 +143,7 @@ static void get_localtime(struct tm *ptm) static void print_timestamp(void) { - char buf[20]; + char buf[64]; /* %x: date representation for the current locale */ /* %X: time representation for the current locale */ strftime(buf, sizeof(buf), "%x %X", &G.tmtime); @@ -162,18 +169,22 @@ static cputime_t get_smp_uptime(void) static void get_cpu_statistics(stats_cpu_t *sc) { FILE *fp; - char buf[1024], *ibuf = buf + 4; + char buf[1024]; fp = xfopen_for_read("/proc/stat"); memset(sc, 0, sizeof(*sc)); while (fgets(buf, sizeof(buf), fp)) { - /* Does the line starts with "cpu "? */ + int i; + char *ibuf; + + /* Does the line start with "cpu "? */ if (!starts_with_cpu(buf) || buf[3] != ' ') { continue; } - for (int i = STATS_CPU_USER; i <= STATS_CPU_GUEST; i++) { + ibuf = buf + 4; + for (i = STATS_CPU_USER; i <= STATS_CPU_GUEST; i++) { ibuf = skip_whitespace(ibuf); sscanf(ibuf, "%"FMT_DATA"u", &sc->vector[i]); if (i != STATS_CPU_GUEST) { @@ -233,7 +244,7 @@ static void print_stats_cpu_struct(stats_cpu_pair_t *stats) { cputime_t *p = stats->prev->vector; cputime_t *c = stats->curr->vector; - printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n", + printf(" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n", percent_value(p[STATS_CPU_USER] , c[STATS_CPU_USER] , stats->itv), percent_value(p[STATS_CPU_NICE] , c[STATS_CPU_NICE] , stats->itv), percent_value(p[STATS_CPU_SYSTEM] + p[STATS_CPU_SOFTIRQ] + p[STATS_CPU_IRQ], @@ -244,36 +255,40 @@ static void print_stats_cpu_struct(stats_cpu_pair_t *stats) ); } -static void print_stats_dev_struct(const struct stats_dev *p, - const struct stats_dev *c, cputime_t itv) +static void cpu_report(stats_cpu_pair_t *stats) { + /* Always print a header */ + puts("avg-cpu: %user %nice %system %iowait %steal %idle"); + + /* Print current statistics */ + print_stats_cpu_struct(stats); +} + +static void print_stats_dev_struct(stats_dev_t *stats_dev, cputime_t itv) +{ + stats_dev_data_t *p = &stats_dev->prev_data; + stats_dev_data_t *c = &stats_dev->curr_data; if (option_mask32 & OPT_z) if (p->rd_ops == c->rd_ops && p->wr_ops == c->wr_ops) return; - printf("%-13s %8.2f %12.2f %12.2f %10llu %10llu \n", c->dname, - percent_value(p->rd_ops + p->wr_ops , - /**/ c->rd_ops + c->wr_ops , itv), + printf("%-13s %8.2f %12.2f %12.2f %10llu %10llu\n", + stats_dev->dname, + percent_value(p->rd_ops + p->wr_ops, c->rd_ops + c->wr_ops, itv), percent_value(p->rd_sectors, c->rd_sectors, itv) / G.unit.div, percent_value(p->wr_sectors, c->wr_sectors, itv) / G.unit.div, (c->rd_sectors - p->rd_sectors) / G.unit.div, - (c->wr_sectors - p->wr_sectors) / G.unit.div); -} - -static void cpu_report(stats_cpu_pair_t *stats) -{ - /* Always print a header */ - puts("avg-cpu: %user %nice %system %iowait %steal %idle"); - - /* Print current statistics */ - print_stats_cpu_struct(stats); + (c->wr_sectors - p->wr_sectors) / G.unit.div + ); } static void print_devstat_header(void) { - printf("Device:%15s%6s%s/s%6s%s/s%6s%s%6s%s\n", "tps", + printf("Device:%15s%6s%s/s%6s%s/s%6s%s%6s%s\n", + "tps", G.unit.str, "_read", G.unit.str, "_wrtn", - G.unit.str, "_read", G.unit.str, "_wrtn"); + G.unit.str, "_read", G.unit.str, "_wrtn" + ); } /* @@ -285,61 +300,81 @@ static int is_partition(const char *dev) return ((dev[0] - 's') | (dev[1] - 'd') | (dev[2] - 'a')) == 0 && isdigit(dev[3]); } +static stats_dev_t *stats_dev_find_or_new(const char *dev_name) +{ + stats_dev_t **curr = &G.stats_dev_list; + + while (*curr != NULL) { + if (strcmp((*curr)->dname, dev_name) == 0) + return *curr; + curr = &(*curr)->next; + } + + *curr = xzalloc(sizeof(stats_dev_t)); + strncpy((*curr)->dname, dev_name, MAX_DEVICE_NAME); + return *curr; +} + +static void stats_dev_free(stats_dev_t *stats_dev) +{ + if (stats_dev) { + stats_dev_free(stats_dev->next); + free(stats_dev); + } +} + static void do_disk_statistics(cputime_t itv) { + char buf[128]; + char dev_name[MAX_DEVICE_NAME + 1]; + unsigned long long rd_sec_or_dummy; + unsigned long long wr_sec_or_dummy; + stats_dev_data_t *curr_data; + stats_dev_t *stats_dev; FILE *fp; int rc; - int i = 0; - char buf[128]; - unsigned major, minor; - unsigned long wr_ops, dummy; /* %*lu for suppress the conversion wouldn't work */ - unsigned long long rd_sec_or_wr_ops; - unsigned long long rd_sec_or_dummy, wr_sec_or_dummy, wr_sec; - struct stats_dev sd; fp = xfopen_for_read("/proc/diskstats"); - /* Read and possibly print stats from /proc/diskstats */ while (fgets(buf, sizeof(buf), fp)) { - rc = sscanf(buf, "%u %u %s %lu %llu %llu %llu %lu %lu %llu %lu %lu %lu %lu", - &major, &minor, sd.dname, &sd.rd_ops, - &rd_sec_or_dummy, &rd_sec_or_wr_ops, &wr_sec_or_dummy, - &wr_ops, &dummy, &wr_sec, &dummy, &dummy, &dummy, &dummy); - - switch (rc) { - case 14: - sd.wr_ops = wr_ops; - sd.rd_sectors = rd_sec_or_wr_ops; - sd.wr_sectors = wr_sec; - break; - case 7: - sd.rd_sectors = rd_sec_or_dummy; - sd.wr_ops = (unsigned long)rd_sec_or_wr_ops; - sd.wr_sectors = wr_sec_or_dummy; - break; - default: - break; + sscanf(buf, "%*s %*s %"MAX_DEVICE_NAME_STR"s", dev_name); + if (G.dev_name_list) { + /* Is device name in list? */ + if (!llist_find_str(G.dev_name_list, dev_name)) + continue; + } else if (is_partition(dev_name)) { + continue; } - if (!G.dev_list && !is_partition(sd.dname)) { - /* User didn't specify device */ - if (!G.show_all && !sd.rd_ops && !sd.wr_ops) { - /* Don't print unused device */ - continue; - } - print_stats_dev_struct(&G.saved_stats_dev[i], &sd, itv); - G.saved_stats_dev[i] = sd; - i++; - } else { - /* Is device in device list? */ - if (llist_find_str(G.dev_list, sd.dname)) { - /* Print current statistics */ - print_stats_dev_struct(&G.saved_stats_dev[i], &sd, itv); - G.saved_stats_dev[i] = sd; - i++; - } else - continue; + stats_dev = stats_dev_find_or_new(dev_name); + curr_data = &stats_dev->curr_data; + + rc = sscanf(buf, "%*s %*s %*s %lu %llu %llu %llu %lu %*s %llu", + &curr_data->rd_ops, + &rd_sec_or_dummy, + &curr_data->rd_sectors, + &wr_sec_or_dummy, + &curr_data->wr_ops, + &curr_data->wr_sectors); + if (rc != 6) { + curr_data->rd_sectors = rd_sec_or_dummy; + curr_data->wr_sectors = wr_sec_or_dummy; + //curr_data->rd_ops = ; + curr_data->wr_ops = (unsigned long)curr_data->rd_sectors; } + + if (!G.dev_name_list /* User didn't specify device */ + && !G.show_all + && curr_data->rd_ops == 0 + && curr_data->wr_ops == 0 + ) { + /* Don't print unused device */ + continue; + } + + /* Print current statistics */ + print_stats_dev_struct(stats_dev, itv); + stats_dev->prev_data = *curr_data; } fclose(fp); @@ -354,35 +389,6 @@ static void dev_report(cputime_t itv) do_disk_statistics(itv); } -static unsigned get_number_of_devices(void) -{ - FILE *fp; - char buf[128]; - int rv; - unsigned n = 0; - unsigned long rd_ops, wr_ops; - char dname[MAX_DEVICE_NAME]; - - fp = xfopen_for_read("/proc/diskstats"); - - while (fgets(buf, sizeof(buf), fp)) { - rv = sscanf(buf, "%*d %*d %s %lu %*u %*u %*u %lu", - dname, &rd_ops, &wr_ops); - if (rv == 2 || is_partition(dname)) - /* A partition */ - continue; - if (!rd_ops && !wr_ops) { - /* Unused device */ - if (!G.show_all) - continue; - } - n++; - } - - fclose(fp); - return n; -} - //usage:#define iostat_trivial_usage //usage: "[-c] [-d] [-t] [-z] [-k|-m] [ALL|BLOCKDEV...] [INTERVAL [COUNT]]" //usage:#define iostat_full_usage "\n\n" @@ -398,7 +404,7 @@ static unsigned get_number_of_devices(void) int iostat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int iostat_main(int argc UNUSED_PARAM, char **argv) { - int opt, dev_num; + int opt; unsigned interval; int count; stats_cpu_t stats_data[2]; @@ -427,14 +433,12 @@ int iostat_main(int argc UNUSED_PARAM, char **argv) argv += optind; /* Store device names into device list */ - dev_num = 0; while (*argv && !isdigit(*argv[0])) { if (strcmp(*argv, "ALL") != 0) { /* If not ALL, save device name */ char *dev_name = skip_dev_pfx(*argv); - if (!llist_find_str(G.dev_list, dev_name)) { - llist_add_to(&G.dev_list, dev_name); - dev_num++; + if (!llist_find_str(G.dev_name_list, dev_name)) { + llist_add_to(&G.dev_name_list, dev_name); } } else { G.show_all = 1; @@ -454,13 +458,6 @@ int iostat_main(int argc UNUSED_PARAM, char **argv) count = xatoi_positive(*argv); } - /* Allocate space for device stats */ - if (opt & OPT_d) { - G.saved_stats_dev = xzalloc(sizeof(G.saved_stats_dev[0]) * - (dev_num ? dev_num : get_number_of_devices()) - ); - } - if (opt & OPT_m) { G.unit.str = " MB"; G.unit.div = 2048; @@ -530,8 +527,8 @@ int iostat_main(int argc UNUSED_PARAM, char **argv) } if (ENABLE_FEATURE_CLEAN_UP) { - llist_free(G.dev_list, NULL); - free(G.saved_stats_dev); + llist_free(G.dev_name_list, NULL); + stats_dev_free(G.stats_dev_list); free(&G); } |