Add option for specifically setting buffer contents
authorJens Axboe <axboe@kernel.dk>
Tue, 14 Jan 2014 22:35:58 +0000 (15:35 -0700)
committerJens Axboe <axboe@kernel.dk>
Tue, 14 Jan 2014 22:35:58 +0000 (15:35 -0700)
Fio can use zeroes, slightly scrambled data, full random data,
or specifically compressible data. With this option, the user
can now fully control the pattern written, similarly to how
verify_pattern works for verify=meta.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
HOWTO
backend.c
fio.1
io_u.c
options.c
thread_options.h
verify.c
verify.h

diff --git a/HOWTO b/HOWTO
index 2183be10205345f85c9eb97305b054f77d60d928..c3672d85d361638e532434a758b05f31a429a424 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -547,6 +547,11 @@ buffer_compress_chunk=int  See buffer_compress_percentage. This
                alternate random and zeroed data throughout the IO
                buffer.
 
                alternate random and zeroed data throughout the IO
                buffer.
 
+buffer_pattern=str     If set, fio will fill the io buffers with this pattern.
+               If not set, the contents of io buffers is defined by the other
+               options related to buffer contents. The setting can be any
+               pattern of bytes, and can be prefixed with 0x for hex values.
+
 nrfiles=int    Number of files to use for this job. Defaults to 1.
 
 openfiles=int  Number of files to keep open at the same time. Defaults to
 nrfiles=int    Number of files to use for this job. Defaults to 1.
 
 openfiles=int  Number of files to keep open at the same time. Defaults to
index 101024d10c24b4ec34c90693cd0244a4f2feb7a6..c9a20a3b36a188e01df2b5865f8e68140b28028f 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -989,7 +989,7 @@ static int init_io_u(struct thread_data *td)
                                 * Fill the buffer with the pattern if we are
                                 * going to be doing writes.
                                 */
                                 * Fill the buffer with the pattern if we are
                                 * going to be doing writes.
                                 */
-                               fill_pattern(td, io_u->buf, max_bs, io_u, 0, 0);
+                               fill_verify_pattern(td, io_u->buf, max_bs, io_u, 0, 0);
                        }
                }
 
                        }
                }
 
diff --git a/fio.1 b/fio.1
index 6c3dd21bab61bea09d839ae984c00a540b2255eb..82d05b77b7319cc87216b1a84a23b34f067fa618 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -426,6 +426,12 @@ provide \fBbuffer_compress_percentage\fR of blocksize random data, followed by
 the remaining zeroed. With this set to some chunk size smaller than the block
 size, fio can alternate random and zeroed data throughout the IO buffer.
 .TP
 the remaining zeroed. With this set to some chunk size smaller than the block
 size, fio can alternate random and zeroed data throughout the IO buffer.
 .TP
+.BI buffer_pattern \fR=\fPstr
+If set, fio will fill the io buffers with this pattern. If not set, the contents
+of io buffers is defined by the other options related to buffer contents. The
+setting can be any pattern of bytes, and can be prefixed with 0x for hex
+values.
+.TP
 .BI nrfiles \fR=\fPint
 Number of files to use for this job.  Default: 1.
 .TP
 .BI nrfiles \fR=\fPint
 Number of files to use for this job.  Default: 1.
 .TP
