log: batch entries of samples before deflating

This both speeds up the log and gets better compression
ratios for the data.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
diff --git a/iolog.c b/iolog.c
index 6807a9f..4eeee4c 100644
--- a/iolog.c
+++ b/iolog.c
@@ -550,23 +550,80 @@
 	free(log);
 }
 
+static void write_log_samples(FILE *f, struct io_sample *samples,
+			      unsigned long nr_samples)
+{
+	unsigned long i;
+
+	for (i = 0; i < nr_samples; i++) {
+		struct io_sample *s = &samples[i];
+
+		s->time = le64_to_cpu(s->time);
+		s->val = le64_to_cpu(s->val);
+		s->ddir = le32_to_cpu(s->ddir);
+		s->bs = le32_to_cpu(s->bs);
+
+		fprintf(f, "%lu, %lu, %u, %u\n",
+				(unsigned long) s->time, (unsigned long) s->val,
+				s->ddir, s->bs);
+	}
+}
+
 #ifdef CONFIG_ZLIB
+static void flush_batch_samples(struct io_log *iolog)
+{
+	int ret;
+
+	iolog->stream.next_in = (void *) iolog->batch_samples;
+	iolog->stream.avail_in = sizeof(struct io_sample) * iolog->nr_batch_samples;
+
+	if (iolog->buf_size - iolog->stream.total_out < IOLOG_Z_WINDOW_MIN) {
+		void *new_buf;
+
+		iolog->buf_size += IOLOG_Z_WINDOW;
+		new_buf = realloc(iolog->buf, iolog->buf_size);
+		if (!new_buf) {
+			log_err("fio: failed extending iolog! Will stop logging.\n");
+			iolog->disabled = 1;
+			return;
+		}
+
+		iolog->buf = new_buf;
+	}
+
+	iolog->stream.avail_out = iolog->buf_size - iolog->stream.total_out;
+	iolog->stream.next_out = iolog->buf + iolog->stream.total_out;
+
+	ret = deflate(&iolog->stream, Z_NO_FLUSH);
+	if (ret < 0) {
+		log_err("fio: log deflation failed (%d)\n", ret);
+		iolog->disabled = 1;
+	}
+
+	iolog->nr_batch_samples = 0;
+}
+
 static void __finish_log_method(struct io_log *log, FILE *f)
 {
 	struct io_sample *samples;
-	unsigned int i;
 	z_stream out;
 	int err;
 
 	/*
-	 * Finish deflation of the log
+	 * Finish deflation of the log, flush out any left batched
+	 * samples first.
 	 */
+	if (log->nr_batch_samples)
+		flush_batch_samples(log);
+
 	deflate(&log->stream, Z_FINISH);
 	deflateEnd(&log->stream);
 
 	if (!log->stream.total_out)
 		return;
 
+	printf("Compression level: 1 : %.2f\n", ((float) sizeof(struct io_sample) * log->nr_samples) / (float) log->buf_size);
+
 	out.zalloc = Z_NULL;
 	out.zfree = Z_NULL;
 	out.opaque = Z_NULL;
@@ -596,20 +653,7 @@
 		}
 
 		nr = (this_out - out.avail_out) / sizeof(struct io_sample);
-
-		for (i = 0; i < nr; i++) {
-			struct io_sample *s = &samples[i];
-
-			s->time = le64_to_cpu(s->time);
-			s->val = le64_to_cpu(s->val);
-			s->ddir = le32_to_cpu(s->ddir);
-			s->bs = le32_to_cpu(s->bs);
-
-			fprintf(f, "%lu, %lu, %u, %u\n",
-					(unsigned long) s->time,
-					(unsigned long) s->val,
-					s->ddir, s->bs);
-		}
+		write_log_samples(f, samples, nr);
 	} while (out.avail_in);
 
 	err = inflateEnd(&out);
@@ -619,21 +663,7 @@
 #else
 static void __finish_log_method(struct io_log *log, FILE *f)
 {
-	unsigned int i;
-
-	for (i = 0; i < log->nr_samples; i++) {
-		struct io_sample *s = &log->log[i];
-
-		s->time	= le64_to_cpu(s->time);
-		s->val	= le64_to_cpu(s->val);
-		s->ddir	= le32_to_cpu(s->ddir);
-		s->bs	= le32_to_cpu(s->bs);
-
-		fprintf(f, "%lu, %lu, %u, %u\n",
-				(unsigned long) s->time,
-				(unsigned long) s->val,
-				s->ddir, s->bs);
-	}
+	write_log_samples(f, log->log, log->nr_samples);
 }
 #endif
 
@@ -676,34 +706,11 @@
 #ifdef CONFIG_ZLIB
 static void __add_log_sample_gz(struct io_log *iolog, struct io_sample *s)
 {
-	int ret;
+	if (iolog->nr_batch_samples == BATCH_SAMPLES)
+		flush_batch_samples(iolog);
 
-	iolog->stream.next_in = (void *) s;
-	iolog->stream.avail_in = sizeof(*s);
-
-	if (iolog->buf_size - iolog->stream.total_out < IOLOG_Z_WINDOW_MIN) {
-		void *new_buf;
-
-		iolog->buf_size += IOLOG_Z_WINDOW;
-		new_buf = realloc(iolog->buf, iolog->buf_size);
-		if (!new_buf) {
-			log_err("fio: failed extending iolog! Will stop logging.\n");
-			iolog->disabled = 1;
-			return;
-		}
-
-		iolog->buf = new_buf;
-	}
-
-	iolog->stream.avail_out = iolog->buf_size - iolog->stream.total_out;
-	iolog->stream.next_out = iolog->buf + iolog->stream.total_out;
-
-	ret = deflate(&iolog->stream, Z_NO_FLUSH);
-	if (ret < 0) {
-		log_err("fio: log deflation failed (%d)\n", ret);
-		iolog->disabled = 1;
-	}
-
+	memcpy(&iolog->batch_samples[iolog->nr_batch_samples], s, sizeof(*s));
+	++iolog->nr_batch_samples;
 }
 #else
 static void __add_log_sample_plain(struct io_log *iolog, struct io_sample *s)
diff --git a/iolog.h b/iolog.h
index 0d14e78..dae6b50 100644
--- a/iolog.h
+++ b/iolog.h
@@ -55,6 +55,10 @@
 	unsigned long nr_samples;
 
 #ifdef CONFIG_ZLIB
+#define BATCH_SAMPLES 64
+	struct io_sample batch_samples[BATCH_SAMPLES];
+	unsigned int nr_batch_samples;
+
 	void *buf;
 	unsigned long buf_size;