#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>
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)
if (!td->create_serialize && setup_file(td))
goto err;
+ if (init_disk_stats(td))
+ goto err;
+
if (init_random_state(td))
goto err;
ret = 0;
+ finish_disk_stats(td);
+
if (td->bw_log)
finish_log(td, td->bw_log, "bw");
if (td->lat_log)
}
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,