diff --git a/io_u.c b/io_u.c
index ea6c251859969b3e86775ea2ba4260de73d00194..518d884f867565cd70b398281797712d0be84755 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -1770,7 +1770,9 @@ void io_u_queued(struct thread_data *td, struct io_u *io_u)
 void fill_io_buffer(struct thread_data *td, void *buf, unsigned int min_write,
                    unsigned int max_bs)
 {
 void fill_io_buffer(struct thread_data *td, void *buf, unsigned int min_write,
                    unsigned int max_bs)
 {
-       if (!td->o.zero_buffers) {
+       if (td->o.buffer_pattern_bytes)
+               fill_buffer_pattern(td, buf, max_bs);
+       else if (!td->o.zero_buffers) {
                unsigned int perc = td->o.compress_percentage;
 
                if (perc) {
                unsigned int perc = td->o.compress_percentage;
 
                if (perc) {
index 16b6636991d65290bd10f4befbf06c00904dc580..b1b6c8e969381cc44cdde496fbcb4ad174c84a84 100644 (file)
--- a/options.c
+++ b/options.c
@@ -834,11 +834,12 @@ static int str_opendir_cb(void *data, const char fio_unused *str)
        return add_dir_files(td, td->o.opendir);
 }
 
        return add_dir_files(td, td->o.opendir);
 }
 
-static int str_verify_pattern_cb(void *data, const char *input)
+static int pattern_cb(char *pattern, unsigned int max_size,
+                     const char *input, unsigned int *pattern_bytes)
 {
 {
-       struct thread_data *td = data;
        long off;
        long off;
-       int i = 0, j = 0, len, k, base = 10, pattern_length;
+       int i = 0, j = 0, len, k, base = 10;
+       uint32_t pattern_length;
        char *loc1, *loc2;
 
        loc1 = strstr(input, "0x");
        char *loc1, *loc2;
 
        loc1 = strstr(input, "0x");
@@ -848,7 +849,7 @@ static int str_verify_pattern_cb(void *data, const char *input)
        off = strtol(input, NULL, base);
        if (off != LONG_MAX || errno != ERANGE) {
                while (off) {
        off = strtol(input, NULL, base);
        if (off != LONG_MAX || errno != ERANGE) {
                while (off) {
-                       td->o.verify_pattern[i] = off & 0xff;
+                       pattern[i] = off & 0xff;
                        off >>= 8;
                        i++;
                }
                        off >>= 8;
                        i++;
                }
@@ -862,13 +863,13 @@ static int str_verify_pattern_cb(void *data, const char *input)
                                j = loc2 - input + 2;
                } else
                        return 1;
                                j = loc2 - input + 2;
                } else
                        return 1;
-               if (len - j < MAX_PATTERN_SIZE * 2) {
+               if (len - j < max_size * 2) {
                        while (k >= j) {
                                off = converthexchartoint(input[k--]);
                                if (k >= j)
                                        off += (converthexchartoint(input[k--])
                                                * 16);
                        while (k >= j) {
                                off = converthexchartoint(input[k--]);
                                if (k >= j)
                                        off += (converthexchartoint(input[k--])
                                                * 16);
-                               td->o.verify_pattern[i++] = (char) off;
+                               pattern[i++] = (char) off;
                        }
                }
        }
                        }
                }
        }
@@ -878,19 +879,19 @@ static int str_verify_pattern_cb(void *data, const char *input)
         * the number of memcpy's we have to do when verifying the IO.
         */
        pattern_length = i;
         * the number of memcpy's we have to do when verifying the IO.
         */
        pattern_length = i;
-       while (i > 1 && i * 2 <= MAX_PATTERN_SIZE) {
-               memcpy(&td->o.verify_pattern[i], &td->o.verify_pattern[0], i);
+       while (i > 1 && i * 2 <= max_size) {
+               memcpy(&pattern[i], &pattern[0], i);
                i *= 2;
        }
 
        /*
         * Fill remainder, if the pattern multiple ends up not being
                i *= 2;
        }
 
        /*
         * Fill remainder, if the pattern multiple ends up not being
-        * MAX_PATTERN_SIZE.
+        * max_size.
         */
         */
-       while (i > 1 && i < MAX_PATTERN_SIZE) {
-               unsigned int b = min(pattern_length, MAX_PATTERN_SIZE - i);
+       while (i > 1 && i < max_size) {
+               unsigned int b = min(pattern_length, max_size - i);
 
 
-               memcpy(&td->o.verify_pattern[i], &td->o.verify_pattern[0], b);
+               memcpy(&pattern[i], &pattern[0], b);
                i += b;
        }
 
                i += b;
        }
 
@@ -899,19 +900,45 @@ static int str_verify_pattern_cb(void *data, const char *input)
                 * The code in verify_io_u_pattern assumes a single byte pattern
                 * fills the whole verify pattern buffer.
                 */
                 * The code in verify_io_u_pattern assumes a single byte pattern
                 * fills the whole verify pattern buffer.
                 */
-               memset(td->o.verify_pattern, td->o.verify_pattern[0],
-                      MAX_PATTERN_SIZE);
+               memset(pattern, pattern[0], max_size);
+       }
+
+       *pattern_bytes = i;
+       return 0;
+}
+
+static int str_buffer_pattern_cb(void *data, const char *input)
+{
+       struct thread_data *td = data;
+       int ret;
+
+       ret = pattern_cb(td->o.buffer_pattern, MAX_PATTERN_SIZE, input,
+                               &td->o.buffer_pattern_bytes);
+
+       if (!ret) {
+               td->o.refill_buffers = 0;
+               td->o.scramble_buffers = 0;
+               td->o.zero_buffers = 0;
        }
 
        }
 
-       td->o.verify_pattern_bytes = i;
+       return ret;
+}
+
+static int str_verify_pattern_cb(void *data, const char *input)
+{
+       struct thread_data *td = data;
+       int ret;
+
+       ret = pattern_cb(td->o.verify_pattern, MAX_PATTERN_SIZE, input,
+                               &td->o.verify_pattern_bytes);
 
        /*
         * VERIFY_META could already be set
         */
 
        /*
         * VERIFY_META could already be set
         */
-       if (td->o.verify == VERIFY_NONE)
+       if (!ret && td->o.verify == VERIFY_NONE)
                td->o.verify = VERIFY_PATTERN;
 
                td->o.verify = VERIFY_PATTERN;
 
-       return 0;
+       return ret;
 }
 
 static int str_gtod_reduce_cb(void *data, int *il)
 }
 
 static int str_gtod_reduce_cb(void *data, int *il)
@@ -2946,6 +2973,15 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_IO_BUF,
        },
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_IO_BUF,
        },
