io_u: speed up small_content_scramble()
authorJens Axboe <axboe@kernel.dk>
Thu, 30 Nov 2017 16:18:37 +0000 (09:18 -0700)
committerJens Axboe <axboe@kernel.dk>
Thu, 30 Nov 2017 16:18:37 +0000 (09:18 -0700)
This is a hot path for write workloads, since we don't want to send the
same buffers to the device again and again. The idea is to defeat basic
dedupe/compression, but slightly modifying the buffer for each write.
small_content_scramble() does this by filling in the io_u offset into a
random spot in each 512b chunk of an io buffer, and filling in the start
time (sec,nsec) at the end of each 512b chunk.

With this change, we still do those two things, but we generate a random
cacheline within each 512b chunk, and fill the offset at the beginning
of the cacheline, and the time at the end of it.  This means that
instead of potentially dirtying 2 cachelines for each 512b chunk in an
IO buffer, we dirty just 1.

The results should still be random enough that small_content_scramble()
fullfils the promise to defeat basic dedupe and compression, but it is
lighter to run.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
io_u.c

diff --git a/io_u.c b/io_u.c
index 086384a..6bb9eab 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -1669,32 +1669,40 @@ static bool check_get_verify(struct thread_data *td, struct io_u *io_u)
  */
 static void small_content_scramble(struct io_u *io_u)
 {
-       unsigned int i, nr_blocks = io_u->buflen / 512;
+       unsigned int i, nr_blocks = io_u->buflen >> 9;
        unsigned int offset;
-       uint64_t boffset;
-       char *p, *end;
+       uint64_t boffset, *iptr;
+       char *p;
 
        if (!nr_blocks)
                return;
 
        p = io_u->xfer_buf;
        boffset = io_u->offset;
-       io_u->buf_filled_len = 0;
+
+       if (io_u->buf_filled_len)
+               io_u->buf_filled_len = 0;
+
+       /*
+        * Generate random index between 0..7. We do chunks of 512b, if
+        * we assume a cacheline is 64 bytes, then we have 8 of those.
+        * Scramble content within the blocks in the same cacheline to
+        * speed things up.
+        */
+       offset = (io_u->start_time.tv_nsec ^ boffset) & 7;
 
        for (i = 0; i < nr_blocks; i++) {
                /*
-                * Fill the byte offset into a "random" start offset of
-                * the first half of the buffer.
+                * Fill offset into start of cacheline, time into end
+                * of cacheline
                 */
-               offset = (io_u->start_time.tv_nsec ^ boffset) & 255;
-               offset &= ~(sizeof(boffset) - 1);
-               memcpy(p + offset, &boffset, sizeof(boffset));
+               iptr = (void *) p + (offset << 6);
+               *iptr = boffset;
+
+               iptr = (void *) p + 64 - 2 * sizeof(uint64_t);
+               iptr[0] = io_u->start_time.tv_sec;
+               iptr[1] = io_u->start_time.tv_nsec;
 
-               /*
-                * Fill the start time into the end of the buffer
-                */
-               end = p + 512 - sizeof(io_u->start_time);
-               memcpy(end, &io_u->start_time, sizeof(io_u->start_time));
                p += 512;
                boffset += 512;
        }