Add new writetrim rw= mode for trims preceding writes
authorDan Ehrenberg <dehrenberg@chromium.org>
Tue, 14 Apr 2015 22:58:15 +0000 (15:58 -0700)
committerJens Axboe <axboe@fb.com>
Wed, 15 Apr 2015 00:16:18 +0000 (18:16 -0600)
In this new mode, sequential trims and writes are interspersed by first
doing a trim at a particular offset, then doing writes starting from
that offset until the start of the next trim block, then another trim,
etc. This workload is designed to match the requirements of NAND flash,
if trims are implemented as erases.

Signed-off-by: Dan Ehrenberg <dehrenberg@chromium.org>
Signed-off-by: Jens Axboe <axboe@fb.com>
backend.c
io_ddir.h
io_u.c
options.c
stat.c

index 2be71496f1ddf3076e9bf36b19539168824b7b92..e8599eef0edffaf3dd1fe9cbee29ab588659f0db 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -744,6 +744,11 @@ static uint64_t do_io(struct thread_data *td)
           (td_write(td) && td->o.verify_backlog))
                total_bytes += td->o.size;
 
           (td_write(td) && td->o.verify_backlog))
                total_bytes += td->o.size;
 
+       /* In writetrim mode, each byte is trimmed and then written, so
+        * allow total_bytes to be twice as big */
+       if (td_writetrim(td))
+               total_bytes += td->total_io_size;
+
        while ((td->o.read_iolog_file && !flist_empty(&td->io_log_list)) ||
                (!flist_empty(&td->trim_list)) || !io_issue_bytes_exceeded(td) ||
                td->o.time_based) {
        while ((td->o.read_iolog_file && !flist_empty(&td->io_log_list)) ||
                (!flist_empty(&td->trim_list)) || !io_issue_bytes_exceeded(td) ||
                td->o.time_based) {
index b16a6b9bade95ce0e0822b5728021d5fae149f7d..b0d79ff7e14bf03ffccf7d8ee2b651e880ccf394 100644 (file)
--- a/io_ddir.h
+++ b/io_ddir.h
@@ -35,6 +35,7 @@ enum td_ddir {
        TD_DDIR_RANDWRITE       = TD_DDIR_WRITE | TD_DDIR_RAND,
        TD_DDIR_RANDRW          = TD_DDIR_RW | TD_DDIR_RAND,
        TD_DDIR_RANDTRIM        = TD_DDIR_TRIM | TD_DDIR_RAND,
        TD_DDIR_RANDWRITE       = TD_DDIR_WRITE | TD_DDIR_RAND,
        TD_DDIR_RANDRW          = TD_DDIR_RW | TD_DDIR_RAND,
        TD_DDIR_RANDTRIM        = TD_DDIR_TRIM | TD_DDIR_RAND,
+       TD_DDIR_WRITETRIM       = TD_DDIR_TRIM | TD_DDIR_WRITE,
 };
 
 #define td_read(td)            ((td)->o.td_ddir & TD_DDIR_READ)
 };
 
 #define td_read(td)            ((td)->o.td_ddir & TD_DDIR_READ)
@@ -43,6 +44,8 @@ enum td_ddir {
 #define td_rw(td)              (((td)->o.td_ddir & TD_DDIR_RW) == TD_DDIR_RW)
 #define td_random(td)          ((td)->o.td_ddir & TD_DDIR_RAND)
 #define file_randommap(td, f)  (!(td)->o.norandommap && fio_file_axmap((f)))
 #define td_rw(td)              (((td)->o.td_ddir & TD_DDIR_RW) == TD_DDIR_RW)
 #define td_random(td)          ((td)->o.td_ddir & TD_DDIR_RAND)
 #define file_randommap(td, f)  (!(td)->o.norandommap && fio_file_axmap((f)))
+#define td_writetrim(td)       (((td)->o.td_ddir & TD_DDIR_WRITETRIM) \
+                                       == TD_DDIR_WRITETRIM)
 
 static inline int ddir_sync(enum fio_ddir ddir)
 {
 
 static inline int ddir_sync(enum fio_ddir ddir)
 {
diff --git a/io_u.c b/io_u.c
index 16065128c324e76e3cf9326ff1824fec42baad5b..aecc2175008026ee1ccc1ed86f2e7b93d0a0842a 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -668,7 +668,17 @@ static enum fio_ddir get_rw_ddir(struct thread_data *td)
 
 static void set_rw_ddir(struct thread_data *td, struct io_u *io_u)
 {
 
 static void set_rw_ddir(struct thread_data *td, struct io_u *io_u)
 {
-       io_u->ddir = io_u->acct_ddir = get_rw_ddir(td);
+       enum fio_ddir ddir = get_rw_ddir(td);
+
+       if (td_writetrim(td)) {
+               struct fio_file *f = io_u->file;
+               if (f->last_pos[DDIR_WRITE] == f->last_pos[DDIR_TRIM])
+                       ddir = DDIR_TRIM;
+               else
+                       ddir = DDIR_WRITE;
+       }
+
+       io_u->ddir = io_u->acct_ddir = ddir;
 
        if (io_u->ddir == DDIR_WRITE && (td->io_ops->flags & FIO_BARRIER) &&
            td->o.barrier_blocks &&
 
        if (io_u->ddir == DDIR_WRITE && (td->io_ops->flags & FIO_BARRIER) &&
            td->o.barrier_blocks &&
index 95e0e0c92f4c4df6fac94b97be9c9034187c3c03..d7ce94bb75c7129cf5e4ff2bc663143ef537d63b 100644 (file)
--- a/options.c
+++ b/options.c
@@ -1416,6 +1416,10 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                            .oval = TD_DDIR_RANDRW,
                            .help = "Random read and write mix"
                          },
                            .oval = TD_DDIR_RANDRW,
                            .help = "Random read and write mix"
                          },
+                         { .ival = "writetrim",
+                           .oval = TD_DDIR_WRITETRIM,
+                           .help = "Write and trim mix, trims preceding writes"
+                         },
                },
        },
        {
                },
        },
        {
diff --git a/stat.c b/stat.c
index 85bd728d4aaa748ae97a50b7861b43f853b2338e..252b2dc96ce286666d059671f7322b1f283c87b0 100644 (file)
--- a/stat.c
+++ b/stat.c
@@ -1296,6 +1296,10 @@ void __show_run_stats(void)
                ts->latency_percentile = td->o.latency_percentile;
                ts->latency_window = td->o.latency_window;
 
                ts->latency_percentile = td->o.latency_percentile;
                ts->latency_window = td->o.latency_window;
 
+               ts->nr_block_infos = td->ts.nr_block_infos;
+               for (i = 0; i < ts->nr_block_infos; i++)
+                       ts->block_infos[i] = td->ts.block_infos[i];
+
                sum_thread_stats(ts, &td->ts, idx);
        }
 
                sum_thread_stats(ts, &td->ts, idx);
        }