+       {
+               .name   = "buffer_pattern",
+               .lname  = "Buffer pattern",
+               .type   = FIO_OPT_STR,
+               .cb     = str_buffer_pattern_cb,
+               .help   = "Fill pattern for IO buffers",
+               .category = FIO_OPT_C_IO,
+               .group  = FIO_OPT_G_IO_BUF,
+       },
        {
                .name   = "buffer_compress_percentage",
                .lname  = "Buffer compression percentage",
        {
                .name   = "buffer_compress_percentage",
                .lname  = "Buffer compression percentage",
index e2c6e88552399a4b2ac88ca164147431822901ef..f40a9927e58e982098695ebb946608e38e0e3407 100644 (file)
@@ -170,6 +170,8 @@ struct thread_options {
        unsigned int zero_buffers;
        unsigned int refill_buffers;
        unsigned int scramble_buffers;
        unsigned int zero_buffers;
        unsigned int refill_buffers;
        unsigned int scramble_buffers;
+       char buffer_pattern[MAX_PATTERN_SIZE];
+       unsigned int buffer_pattern_bytes;
        unsigned int compress_percentage;
        unsigned int compress_chunk;
        unsigned int time_based;
        unsigned int compress_percentage;
        unsigned int compress_chunk;
        unsigned int time_based;
@@ -381,6 +383,8 @@ struct thread_options_pack {
        uint32_t zero_buffers;
        uint32_t refill_buffers;
        uint32_t scramble_buffers;
        uint32_t zero_buffers;
        uint32_t refill_buffers;
        uint32_t scramble_buffers;
+       uint8_t buffer_pattern[MAX_PATTERN_SIZE];
+       uint32_t buffer_pattern_bytes;
        unsigned int compress_percentage;
        unsigned int compress_chunk;
        uint32_t time_based;
        unsigned int compress_percentage;
        unsigned int compress_chunk;
        uint32_t time_based;
index 0d38c0e92e77444d49e3d1906a37c210325c9bb6..721aeb46635701b3f0f1cca8fc2db18d8c2cc4eb 100644 (file)
--- a/verify.c
+++ b/verify.c
@@ -28,51 +28,65 @@ static void populate_hdr(struct thread_data *td, struct io_u *io_u,
                         struct verify_header *hdr, unsigned int header_num,
                         unsigned int header_len);
 
                         struct verify_header *hdr, unsigned int header_num,
                         unsigned int header_len);
 
-void fill_pattern(struct thread_data *td, void *p, unsigned int len, struct io_u *io_u, unsigned long seed, int use_seed)
+static void fill_pattern(struct thread_data *td, void *p, unsigned int len,
+                        char *pattern, unsigned int pattern_bytes)
 {
 {
-       switch (td->o.verify_pattern_bytes) {
+       switch (pattern_bytes) {
        case 0:
        case 0:
-               dprint(FD_VERIFY, "fill random bytes len=%u\n", len);
-               if (use_seed)
-                       __fill_random_buf(p, len, seed);
-               else
-                       io_u->rand_seed = fill_random_buf(&td->buf_state, p, len);
+               assert(0);
                break;
        case 1:
                break;
        case 1:
-               if (io_u->buf_filled_len >= len) {
-                       dprint(FD_VERIFY, "using already filled verify pattern b=0 len=%u\n", len);
-                       return;
-               }
                dprint(FD_VERIFY, "fill verify pattern b=0 len=%u\n", len);
                dprint(FD_VERIFY, "fill verify pattern b=0 len=%u\n", len);
-               memset(p, td->o.verify_pattern[0], len);
-               io_u->buf_filled_len = len;
+               memset(p, pattern[0], len);
                break;
        default: {
                unsigned int i = 0, size = 0;
                unsigned char *b = p;
 
                break;
        default: {
                unsigned int i = 0, size = 0;
                unsigned char *b = p;
 
-               if (io_u->buf_filled_len >= len) {
-                       dprint(FD_VERIFY, "using already filled verify pattern b=%d len=%u\n",
-                                       td->o.verify_pattern_bytes, len);
-                       return;
-               }
-
                dprint(FD_VERIFY, "fill verify pattern b=%d len=%u\n",
                dprint(FD_VERIFY, "fill verify pattern b=%d len=%u\n",
-                                       td->o.verify_pattern_bytes, len);
+                                       pattern_bytes, len);
 
                while (i < len) {
 
                while (i < len) {
-                       size = td->o.verify_pattern_bytes;
+                       size = pattern_bytes;
                        if (size > (len - i))
                                size = len - i;
                        if (size > (len - i))
                                size = len - i;
-                       memcpy(b+i, td->o.verify_pattern, size);
+                       memcpy(b+i, pattern, size);
                        i += size;
                }
                        i += size;
                }
-               io_u->buf_filled_len = len;
                break;
                }
        }
 }
 
                break;
                }
        }
 }
 
+void fill_buffer_pattern(struct thread_data *td, void *p, unsigned int len)
+{
+       fill_pattern(td, p, len, td->o.buffer_pattern, td->o.buffer_pattern_bytes);
+}
+
+void fill_verify_pattern(struct thread_data *td, void *p, unsigned int len,
+                        struct io_u *io_u, unsigned long seed, int use_seed)
+{
+       if (!td->o.verify_pattern_bytes) {
+               dprint(FD_VERIFY, "fill random bytes len=%u\n", len);
+
+               if (use_seed)
+                       __fill_random_buf(p, len, seed);
+               else
+                       io_u->rand_seed = fill_random_buf(&td->buf_state, p, len);
+               return;
+       }
+       
+       if (io_u->buf_filled_len >= len) {
+               dprint(FD_VERIFY, "using already filled verify pattern b=%d len=%u\n",
+                       td->o.verify_pattern_bytes, len);
+               return;
+       }
+
+       fill_pattern(td, p, len, td->o.verify_pattern, td->o.verify_pattern_bytes);
+
+       io_u->buf_filled_len = len;
+}
+
 static unsigned int get_hdr_inc(struct thread_data *td, struct io_u *io_u)
 {
        unsigned int hdr_inc;
 static unsigned int get_hdr_inc(struct thread_data *td, struct io_u *io_u)
 {
        unsigned int hdr_inc;
@@ -91,7 +105,7 @@ static void fill_pattern_headers(struct thread_data *td, struct io_u *io_u,
        struct verify_header *hdr;
        void *p = io_u->buf;
 
        struct verify_header *hdr;
        void *p = io_u->buf;
 
-       fill_pattern(td, p, io_u->buflen, io_u, seed, use_seed);
+       fill_verify_pattern(td, p, io_u->buflen, io_u, seed, use_seed);
 
        hdr_inc = get_hdr_inc(td, io_u);
        header_num = 0;
 
        hdr_inc = get_hdr_inc(td, io_u);
        header_num = 0;
index 6a81e9b012bc6fa0632a90ea0dc2e9acfe26755f..05d7b81b804460e7c49738acb42f83d4dad8bd6e 100644 (file)
--- a/verify.h
+++ b/verify.h
@@ -74,7 +74,8 @@ extern void populate_verify_io_u(struct thread_data *, struct io_u *);
 extern int __must_check get_next_verify(struct thread_data *td, struct io_u *);
 extern int __must_check verify_io_u(struct thread_data *, struct io_u *);
 extern int verify_io_u_async(struct thread_data *, struct io_u *);
 extern int __must_check get_next_verify(struct thread_data *td, struct io_u *);
 extern int __must_check verify_io_u(struct thread_data *, struct io_u *);
 extern int verify_io_u_async(struct thread_data *, struct io_u *);
-extern void fill_pattern(struct thread_data *td, void *p, unsigned int len, struct io_u *io_u, unsigned long seed, int use_seed);
+extern void fill_verify_pattern(struct thread_data *td, void *p, unsigned int len, struct io_u *io_u, unsigned long seed, int use_seed);
+extern void fill_buffer_pattern(struct thread_data *td, void *p, unsigned int len);
 extern void fio_verify_init(struct thread_data *td);
 
 /*
 extern void fio_verify_init(struct thread_data *td);
 
 /*