[PATCH] fio: add support for mmap'ed io.
authorJens Axboe <axboe@suse.de>
Thu, 17 Nov 2005 13:58:33 +0000 (14:58 +0100)
committerJens Axboe <axboe@suse.de>
Thu, 17 Nov 2005 13:58:33 +0000 (14:58 +0100)
README.fio
fio-ini.c
fio.c
fio.h

index 1ba2b236514073ad8ad9a5b635feb43338a2d30f..ed9cae2eeb786de521ba8601afd53eda2e4875ee 100644 (file)
@@ -56,6 +56,7 @@ The <jobs> format is as follows:
        verify=x        If 'x' and writing, verify data written.
        stonewall       Wait for preceeding jobs to end before running.
        numjobs=x       Create 'x' similar entries for this job
+       mmap=x          If 'x', use mmap for data transfers
 
 
 Examples using a job file
index 97f3807a05849f5a6f2bc732575dca1631efeebf..845042c5d1a7714dbae3bf3d0ebe39e3be174697 100644 (file)
--- a/fio-ini.c
+++ b/fio-ini.c
@@ -29,6 +29,7 @@
 #define DEF_STONEWALL  (0)
 #define DEF_NUMJOBS    (1)
 #define DEF_USE_THREAD (0)
+#define DEF_USE_MMAP   (0)
 
 static int repeatable = DEF_RAND_REPEAT;
 static char *ini_file;
@@ -139,6 +140,7 @@ static struct thread_data *get_new_job(int global, struct thread_data *parent)
        td->stonewall = parent->stonewall;
        td->numjobs = parent->numjobs;
        td->use_thread = parent->use_thread;
+       td->use_mmap = parent->use_mmap;
        memcpy(&td->cpumask, &parent->cpumask, sizeof(td->cpumask));
 
        return td;
@@ -177,8 +179,12 @@ static int add_job(struct thread_data *td, const char *jobname, int prioclass,
 
        run_str[td->thread_number - 1] = 'P';
 
-       if (td->use_aio && !td->aio_depth)
-               td->aio_depth = 1;
+       if (td->use_aio) {
+               if (!td->aio_depth)
+                       td->aio_depth = 1;
+               if (td->use_mmap)
+                       td->use_mmap = 0;
+       }
 
        if (td->min_bs == -1U)
                td->min_bs = td->bs;
@@ -556,6 +562,10 @@ int parse_jobs_ini(char *file)
                                fgetpos(f, &off);
                                continue;
                        }
+                       if (!check_int(p, "mmap", &td->use_mmap)) {
+                               fgetpos(f, &off);
+                               continue;
+                       }
                        if (!check_range(p, "bsrange", &ul1, &ul2)) {
                                if (ul1 & 511)
                                        printf("bad min block size, must be a multiple of 512\n");
@@ -686,6 +696,7 @@ static int fill_def_thread(void)
        def_thread.stonewall = DEF_STONEWALL;
        def_thread.numjobs = DEF_NUMJOBS;
        def_thread.use_thread = DEF_USE_THREAD;
+       def_thread.use_mmap = DEF_USE_MMAP;
 
        return 0;
 }
diff --git a/fio.c b/fio.c
index d6e40d522a9c906d6d3f2b27d12f9313be920993..baf50f4c6fd0182886f32431d4e4411dc3c3b347 100644 (file)
--- a/fio.c
+++ b/fio.c
@@ -35,6 +35,7 @@
 #include <sys/ipc.h>
 #include <sys/shm.h>
 #include <sys/ioctl.h>
+#include <sys/mman.h>
 #include <asm/unistd.h>
 
 #include "fio.h"
@@ -638,9 +639,16 @@ static void do_sync_verify(struct thread_data *td)
        io_u = __get_io_u(td);
 
        if (!td->odirect) {
-               if (fadvise(td->fd, td->file_offset, td->io_size, POSIX_FADV_DONTNEED) < 0) {
-                       td->error = errno;
-                       goto out;
+               if (!td->use_mmap) {
+                       if (fadvise(td->fd, td->file_offset, td->io_size, POSIX_FADV_DONTNEED) < 0) {
+                               td->error = errno;
+                               goto out;
+                       }
+               } else {
+                       if (madvise(td->mmap, td->io_size, MADV_DONTNEED)) {
+                               td->error = errno;
+                               goto out;
+                       }
                }
        }
 
@@ -684,6 +692,41 @@ out:
        put_io_u(td, io_u);
 }
 
