[PATCH] fio: move the disk util stats out of the thread area
authorJens Axboe <axboe@suse.de>
Thu, 24 Nov 2005 19:35:05 +0000 (20:35 +0100)
committerJens Axboe <axboe@suse.de>
Thu, 24 Nov 2005 19:35:05 +0000 (20:35 +0100)
fio.c
fio.h
list.h

diff --git a/fio.c b/fio.c
index 76e3626d24abda83a43907010a1e502e7772bc50..146023f3497a3dd29d28d763fd840a3920a6a3b1 100644 (file)
--- a/fio.c
+++ b/fio.c
@@ -50,6 +50,7 @@ int groupid = 0;
 int thread_number = 0;
 char run_str[MAX_JOBS + 1];
 int shm_id = 0;
+static LIST_HEAD(disk_list);
 
 /*
  * thread life cycle
@@ -1552,7 +1553,7 @@ static char *find_block_dir(dev_t dev, char *path)
        return found;
 }
 
-static int get_io_ticks(struct thread_data *td)
+static int get_io_ticks(struct disk_util *du)
 {
        int i1, i2, i3, i4, i5, i6, i7, i8, i9;
        unsigned long long ull1, ull2;
@@ -1560,7 +1561,7 @@ static int get_io_ticks(struct thread_data *td)
        FILE *f;
        char *p;
 
-       f = fopen(td->disk_stat_path, "r");
+       f = fopen(du->path, "r");
        if (!f)
                return 0;
 
@@ -1579,36 +1580,92 @@ static int get_io_ticks(struct thread_data *td)
        return i8;
 }
 
-static void update_io_ticks(struct thread_data *td)
+static void update_io_tick_disk(struct disk_util *du)
 {
-       unsigned long ticks;
+       unsigned long ticks = get_io_ticks(du);
+       struct timeval t;
+
+       du->io_ticks += (ticks - du->last_io_ticks);
+       du->last_io_ticks = ticks;
+       gettimeofday(&t, NULL);
+       du->msec += mtime_since(&du->time, &t);
+       memcpy(&du->time, &t, sizeof(t));
+}
+
+static void update_io_ticks(void)
+{
+       struct list_head *entry;
+       struct disk_util *du;
+
+       list_for_each(entry, &disk_list) {
+               du = list_entry(entry, struct disk_util, list);
+               update_io_tick_disk(du);
+       }
+}
+
+static int disk_util_exists(dev_t dev)
+{
+       struct list_head *entry;
+       struct disk_util *du;
+
+       list_for_each(entry, &disk_list) {
+               du = list_entry(entry, struct disk_util, list);
+
+               if (du->dev == dev)
+                       return 1;
+       }
 
-       ticks = get_io_ticks(td);
-       td->io_ticks += (ticks - td->start_io_ticks);
-       td->start_io_ticks = ticks;
+       return 0;
 }
 
-static int init_disk_stats(struct thread_data *td)
+static void disk_util_add(dev_t dev, char *path)
+{
+       struct disk_util *du = malloc(sizeof(*du));
+
+       memset(du, 0, sizeof(*du));
+       INIT_LIST_HEAD(&du->list);
+       sprintf(du->path, "%s/stat", path);
+       du->name = basename(path);
+       du->dev = dev;
+
+       gettimeofday(&du->time, NULL);
+       du->last_io_ticks = get_io_ticks(du);
+
+       list_add_tail(&du->list, &disk_list);
+}
+
+static void init_disk_util(struct thread_data *td)
 {
        struct stat st;
        char foo[256], tmp[256];
        dev_t dev;
        char *p, *dir;
 
-       if (fstat(td->fd, &st) < 0) {
-               td->error = errno;
-               return 1;
-       }
+       if (!stat(td->file_name, &st)) {
+               if (S_ISBLK(st.st_mode))
+                       dev = st.st_rdev;
+               else
+                       dev = st.st_dev;
+       } else {
+               /*
+                * must be a file, open "." in that path
+                */
+               p = dirname(td->file_name);
+               if (stat(p, &st)) {
+                       perror("disk util stat");
+                       return;
+               }
 
-       if (td->filetype == FIO_TYPE_FILE)
                dev = st.st_dev;
-       else
-               dev = st.st_rdev;
+       }
+
+       if (disk_util_exists(dev))
+               return;
                
        sprintf(foo, "/sys/block");
        dir = find_block_dir(dev, foo);
        if (!dir)
