X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Fdiskio.c;h=d9b2f3fe4f58d37c0a5ecc43035be99a3ee17675;hb=da4f602694c3083a131b2f58a502c25a7febb76e;hp=56fa7446c15e1c9259a8eed990d1f6cb7e8466b3;hpb=dc3ed8df13fdfb6c921b7411a587af83db58e883;p=monky diff --git a/src/diskio.c b/src/diskio.c index 56fa744..d9b2f3f 100644 --- a/src/diskio.c +++ b/src/diskio.c @@ -1,4 +1,6 @@ -/* +/* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*- + * vim: ts=4 sw=4 noet ai cindent syntax=c + * * Conky, a system monitor, based on torsmo * * Any original torsmo code is licensed under the BSD license @@ -8,7 +10,7 @@ * Please see COPYING for details * * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen - * Copyright (c) 2005-2008 Brenden Matthews, Philip Kovacs, et. al. + * Copyright (c) 2005-2010 Brenden Matthews, Philip Kovacs, et. al. * (see AUTHORS) * All rights reserved. * @@ -26,201 +28,213 @@ * */ -#include "conky.h" +#include "config.h" +#include "conky.h" /* text_buffer_size */ +#include "core.h" +#include "logging.h" +#include "diskio.h" +#include "common.h" +#include "specials.h" +#include "text_object.h" +#include #include -/* The following ifdefs were adapted from gkrellm */ -#include - -#if !defined(MD_MAJOR) -#define MD_MAJOR 9 -#endif - -#if !defined(LVM_BLK_MAJOR) -#define LVM_BLK_MAJOR 58 -#endif - -#if !defined(NBD_MAJOR) -#define NBD_MAJOR 43 -#endif - -static struct diskio_stat diskio_stats_[MAX_DISKIO_STATS]; -struct diskio_stat *diskio_stats = diskio_stats_; +#include + +/* this is the root of all per disk stats, + * also containing the totals. */ +struct diskio_stat stats = { + .next = NULL, + .sample = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + .sample_read = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + .sample_write = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + .current = 0, + .current_read = 0, + .current_write = 0, + .last = UINT_MAX, + .last_read = UINT_MAX, + .last_write = UINT_MAX, +}; void clear_diskio_stats(void) { - unsigned i; - for(i = 0; i < MAX_DISKIO_STATS; i++) { - if (diskio_stats[i].dev) { - free(diskio_stats[i].dev); - diskio_stats[i].dev = 0; - } + struct diskio_stat *cur; + while (stats.next) { + cur = stats.next; + stats.next = stats.next->next; + if (cur->dev) + free(cur->dev); + free(cur); } } struct diskio_stat *prepare_diskio_stat(const char *s) { - struct diskio_stat *new = 0; - unsigned i; - FILE *fp; - int found = 0; - char device[text_buffer_size], fbuf[text_buffer_size]; - static int rep = 0; - /* lookup existing or get new */ - for (i = 0; i < MAX_DISKIO_STATS; i++) { - if (diskio_stats[i].dev) { - if (strcmp(diskio_stats[i].dev, s) == 0) { - return &diskio_stats[i]; - } - } else { - new = &diskio_stats[i]; - break; - } - } - /* new dev */ - if (!new) { - ERR("too many diskio stats"); - return 0; - } - if (new->dev) { - free(new->dev); - new->dev = 0; - } - new->dev = strndup(s, text_buffer_size); + struct stat sb; + char stat_name[text_buffer_size], device_name[text_buffer_size]; + struct diskio_stat *cur = &stats; + + if (!s) + return &stats; - /* - * check that device actually exists - */ + strncpy(device_name, s, text_buffer_size); - if (!(fp = open_file("/proc/diskstats", &rep))) { - ERR("cannot read from /proc/diskstats"); - return 0; + snprintf(stat_name, text_buffer_size, "/dev/%s", device_name); + + if (stat(stat_name, &sb)) { + NORM_ERR("diskio device '%s' does not exist", s); } - while (!feof(fp)) { - fgets(fbuf, text_buffer_size, fp); - if (sscanf(fbuf, "%*u %*u %255s %*u %*u %*u %*u %*u %*u %*u", device)) { - // check for device match - if (strncmp(new->dev, device, 256) == 0) { - found = 1; - break; - } + /* lookup existing */ + while (cur->next) { + cur = cur->next; + if (!strcmp(cur->dev, device_name)) { + return cur; } } - fclose(fp); - fp = 0; - if (!found) { - ERR("diskio device '%s' does not exist", s); - return 0; - } - new->current = 0; - new->current_read = 0; - new ->current_write = 0; - new->last = UINT_MAX; - new->last_read = UINT_MAX; - new->last_write = UINT_MAX; - return new; + + /* no existing found, make a new one */ + cur->next = calloc(1, sizeof(struct diskio_stat)); + cur = cur->next; + cur->dev = strndup(device_name, text_buffer_size); + cur->last = UINT_MAX; + cur->last_read = UINT_MAX; + cur->last_write = UINT_MAX; + + return cur; } -void update_diskio(void) +void parse_diskio_arg(struct text_object *obj, const char *arg) { - static unsigned int last = UINT_MAX; - static unsigned int last_read = UINT_MAX; - static unsigned int last_write = UINT_MAX; - FILE *fp; - static int rep = 0; + obj->data.opaque = prepare_diskio_stat(arg); +} - char buf[512], devbuf[64]; - int i; - unsigned int major, minor; - unsigned int current = 0; - unsigned int current_read = 0; - unsigned int current_write = 0; - unsigned int reads, writes = 0; - int col_count = 0; - int tot, tot_read, tot_write; - - if (!(fp = open_file("/proc/diskstats", &rep))) { - info.diskio_value = 0; +/* dir indicates the direction: + * -1: read + * 0: read + write + * 1: write + */ +static void print_diskio_dir(struct text_object *obj, int dir, char *p, int p_max_size) +{ + struct diskio_stat *diskio = obj->data.opaque; + double val; + + if (!diskio) return; - } - /* read reads and writes from all disks (minor = 0), including cd-roms - * and floppies, and sum them up */ - while (!feof(fp)) { - fgets(buf, 512, fp); - col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major, - &minor, devbuf, &reads, &writes); - /* ignore subdevices (they have only 3 matching entries in their line) - * and virtual devices (LVM, network block devices, RAM disks, Loopback) - * - * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */ - if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR - && major != RAMDISK_MAJOR && major != LOOP_MAJOR) { - current += reads + writes; - current_read += reads; - current_write += writes; - } else { - col_count = sscanf(buf, "%u %u %s %*u %u %*u %u", - &major, &minor, devbuf, &reads, &writes); - if (col_count != 5) { - continue; - } - } - for (i = 0; i < MAX_DISKIO_STATS; i++) { - if (diskio_stats[i].dev && - strncmp(devbuf, diskio_stats[i].dev, text_buffer_size) == 0) { - diskio_stats[i].current = - (reads + writes - diskio_stats[i].last) / 2; - diskio_stats[i].current_read = - (reads - diskio_stats[i].last_read) / 2; - diskio_stats[i].current_write = - (writes - diskio_stats[i].last_write) / 2; - if (reads + writes < diskio_stats[i].last) { - diskio_stats[i].current = 0; - } - if (reads < diskio_stats[i].last_read) { - diskio_stats[i].current_read = 0; - diskio_stats[i].current = diskio_stats[i].current_write; - } - if (writes < diskio_stats[i].last_write) { - diskio_stats[i].current_write = 0; - diskio_stats[i].current = diskio_stats[i].current_read; - } - diskio_stats[i].last = reads + writes; - diskio_stats[i].last_read = reads; - diskio_stats[i].last_write = writes; - } - } - } + if (dir < 0) + val = diskio->current_read; + else if (dir == 0) + val = diskio->current; + else + val = diskio->current_write; - /* since the values in /proc/diststats are absolute, we have to substract - * our last reading. The numbers stand for "sectors read", and we therefore - * have to divide by two to get KB */ - tot = ((double) (current - last) / 2); - tot_read = ((double) (current_read - last_read) / 2); - tot_write = ((double) (current_write - last_write) / 2); + /* TODO: move this correction from kB to kB/s elsewhere + * (or get rid of it??) */ + human_readable((val / update_interval) * 1024LL, p, p_max_size); +} + +void print_diskio(struct text_object *obj, char *p, int p_max_size) +{ + print_diskio_dir(obj, 0, p, p_max_size); +} + +void print_diskio_read(struct text_object *obj, char *p, int p_max_size) +{ + print_diskio_dir(obj, -1, p, p_max_size); +} - if (last_read > current_read) { - tot_read = 0; +void print_diskio_write(struct text_object *obj, char *p, int p_max_size) +{ + print_diskio_dir(obj, 1, p, p_max_size); +} + +#ifdef X11 +void parse_diskiograph_arg(struct text_object *obj, const char *arg) +{ + char *buf = 0; + buf = scan_graph(obj, arg, 0); + + obj->data.opaque = prepare_diskio_stat(dev_name(buf)); + if (buf) + free(buf); +} + +static void print_diskiograph_dir(struct text_object *obj, int dir, char *p, int p_max_size) +{ + struct diskio_stat *diskio = obj->data.opaque; + double val; + + if (!diskio) + return; + + if (!p_max_size) + return; + + if (dir < 0) + val = diskio->current_read; + else if (dir == 0) + val = diskio->current; + else + val = diskio->current_write; + + new_graph(obj, p, p_max_size, val); +} + +void print_diskiograph(struct text_object *obj, char *p, int p_max_size) +{ + print_diskiograph_dir(obj, 0, p, p_max_size); +} + +void print_diskiograph_read(struct text_object *obj, char *p, int p_max_size) +{ + print_diskiograph_dir(obj, -1, p, p_max_size); +} + +void print_diskiograph_write(struct text_object *obj, char *p, int p_max_size) +{ + print_diskiograph_dir(obj, 1, p, p_max_size); +} +#endif /* X11 */ + +void update_diskio_values(struct diskio_stat *ds, + unsigned int reads, unsigned int writes) +{ + int i; + double sum=0, sum_r=0, sum_w=0; + + if (reads < ds->last_read || writes < ds->last_write) { + /* counter overflow or reset - rebase to sane values */ + ds->last = reads+writes; + ds->last_read = reads; + ds->last_write = writes; } - if (last_write > current_write) { - tot_write = 0; + /* since the values in /proc/diskstats are absolute, we have to subtract + * our last reading. The numbers stand for "sectors read", and we therefore + * have to divide by two to get KB */ + ds->sample_read[0] = (reads - ds->last_read) / 2; + ds->sample_write[0] = (writes - ds->last_write) / 2; + ds->sample[0] = ds->sample_read[0] + ds->sample_write[0]; + + /* compute averages */ + for (i = 0; i < (signed) info.diskio_avg_samples; i++) { + sum += ds->sample[i]; + sum_r += ds->sample_read[i]; + sum_w += ds->sample_write[i]; } - - if (last > current) { - /* we hit this either if it's the very first time we run this, or - * when /proc/diskstats overflows; while 0 is not correct, it's at - * least not way off */ - tot = 0; + ds->current = sum / (double) info.diskio_avg_samples; + ds->current_read = sum_r / (double) info.diskio_avg_samples; + ds->current_write = sum_w / (double) info.diskio_avg_samples; + + /* shift sample history */ + for (i = info.diskio_avg_samples-1; i > 0; i--) { + ds->sample[i] = ds->sample[i-1]; + ds->sample_read[i] = ds->sample_read[i-1]; + ds->sample_write[i] = ds->sample_write[i-1]; } - last = current; - last_read = current_read; - last_write = current_write; - - info.diskio_value = tot; - info.diskio_read_value = tot_read; - info.diskio_write_value = tot_write; - fclose(fp); + /* save last */ + ds->last_read = reads; + ds->last_write = writes; + ds->last = ds->last_read + ds->last_write; }