From: Jens Axboe Date: Thu, 24 Nov 2005 19:35:05 +0000 (+0100) Subject: [PATCH] fio: move the disk util stats out of the thread area X-Git-Url: https://git.kernel.dk/?a=commitdiff_plain;h=6f75d67ce358155dd6cfc8085aba0b67b82df4e2;p=disktools.git [PATCH] fio: move the disk util stats out of the thread area --- diff --git a/fio.c b/fio.c index 76e3626..146023f 100644 --- 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 54a23a3..221e97c 100644 --- 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 3a61544..cedbafa 100644 --- 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.