* fio - the flexible io tester
*
* Copyright (C) 2005 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
int shm_id = 0;
static struct timeval genesis;
static int temp_stall_ts;
+char *fio_inst_prefix = _INST_PREFIX;
static void print_thread_status(void);
static int td_io_prep(struct thread_data *td, struct io_u *io_u)
{
- if (td->io_prep && td->io_prep(td, io_u))
+ if (td->io_ops->prep && td->io_ops->prep(td, io_u))
return 1;
return 0;
static int sync_td(struct thread_data *td)
{
- if (td->io_sync)
- return td->io_sync(td);
+ if (td->io_ops->sync)
+ return td->io_ops->sync(td);
return 0;
}
static int io_u_getevents(struct thread_data *td, int min, int max,
struct timespec *t)
{
- return td->io_getevents(td, min, max, t);
+ return td->io_ops->getevents(td, min, max, t);
}
static int io_u_queue(struct thread_data *td, struct io_u *io_u)
{
gettimeofday(&io_u->issue_time, NULL);
- return td->io_queue(td, io_u);
+ return td->io_ops->queue(td, io_u);
}
#define iocb_time(iocb) ((unsigned long) (iocb)->data)
icd->bytes_done[0] = icd->bytes_done[1] = 0;
for (i = 0; i < icd->nr; i++) {
- io_u = td->io_event(td, i);
+ io_u = td->io_ops->event(td, i);
io_completed(td, io_u, icd);
put_io_u(td, io_u);
/*
* now cancel remaining active events
*/
- if (td->io_cancel) {
+ if (td->io_ops->cancel) {
list_for_each_safe(entry, n, &td->io_u_busylist) {
io_u = list_entry(entry, struct io_u, list);
- r = td->io_cancel(td, io_u);
+ r = td->io_ops->cancel(td, io_u);
if (!r)
put_io_u(td, io_u);
}
break;
}
- v_io_u = td->io_event(td, 0);
+ v_io_u = td->io_ops->event(td, 0);
icd.nr = 1;
icd.error = 0;
io_completed(td, v_io_u, &icd);
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) {
+ gettimeofday(&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.
}
}
-static void cleanup_io(struct thread_data *td)
-{
- if (td->io_cleanup)
- td->io_cleanup(td);
-}
-
static int init_io(struct thread_data *td)
{
- if (td->io_engine == FIO_SYNCIO)
- return fio_syncio_init(td);
- else if (td->io_engine == FIO_MMAPIO)
- return fio_mmapio_init(td);
- else if (td->io_engine == FIO_LIBAIO)
- return fio_libaio_init(td);
- else if (td->io_engine == FIO_POSIXAIO)
- return fio_posixaio_init(td);
- else if (td->io_engine == FIO_SGIO)
- return fio_sgio_init(td);
- else if (td->io_engine == FIO_SPLICEIO)
- return fio_spliceio_init(td);
- else {
- log_err("bad io_engine %d\n", td->io_engine);
- return 1;
- }
+ if (td->io_ops->init)
+ return td->io_ops->init(td);
+
+ return 0;
}
static void cleanup_io_u(struct thread_data *td)
int i, max_units;
char *p;
- if (td->io_engine & FIO_SYNCIO)
+ if (td->io_ops->flags & FIO_CPUIO)
+ return 0;
+
+ if (td->io_ops->flags & FIO_SYNCIO)
max_units = 1;
else
max_units = td->iodepth;
struct stat st;
int flags = 0;
+ if (td->io_ops->setup)
+ return td->io_ops->setup(td);
+
if (stat(td->file_name, &st) == -1) {
if (errno != ENOENT) {
td_verror(td, errno);
if (get_file_size(td))
return 1;
- if (td->io_engine != FIO_MMAPIO)
- return setup_file_plain(td);
- else
+ if (td->io_ops->flags & FIO_MMAPIO)
return setup_file_mmap(td);
+ else
+ return setup_file_plain(td);
}
static int switch_ioscheduler(struct thread_data *td)
static void clear_io_state(struct thread_data *td)
{
- if (td->io_engine == FIO_SYNCIO)
+ if (td->io_ops->flags & FIO_SYNCIO)
lseek(td->fd, SEEK_SET, 0);
td->last_pos = 0;
}
}
- if (nice(td->nice) < 0) {
+ if (nice(td->nice) == -1) {
td_verror(td, errno);
goto err;
}
clear_io_state(td);
prune_io_piece_log(td);
- do_io(td);
+ if (td->io_ops->flags & FIO_CPUIO)
+ do_cpuio(td);
+ else
+ do_io(td);
td->runtime[td->ddir] += mtime_since_now(&td->start);
if (td_rw(td) && td->io_bytes[td->ddir ^ 1])
}
if (td->mmap)
munmap(td->mmap, td->file_size);
- cleanup_io(td);
+ close_ioengine(td);
cleanup_io_u(td);
td_set_runstate(td, TD_EXITED);
return NULL;
printf("Threads running: %d", nr_running);
if (m_rate || t_rate)
printf(", commitrate %d/%dKiB/sec", t_rate, m_rate);
- if (eta_sec != INT_MAX) {
+ if (eta_sec != INT_MAX && nr_running) {
perc *= 100.0;
printf(": [%s] [%3.2f%% done] [eta %s]", run_str, perc,eta_str);
}
*/
static void reap_threads(int *nr_running, int *t_rate, int *m_rate)
{
- int i;
+ int i, cputhreads;
/*
* reap exited threads (TD_EXITED -> TD_REAPED)
*/
- for (i = 0; i < thread_number; i++) {
+ for (i = 0, cputhreads = 0; i < thread_number; i++) {
struct thread_data *td = &threads[i];
+ if (td->io_ops->flags & FIO_CPUIO)
+ cputhreads++;
+
if (td->runstate != TD_EXITED)
continue;
(*m_rate) -= td->ratemin;
(*t_rate) -= td->rate;
}
+
+ if (*nr_running == cputhreads)
+ terminate_threads(TERMINATE_ALL);
}
static void fio_unpin_memory(void *pinned)