+static int __do_sync_mmap(struct thread_data *td, struct io_u *io_u)
+{
+       unsigned long long real_off = io_u->offset - td->file_offset;
+
+       if (td_read(td))
+               memcpy(io_u->buf, td->mmap + real_off, io_u->buflen);
+       else
+               memcpy(td->mmap + real_off, io_u->buf, io_u->buflen);
+
+       return io_u->buflen;
+}
+
+static int __do_sync_rw(struct thread_data *td, struct io_u *io_u)
+{
+       if (td->cur_off != io_u->offset) {
+               if (lseek(td->fd, io_u->offset, SEEK_SET) == -1) {
+                       td->error = errno;
+                       return 1;
+               }
+       }
+
+       if (td_read(td))
+               return read(td->fd, io_u->buf, io_u->buflen);
+       else
+               return write(td->fd, io_u->buf, io_u->buflen);
+}
+
+static void sync_td(struct thread_data *td)
+{
+       if (!td->use_mmap)
+               fsync(td->fd);
+       else
+               msync(td->mmap, td->file_size, MS_SYNC);
+}
+
 static void do_sync_io(struct thread_data *td)
 {
        unsigned long msec, usec;
@@ -700,17 +743,10 @@ static void do_sync_io(struct thread_data *td)
                if (!io_u)
                        break;
 
-               if (td->cur_off != io_u->offset) {
-                       if (lseek(td->fd, io_u->offset, SEEK_SET) == -1) {
-                               td->error = errno;
-                               break;
-                       }
-               }
-
-               if (td_read(td))
-                       ret = read(td->fd, io_u->buf, io_u->buflen);
+               if (!td->use_mmap)
+                       ret = __do_sync_rw(td, io_u);
                else
-                       ret = write(td->fd, io_u->buf, io_u->buflen);
+                       ret = __do_sync_mmap(td, io_u);
 
                if (ret < (int) io_u->buflen) {
                        if (ret == -1)
@@ -752,14 +788,14 @@ static void do_sync_io(struct thread_data *td)
 
                if (should_fsync(td) && td->fsync_blocks &&
                    (td->io_blocks % td->fsync_blocks) == 0)
-                       fsync(td->fd);
+                       sync_td(td);
        }
 
        if (io_u)
                put_io_u(td, io_u);
 
        if (should_fsync(td))
-               fsync(td->fd);
+               sync_td(td);
 }
 
 static int io_u_getevents(struct thread_data *td, int min, int max,
@@ -1250,6 +1286,72 @@ static int get_file_size(struct thread_data *td)
        return 0;
 }
 
+static int setup_file_mmap(struct thread_data *td)
+{
+       int flags;
+
+       if (td_read(td))
+               flags = PROT_READ;
+       else {
+               flags = PROT_WRITE;
+
+               if (td->verify)
+                       flags |= PROT_READ;
+       }
+
+       td->mmap = mmap(NULL, td->file_size, flags, MAP_SHARED, td->fd, td->file_offset);
+       if (td->mmap == MAP_FAILED) {
+               td->mmap = NULL;
+               td->error = errno;
+               return 1;
+       }
+
+       if (td->invalidate_cache) {
+               if (madvise(td->mmap, td->file_size, MADV_DONTNEED) < 0) {
+                       td->error = errno;
+                       return 1;
+               }
+       }
+
+       if (td->sequential) {
+               if (madvise(td->mmap, td->file_size, MADV_SEQUENTIAL) < 0) {
+                       td->error = errno;
+                       return 1;
+               }
+       } else {
+               if (madvise(td->mmap, td->file_size, MADV_RANDOM) < 0) {
+                       td->error = errno;
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int setup_file_plain(struct thread_data *td)
+{
+       if (td->invalidate_cache) {
+               if (fadvise(td->fd, td->file_offset, td->file_size, POSIX_FADV_DONTNEED) < 0) {
+                       td->error = errno;
+                       return 1;
+               }
+       }
+
+       if (td->sequential) {
+               if (fadvise(td->fd, td->file_offset, td->file_size, POSIX_FADV_SEQUENTIAL) < 0) {
+                       td->error = errno;
+                       return 1;
+               }
+       } else {
+               if (fadvise(td->fd, td->file_offset, td->file_size, POSIX_FADV_RANDOM) < 0) {
+                       td->error = errno;
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
 static int setup_file(struct thread_data *td)
 {
        int flags = 0;
@@ -1273,10 +1375,8 @@ static int setup_file(struct thread_data *td)
                        flags |= O_TRUNC;
                if (td->sync_io)
                        flags |= O_SYNC;
-               if (td->verify)
-                       flags |= O_RDWR;
-               else
-                       flags |= O_WRONLY;
+
+               flags |= O_RDWR;
 
                td->fd = open(td->file_name, flags | O_CREAT, 0600);
        }
@@ -1294,14 +1394,10 @@ static int setup_file(struct thread_data *td)
                return 1;
        }
 
-       if (td->invalidate_cache) {
-               if (fadvise(td->fd, td->file_offset, td->file_size, POSIX_FADV_DONTNEED) < 0) {
-                       td->error = errno;
-                       return 1;
-               }
-       }
-
-       return 0;
+       if (!td->use_mmap)
+               return setup_file_plain(td);
+       else
+               return setup_file_mmap(td);
 }
 
 static void clear_io_state(struct thread_data *td)
@@ -1419,6 +1515,8 @@ err:
                close(td->fd);
                td->fd = -1;
        }
+       if (td->mmap)
+               munmap(td->mmap, td->file_size);
        if (td->use_aio)
                cleanup_aio(td);
        cleanup_io_u(td);
diff --git a/fio.h b/fio.h
index 81969d3527e072e6586caaf1372196d02c92e988..6dfdc47324ea09f78effa375f17064c7f0e9b641 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -61,6 +61,7 @@ struct thread_data {
        int filetype;
        int error;
        int fd;
+       void *mmap;
        pid_t pid;
        char *orig_buffer;
        volatile int terminate;
@@ -93,6 +94,7 @@ struct thread_data {
        unsigned int stonewall;
        unsigned int numjobs;
        unsigned int use_thread;
+       unsigned int use_mmap;
        cpu_set_t cpumask;
 
        struct drand48_data bsrange_state;