-               return 0;
+               return;
 
        /*
         * if this is inside a partition dir, jump back to parent
@@ -1619,13 +1676,33 @@ static int init_disk_stats(struct thread_data *td)
                sprintf(tmp, "%s/queue", p);
                if (stat(tmp, &st)) {
                        fprintf(stderr, "unknown sysfs layout\n");
-                       return 0;
+                       return;
                }
-               sprintf(td->disk_stat_path, "%s/stat", p);
+               sprintf(foo, "%s", p);
        }
 
-       td->start_io_ticks = get_io_ticks(td);
-       return 0;
+       disk_util_add(dev, foo);
+}
+
+static void disk_util_timer_arm(void)
+{
+       struct itimerval itimer;
+
+       itimer.it_value.tv_sec = 0;
+       itimer.it_value.tv_usec = DISK_UTIL_MSEC * 1000;
+       setitimer(ITIMER_REAL, &itimer, NULL);
+}
+
+static void disk_util_timer(int sig)
+{
+       update_io_ticks();
+       disk_util_timer_arm();
+}
+
+static void setup_disk_util_timer(void)
+{
+       signal(SIGALRM, disk_util_timer);
+       disk_util_timer_arm();
 }
 
 static void clear_io_state(struct thread_data *td)
@@ -1689,9 +1766,6 @@ static void *thread_main(void *data)
        if (!td->create_serialize && setup_file(td))
                goto err;
 
-       if (init_disk_stats(td))
-               goto err;
-
        if (init_random_state(td))
                goto err;
 
@@ -1716,7 +1790,6 @@ static void *thread_main(void *data)
 
                td->runtime += mtime_since_now(&td->start);
                update_rusage_stat(td);
-               update_io_ticks(td);
 
                if (td->verify == VERIFY_NONE)
                        continue;
@@ -1833,11 +1906,6 @@ static void show_thread_status(struct thread_data *td,
        }
 
        printf("  cpu        : usr=%3.2f%%, sys=%3.2f%%, ctx=%lu\n", usr_cpu, sys_cpu, td->ctx);
-       
-       if (td->io_ticks) {
-               double disk_util = (double) 100 * td->io_ticks / (double) td->runtime;
-               printf("  disk       : util=%3.2f%%\n", disk_util);
-       }
 }
 
 static void print_thread_status(struct thread_data *td, int nr_running,
@@ -1947,6 +2015,8 @@ static void run_threads(char *argv[])
        for (i = 0; i < thread_number; i++) {
                td = &threads[i];
 
+               init_disk_util(td);
+
                if (!td->create_serialize)
                        continue;
 
@@ -2051,6 +2121,8 @@ static void run_threads(char *argv[])
                reap_threads(&nr_running, &t_rate, &m_rate);
                usleep(10000);
        }
+
+       update_io_ticks();
 }
 
 static void show_group_stats(struct group_run_stats *rs, int id)
@@ -2063,6 +2135,25 @@ static void show_group_stats(struct group_run_stats *rs, int id)
                printf("  WRITE: io=%luMiB, aggrb=%lu, minb=%lu, maxb=%lu, mint=%lumsec, maxt=%lumsec\n", rs->io_mb[1], rs->agg[1], rs->min_bw[1], rs->max_bw[1], rs->min_run[1], rs->max_run[1]);
 }
 
+static void show_disk_util(void)
+{
+       struct list_head *entry;
+       struct disk_util *du;
+       double util;
+
+       printf("\nDisk utilization:\n");
+
+       list_for_each(entry, &disk_list) {
+               du = list_entry(entry, struct disk_util, list);
+
+               util = (double) 100 * du->io_ticks / (double) du->msec;
+               if (util > 100.0)
+                       util = 100.0;
+
+               printf("  %s: %3.2f%%\n", du->name, util);
+       }
+}
+
 static void show_run_stats(void)
 {
        struct group_run_stats *runstats, *rs;
@@ -2122,6 +2213,8 @@ static void show_run_stats(void)
 
        for (i = 0; i < groupid + 1; i++)
                show_group_stats(&runstats[i], i);
+
+       show_disk_util();
 }
 
 int main(int argc, char *argv[])
@@ -2136,6 +2229,8 @@ int main(int argc, char *argv[])
                return 1;
        }
 
+       setup_disk_util_timer();
+
        run_threads(argv);
        show_run_stats();
 
diff --git a/fio.h b/fio.h
index 54a23a3598e5db1b2f43717b09e0d2d5bba93b95..221e97c5b59ceaa99cfd323d3052ab74202ff59c 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -167,12 +167,6 @@ struct thread_data {
        unsigned long ctx;
 
        struct list_head io_hist_list;
-
-       /*
-        * disk util stats
-        */
-       char disk_stat_path[256];
-       unsigned long start_io_ticks, io_ticks;
 };
 
 extern int parse_jobs_ini(char *);
@@ -224,4 +218,17 @@ enum {
 
 #define MAX_JOBS       (1024)
 
+struct disk_util {
+       struct list_head list;
+
+       char *name;
+       char path[256];
+       dev_t dev;
+       unsigned long io_ticks, last_io_ticks;
+       unsigned long msec;
+       struct timeval time;
+};
+
+#define DISK_UTIL_MSEC (250)
+
 #endif
diff --git a/list.h b/list.h
index 3a615441cf8233d01da3dc6333bf011ac87d9f9f..cedbafaae022de9267bcfd02296410a0b42c3465 100644 (file)
--- a/list.h
+++ b/list.h
@@ -26,6 +26,11 @@ struct list_head {
        struct list_head *next, *prev;
 };
 
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+       struct list_head name = LIST_HEAD_INIT(name)
+
 #define INIT_LIST_HEAD(ptr) do { \
        (ptr)->next = (ptr); (ptr)->prev = (ptr); \
 } while (0)
@@ -108,6 +113,14 @@ static inline int list_empty(const struct list_head *head)
 #define list_entry(ptr, type, member) \
        container_of(ptr, type, member)
 
+/**
+ * list_for_each       -       iterate over a list
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @head:      the head for your list.
+ */
+#define list_for_each(pos, head) \
+       for (pos = (head)->next; pos != (head); pos = pos->next)
+
 /**
  * list_for_each_safe  -       iterate over a list safe against removal of list entry
  * @pos:       the &struct list_head to use as a loop counter.