int thread_number = 0;
char run_str[MAX_JOBS + 1];
int shm_id = 0;
+static LIST_HEAD(disk_list);
/*
* thread life cycle
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;
FILE *f;
char *p;
- f = fopen(td->disk_stat_path, "r");
+ f = fopen(du->path, "r");
if (!f)
return 0;
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
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)
if (!td->create_serialize && setup_file(td))
goto err;
- if (init_disk_stats(td))
- goto err;
-
if (init_random_state(td))
goto err;
td->runtime += mtime_since_now(&td->start);
update_rusage_stat(td);
- update_io_ticks(td);
if (td->verify == VERIFY_NONE)
continue;
}
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,
for (i = 0; i < thread_number; i++) {
td = &threads[i];
+ init_disk_util(td);
+
if (!td->create_serialize)
continue;
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)
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;
for (i = 0; i < groupid + 1; i++)
show_group_stats(&runstats[i], i);
+
+ show_disk_util();
}
int main(int argc, char *argv[])
return 1;
}
+ setup_disk_util_timer();
+
run_threads(argv);
show_run_stats();