[PATCH] fio: add some basic disk utilization stats
authorJens Axboe <axboe@suse.de>
Thu, 24 Nov 2005 15:06:29 +0000 (16:06 +0100)
committerJens Axboe <axboe@suse.de>
Thu, 24 Nov 2005 15:06:29 +0000 (16:06 +0100)
fio.c
fio.h

diff --git a/fio.c b/fio.c
index 8cec4c52a040e94cae57526342e49e0a80b07fed..a789bd86881f22c8aa0d76134b68113d7de830bd 100644 (file)
--- a/fio.c
+++ b/fio.c
@@ -29,6 +29,8 @@
 #include <math.h>
 #include <assert.h>
 #include <pthread.h>
+#include <dirent.h>
+#include <libgen.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
@@ -1474,6 +1476,157 @@ static int setup_file(struct thread_data *td)
                return setup_file_mmap(td);
 }
 
+static int check_dev_match(dev_t dev, char *path)
+{
+       int major, minor;
+       char line[256], *p;
+       FILE *f;
+
+       f = fopen(path, "r");
+       if (!f) {
+               perror("open path");
+               return 1;
+       }
+
+       p = fgets(line, sizeof(line), f);
+       if (!p) {
+               fclose(f);
+               return 1;
+       }
+
+       if (sscanf(p, "%u:%u", &major, &minor) != 2) {
+               fclose(f);
+               return 1;
+       }
+
+       if (((major << 8) | minor) == dev) {
+               fclose(f);
+               return 0;
+       }
+
+       fclose(f);
+       return 1;
+}
+
+static char *find_block_dir(dev_t dev, char *path)
+{
+       struct dirent *dir;
+       char *found = NULL;
+       struct stat st;
+       DIR *D;
+
+       D = opendir(path);
+       if (!D)
+               return NULL;
+
+       while ((dir = readdir(D)) != NULL) {
+               char full_path[256];
+
+               if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))
+                       continue;
+               if (!strcmp(dir->d_name, "device"))
+                       continue;
+
+               sprintf(full_path, "%s/%s", path, dir->d_name);
+
+               if (!strcmp(dir->d_name, "dev")) {
+                       if (!check_dev_match(dev, full_path)) {
+                               found = path;
+                               break;
+                       }
+               }
+
+               if (stat(full_path, &st) == -1) {
+                       perror("stat");
+                       break;
+               }
+
+               if (!S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))
+                       continue;
+
+               if ((found = find_block_dir(dev, full_path)) != NULL)
+                       break;
+       }
+
+       closedir(D);
+       return found;
+}
+
+static int get_io_ticks(struct thread_data *td)
+{
+       int i1, i2, i3, i4, i5, i6, i7, i8, i9;
+       unsigned long long ull1, ull2;
+       char line[256];
+       FILE *f;
+       char *p;
+
+       f = fopen(td->disk_stat_path, "r");
+       if (!f)
+               return 0;
+
+       p = fgets(line, sizeof(line), f);
+       if (!p) {
+               fclose(f);
+               return 0;
+       }
+
+       if (sscanf(p, "%8u %8u %8llu %8u %8u %8u %8llu %8u %8u %8u %8u", &i1, &i2, &ull1, &i3, &i4, &i5, &ull2, &i6, &i7, &i8, &i9) != 11) {
+               fclose(f);
+               return 0;
+       }
+
+       fclose(f);
+       return i8;
+}
+
+static void finish_disk_stats(struct thread_data *td)
+{
+       unsigned long ticks;
+
+       ticks = get_io_ticks(td);
+       td->io_ticks = ticks - td->io_ticks;
+}
+
+static int init_disk_stats(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 (td->filetype == FIO_TYPE_FILE)
+               dev = st.st_dev;
+       else
+               dev = st.st_rdev;
+               
+       sprintf(foo, "/sys/block");
+       dir = find_block_dir(dev, foo);
+       if (!dir)
+               return 0;
+
+       /*
+        * if this is inside a partition dir, jump back to parent
+        */
+       sprintf(tmp, "%s/queue", dir);
+       if (stat(tmp, &st)) {
+               p = dirname(dir);
+               sprintf(tmp, "%s/queue", p);
+               if (stat(tmp, &st)) {
+                       fprintf(stderr, "unknown sysfs layout\n");
+                       return 0;
+               }
+               sprintf(td->disk_stat_path, "%s/stat", p);
+       }
+
+       td->io_ticks = get_io_ticks(td);
+       return 0;
+}
+
 static void clear_io_state(struct thread_data *td)
 {
        if (!td->use_aio)
@@ -1535,6 +1688,9 @@ 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;
 
@@ -1576,6 +1732,8 @@ static void *thread_main(void *data)
 
        ret = 0;
 
+       finish_disk_stats(td);
+
        if (td->bw_log)
                finish_log(td, td->bw_log, "bw");
        if (td->lat_log)
@@ -1675,6 +1833,11 @@ 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,
diff --git a/fio.h b/fio.h
index 96df3bf1149cdd5f2b2284bbb7787ab4b2b07e40..1ef9d3321417e00f3813881f66f7eda4b8f2af0f 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -167,6 +167,12 @@ struct thread_data {
        unsigned long ctx;
 
        struct list_head io_hist_list;
+
+       /*
+        * disk util stats
+        */
+       char disk_stat_path[256];
+       unsigned long io_ticks;
 };
 
 extern int parse_jobs_ini(char *);