Add buffer_compress_percentage

The option is pending testing, so not documented yet.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
diff --git a/backend.c b/backend.c
index 5279104..f3f1030 100644
--- a/backend.c
+++ b/backend.c
@@ -762,12 +762,13 @@
 static int init_io_u(struct thread_data *td)
 {
 	struct io_u *io_u;
-	unsigned int max_bs;
+	unsigned int max_bs, min_write;
 	int cl_align, i, max_units;
 	char *p;
 
 	max_units = td->o.iodepth;
 	max_bs = max(td->o.max_bs[DDIR_READ], td->o.max_bs[DDIR_WRITE]);
+	min_write = td->o.min_bs[DDIR_WRITE];
 	td->orig_buffer_size = (unsigned long long) max_bs
 					* (unsigned long long) max_units;
 
@@ -816,7 +817,7 @@
 			dprint(FD_MEM, "io_u %p, mem %p\n", io_u, io_u->buf);
 
 			if (td_write(td))
-				io_u_fill_buffer(td, io_u, max_bs);
+				io_u_fill_buffer(td, io_u, min_write, max_bs);
 			if (td_write(td) && td->o.verify_pattern_bytes) {
 				/*
 				 * Fill the buffer with the pattern if we are
diff --git a/fio.h b/fio.h
index 5c912d0..7443bc0 100644
--- a/fio.h
+++ b/fio.h
@@ -194,6 +194,7 @@
 	unsigned int zero_buffers;
 	unsigned int refill_buffers;
 	unsigned int scramble_buffers;
+	unsigned int compress_percentage;
 	unsigned int time_based;
 	unsigned int disable_lat;
 	unsigned int disable_clat;
diff --git a/io_u.c b/io_u.c
index 161c2cb..2deb5c7 100644
--- a/io_u.c
+++ b/io_u.c
@@ -1227,9 +1227,10 @@
 		if (io_u->ddir == DDIR_WRITE) {
 			if (td->o.verify != VERIFY_NONE)
 				populate_verify_io_u(td, io_u);
-			else if (td->o.refill_buffers)
-				io_u_fill_buffer(td, io_u, io_u->xfer_buflen);
-			else if (td->o.scramble_buffers)
+			else if (td->o.refill_buffers) {
+				io_u_fill_buffer(td, io_u,
+					io_u->xfer_buflen, io_u->xfer_buflen);
+			} else if (td->o.scramble_buffers)
 				do_scramble = 1;
 		} else if (io_u->ddir == DDIR_READ) {
 			/*
@@ -1532,12 +1533,18 @@
  * "randomly" fill the buffer contents
  */
 void io_u_fill_buffer(struct thread_data *td, struct io_u *io_u,
-		      unsigned int max_bs)
+		      unsigned int min_write, unsigned int max_bs)
 {
 	io_u->buf_filled_len = 0;
 
-	if (!td->o.zero_buffers)
-		fill_random_buf(&td->buf_state, io_u->buf, max_bs);
-	else
+	if (!td->o.zero_buffers) {
+		unsigned int perc = td->o.compress_percentage;
+
+		if (perc) {
+			fill_random_buf_percentage(&td->buf_state, io_u->buf,
+						perc, min_write, max_bs);
+		} else
+			fill_random_buf(&td->buf_state, io_u->buf, max_bs);
+	} else
 		memset(io_u->buf, 0, max_bs);
 }
diff --git a/ioengine.h b/ioengine.h
index 51e5594..efca45e 100644
--- a/ioengine.h
+++ b/ioengine.h
@@ -176,7 +176,7 @@
 extern void io_u_queued(struct thread_data *, struct io_u *);
 extern void io_u_log_error(struct thread_data *, struct io_u *);
 extern void io_u_mark_depth(struct thread_data *, unsigned int);
-extern void io_u_fill_buffer(struct thread_data *td, struct io_u *, unsigned int);
+extern void io_u_fill_buffer(struct thread_data *td, struct io_u *, unsigned int, unsigned int);
 void io_u_mark_complete(struct thread_data *, unsigned int);
 void io_u_mark_submit(struct thread_data *, unsigned int);
 
diff --git a/lib/rand.c b/lib/rand.c
index 7c6fed1..66d0472 100644
--- a/lib/rand.c
+++ b/lib/rand.c
@@ -33,6 +33,8 @@
 
 */
 
+#include <string.h>
+#include <assert.h>
 #include "rand.h"
 #include "../hash.h"
 
@@ -88,3 +90,43 @@
 	__fill_random_buf(buf, len, r);
 	return r;
 }
+
+unsigned long fill_random_buf_percentage(struct frand_state *fs, void *buf,
+					 unsigned int percentage,
+					 unsigned int segment, unsigned int len)
+{
+	unsigned int this_len, rep_len;
+	unsigned long r = __rand(fs);
+
+	assert(segment <= len);
+
+	if (sizeof(int) != sizeof(long *))
+		r *= (unsigned long) __rand(fs);
+
+	while (len) {
+		/*
+		 * Fill random chunk
+		 */
+		this_len = (segment * (100 - percentage)) / 100;
+		if (this_len > len)
+			this_len = len;
+
+		__fill_random_buf(buf, this_len, r);
+
+		len -= this_len;
+		buf += this_len;
+
+		/*
+		 * Now duplicate random chunk in rest of buf
+		 */
+		rep_len = segment - this_len;
+		if (rep_len > len)
+			rep_len = len;
+
+		memcpy(buf, buf + rep_len, rep_len);
+		buf += rep_len;
+		len -= rep_len;
+	}
+
+	return r;
+}
diff --git a/lib/rand.h b/lib/rand.h
index 6b9e13c..d62ebe5 100644
--- a/lib/rand.h
+++ b/lib/rand.h
@@ -22,5 +22,6 @@
 extern void init_rand_seed(struct frand_state *, unsigned int seed);
 extern void __fill_random_buf(void *buf, unsigned int len, unsigned long seed);
 extern unsigned long fill_random_buf(struct frand_state *, void *buf, unsigned int len);
+extern unsigned long fill_random_buf_percentage(struct frand_state *, void *buf, unsigned int percentage, unsigned int segment, unsigned int len);
 
 #endif
diff --git a/options.c b/options.c
index d777efc..8034cd7 100644
--- a/options.c
+++ b/options.c
@@ -2014,6 +2014,14 @@
 		.def	= "1",
 	},
 	{
+		.name	= "buffer_compress_percentage",
+		.type	= FIO_OPT_INT,
+		.off1	= td_var_offset(compress_percentage),
+		.maxval	= 100,
+		.minval	= 1,
+		.help	= "How compressible the buffer is (approximately)",
+	},
+	{
 		.name	= "clat_percentiles",
 		.type	= FIO_OPT_BOOL,
 		.off1	= td_var_offset(clat_percentiles),