Turn the CPU burner into a real io engine

This removes the special casing in fio.c for the cpu engine, and
also gets rid of FIO_CPUIO.

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
diff --git a/HOWTO b/HOWTO
index d1a3ad1..1374d05 100644
--- a/HOWTO
+++ b/HOWTO
@@ -301,6 +301,12 @@
 				or receive, if the latter only the port
 				argument is used.
 
+			cpu	Doesn't transfer any data, but burns CPU
+				cycles according to the cpuload= and
+				cpucycle= options. Setting cpuload=85
+				will cause that job to do nothing but burn
+				85% of the CPU.
+
 			external Prefix to specify loading an external
 				IO engine object file. Append the engine
 				filename, eg ioengine=external:/tmp/foo.o
diff --git a/README b/README
index 6980340..8b55f31 100644
--- a/README
+++ b/README
@@ -106,11 +106,11 @@
 			posixaio for POSIX aio, sync for regular read/write io,
 			mmap for mmap'ed io, syslet-rw for syslet driven
 			read/write, splice for using splice/vmsplice,
-			sgio for direct SG_IO io, or net for network io. sgio
-			only works on Linux on SCSI (or SCSI-like devices,
-			such as usb-storage or sata/libata driven) devices.
-			Fio also has a null io engine, which is mainly used
-			for testing fio itself.
+			sgio for direct SG_IO io, net for network io, or cpuio
+			for a cycler burner load. sgio only works on Linux on
+			SCSI (or SCSI-like devices, such as usb-storage or
+			sata/libata driven) devices. Fio also has a null io
+			engine, which is mainly used for testing fio itself.
 	iodepth=x	For async io, allow 'x' ios in flight
 	overwrite=x	If 'x', layout a write file first.
 	nrfiles=x	Spread io load over 'x' number of files per job,
@@ -176,7 +176,7 @@
 	ioscheduler=x	Use ioscheduler 'x' for this job.
 	cpuload=x	For a CPU io thread, percentage of CPU time to attempt
 			to burn.
-	cpuchunks=x	Split burn cycles into pieces of x.
+	cpuchunks=x	Split burn cycles into pieces of x usecs.
 
 
 Author
diff --git a/engines/cpu.c b/engines/cpu.c
index c89a4c9..7a084e0 100644
--- a/engines/cpu.c
+++ b/engines/cpu.c
@@ -1,30 +1,64 @@
 #include "../fio.h"
 #include "../os.h"
 
+static int fio_cpuio_queue(struct thread_data *td, struct io_u fio_unused *io_u)
+{
+	__usec_sleep(td->cpucycle);
+	return FIO_Q_COMPLETED;
+}
+
 static int fio_cpuio_setup(struct thread_data fio_unused *td)
 {
+	struct fio_file *f;
+	int i;
+
+	td->total_file_size = -1;
+	td->io_size = td->total_file_size;
+	td->total_io_size = td->io_size;
+
+	for_each_file(td, f, i) {
+		f->real_file_size = -1;
+		f->file_size = -1;
+	}
+
 	return 0;
 }
 
 static int fio_cpuio_init(struct thread_data *td)
 {
 	if (!td->cpuload) {
-		td_vmsg(td, EINVAL, "cpu thread needs rate", "cpu_load");
+		td_vmsg(td, EINVAL, "cpu thread needs rate (cpuload=)","cpuio");
 		return 1;
-	} else if (td->cpuload > 100)
+	}
+
+	if (td->cpuload > 100)
 		td->cpuload = 100;
 
-	td->nr_files = 0;
+	/*
+	 * set thinktime_sleep and thinktime_spin appropriately
+	 */
+	td->thinktime_blocks = 1;
+	td->thinktime_spin = 0;
+	td->thinktime = (td->cpucycle * (100 - td->cpuload)) / td->cpuload;
 
+	td->nr_files = td->open_files = 1;
+	return 0;
+}
+
+static int fio_cpuio_open(struct thread_data fio_unused *td, struct fio_file *f)
+{
+	f->fd = 0;
 	return 0;
 }
 
 static struct ioengine_ops ioengine = {
 	.name		= "cpuio",
 	.version	= FIO_IOOPS_VERSION,
+	.queue		= fio_cpuio_queue,
 	.init		= fio_cpuio_init,
 	.setup		= fio_cpuio_setup,
-	.flags		= FIO_CPUIO,
+	.open_file	= fio_cpuio_open,
+	.flags		= FIO_SYNCIO | FIO_DISKLESSIO,
 };
 
 static void fio_init fio_cpuio_register(void)
