From: Jens Axboe Date: Fri, 9 Mar 2007 13:34:23 +0000 (+0100) Subject: Turn the CPU burner into a real io engine X-Git-Tag: fio-1.14~48 X-Git-Url: https://git.kernel.dk/?p=fio.git;a=commitdiff_plain;h=ba0fbe1029bae1de08d66a72b6d0b2505c67c438 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 --- diff --git a/HOWTO b/HOWTO index d1a3ad1e..1374d05e 100644 --- a/HOWTO +++ b/HOWTO @@ -301,6 +301,12 @@ ioengine=str Defines how the job issues io to the file. The following 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 69803403..8b55f314 100644 --- a/README +++ b/README @@ -106,11 +106,11 @@ The job file parameters are: 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 @@ The job file parameters are: 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 c89a4c9e..7a084e0a 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 6ce46ba5..36dde3a6 100644 --- a/fio.c +++ b/fio.c @@ -361,31 +361,6 @@ static void do_verify(struct thread_data *td) td_set_runstate(td, TD_RUNNING); } -/* - * 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 @@ static int init_io_u(struct thread_data *td) 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 @@ static int switch_ioscheduler(struct thread_data *td) 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 @@ static void *thread_main(void *data) 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 @@ static void reap_threads(int *nr_running, int *t_rate, int *m_rate) * ->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 c20f21ba..41a1790d 100644 --- a/fio.h +++ b/fio.h @@ -212,9 +212,8 @@ enum fio_filetype { 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 56df3c75..ba33a5e3 100644 --- a/init.c +++ b/init.c @@ -102,6 +102,7 @@ static struct fio_option options[] = { #ifdef FIO_HAVE_SYSLET { .ival = "syslet-rw", }, #endif + { .ival = "cpuio", }, { .ival = "external", }, }, }, @@ -474,7 +475,8 @@ static struct fio_option options[] = { .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 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num) 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 init_random_state(struct thread_data *td) 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 66991c7c..9de7ca16 100644 --- a/ioengines.c +++ b/ioengines.c @@ -28,12 +28,6 @@ static int check_engine_ops(struct ioengine_ops *ops) 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 994f4971..50caf3d4 100644 --- a/log.c +++ b/log.c @@ -172,7 +172,7 @@ int init_iolog(struct thread_data *td) { int ret = 0; - if (td->io_ops->flags & FIO_CPUIO) + if (td->io_ops->flags & FIO_DISKLESSIO) return 0; if (td->read_iolog_file)