diff --git a/fio.c b/fio.c
index 6ce46ba..36dde3a 100644
--- a/fio.c
+++ b/fio.c
@@ -362,31 +362,6 @@
 }
 
 /*
- * Not really an io thread, all it does is burn CPU cycles in the specified
- * manner.
- */
-static void do_cpuio(struct thread_data *td)
-{
-	struct timeval e;
-	int split = 100 / td->cpuload;
-	int i = 0;
-
-	while (!td->terminate) {
-		fio_gettime(&e, NULL);
-
-		if (runtime_exceeded(td, &e))
-			break;
-
-		if (!(i % split))
-			__usec_sleep(10000);
-		else
-			usec_sleep(td, 10000);
-
-		i++;
-	}
-}
-
-/*
  * Main IO worker function. It retrieves io_u's to process and queues
  * and reaps them, checking for rate and errors along the way.
  */
@@ -566,9 +541,6 @@
 	int i, max_units;
 	char *p;
 
-	if (td->io_ops->flags & FIO_CPUIO)
-		return 0;
-
 	if (td->io_ops->flags & FIO_SYNCIO)
 		max_units = 1;
 	else
@@ -611,7 +583,7 @@
 	FILE *f;
 	int ret;
 
-	if (td->io_ops->flags & FIO_CPUIO)
+	if (td->io_ops->flags & FIO_DISKLESSIO)
 		return 0;
 
 	sprintf(tmp, "%s/queue/scheduler", td->sysfs_root);
@@ -772,10 +744,7 @@
 
 		prune_io_piece_log(td);
 
-		if (td->io_ops->flags & FIO_CPUIO)
-			do_cpuio(td);
-		else
-			do_io(td);
+		do_io(td);
 
 		clear_state = 1;
 
@@ -878,7 +847,7 @@
 		 * ->io_ops is NULL for a thread that has closed its
 		 * io engine
 		 */
-		if (td->io_ops && td->io_ops->flags & FIO_CPUIO)
+		if (td->io_ops && !strcmp(td->io_ops->name, "cpuio"))
 			cputhreads++;
 
 		if (!td->pid || td->runstate == TD_REAPED)
diff --git a/fio.h b/fio.h
index c20f21b..41a1790 100644
--- a/fio.h
+++ b/fio.h
@@ -212,9 +212,8 @@
 
 enum fio_ioengine_flags {
 	FIO_SYNCIO	= 1 << 0,	/* io engine has synchronous ->queue */
-	FIO_CPUIO	= 1 << 1,	/* cpu burner, doesn't do real io */
-	FIO_RAWIO	= 1 << 2,	/* some sort of direct/raw io */
-	FIO_DISKLESSIO	= 1 << 3,	/* no disk involved */
+	FIO_RAWIO	= 1 << 1,	/* some sort of direct/raw io */
+	FIO_DISKLESSIO	= 1 << 2,	/* no disk involved */
 };
 
 /*
diff --git a/init.c b/init.c
index 56df3c7..ba33a5e 100644
--- a/init.c
+++ b/init.c
@@ -102,6 +102,7 @@
 #ifdef FIO_HAVE_SYSLET
 			  { .ival = "syslet-rw", },
 #endif
+			  { .ival = "cpuio", },
 			  { .ival = "external", },
 			  },
 	},
@@ -474,7 +475,8 @@
 		.name	= "cpuchunks",
 		.type	= FIO_OPT_INT,
 		.off1	= td_var_offset(cpucycle),
-		.help	= "Length of the CPU burn cycles",
+		.help	= "Length of the CPU burn cycles (usecs)",
+		.def	= "50000",
 	},
 #ifdef FIO_HAVE_CPU_AFFINITY
 	{
@@ -902,7 +904,7 @@
 
 	if (!terse_output) {
 		if (!job_add_num) {
-			if (td->io_ops->flags & FIO_CPUIO)
+			if (!strcmp(td->io_ops->name, "cpuio"))
 				fprintf(f_out, "%s: ioengine=cpu, cpuload=%u, cpucycle=%u\n", td->name, td->cpuload, td->cpucycle);
 			else {
 				char *c1, *c2, *c3, *c4;
@@ -957,7 +959,7 @@
 	int fd, num_maps, blocks, i;
 	struct fio_file *f;
 
-	if (td->io_ops->flags & FIO_CPUIO)
+	if (td->io_ops->flags & FIO_DISKLESSIO)
 		return 0;
 
 	fd = open("/dev/urandom", O_RDONLY);
diff --git a/ioengines.c b/ioengines.c
index 66991c7..9de7ca1 100644
--- a/ioengines.c
+++ b/ioengines.c
@@ -28,12 +28,6 @@
 		return 1;
 	}
 
-	/*
-	 * cpu thread doesn't need to provide anything
-	 */
-	if (ops->flags & FIO_CPUIO)
-		return 0;
-
 	if (!ops->queue) {
 		log_err("%s: no queue handler\n", ops->name);
 		return 1;
diff --git a/log.c b/log.c
index 994f497..50caf3d 100644
--- a/log.c
+++ b/log.c
@@ -172,7 +172,7 @@
 {
 	int ret = 0;
 
-	if (td->io_ops->flags & FIO_CPUIO)
+	if (td->io_ops->flags & FIO_DISKLESSIO)
 		return 0;
 
 	if (td->read_iolog_file)