*/
static void cleanup_pending_aio(struct thread_data *td)
{
- struct flist_head *entry, *n;
- struct io_u *io_u;
int r;
/*
* now cancel remaining active events
*/
if (td->io_ops->cancel) {
- flist_for_each_safe(entry, n, &td->io_u_busylist) {
- io_u = flist_entry(entry, struct io_u, list);
+ struct io_u *io_u;
+ int i;
- /*
- * if the io_u isn't in flight, then that generally
- * means someone leaked an io_u. complain but fix
- * it up, so we don't stall here.
- */
- if ((io_u->flags & IO_U_F_FLIGHT) == 0) {
- log_err("fio: non-busy IO on busy list\n");
- put_io_u(td, io_u);
- } else {
+ io_u_qiter(&td->io_u_all, io_u, i) {
+ if (io_u->flags & IO_U_F_FLIGHT) {
r = td->io_ops->cancel(td, io_u);
if (!r)
put_io_u(td, io_u);
uint64_t bytes_done[DDIR_RWDIR_CNT] = { 0, 0, 0 };
unsigned int i;
int ret = 0;
+ uint64_t bytes_issued = 0;
if (in_ramp_time(td))
td_set_runstate(td, TD_RAMP);
if (flow_threshold_exceeded(td))
continue;
+ if (bytes_issued >= (uint64_t) td->o.size)
+ break;
+
io_u = get_io_u(td);
if (!io_u)
break;
int bytes = io_u->xfer_buflen - io_u->resid;
struct fio_file *f = io_u->file;
+ bytes_issued += bytes;
/*
* zero read, fail
*/
ret = io_u_sync_complete(td, io_u, bytes_done);
if (ret < 0)
break;
+ bytes_issued += io_u->xfer_buflen;
}
break;
case FIO_Q_QUEUED:
*/
if (td->io_ops->commit == NULL)
io_u_queued(td, io_u);
+ bytes_issued += io_u->xfer_buflen;
break;
case FIO_Q_BUSY:
requeue_io_u(td, &io_u);
if (!(b % td->o.thinktime_blocks)) {
int left;
+ io_u_quiesce(td);
+
if (td->o.thinktime_spin)
usec_spin(td->o.thinktime_spin);
static void cleanup_io_u(struct thread_data *td)
{
- struct flist_head *entry, *n;
struct io_u *io_u;
- flist_for_each_safe(entry, n, &td->io_u_freelist) {
- io_u = flist_entry(entry, struct io_u, list);
-
- flist_del(&io_u->list);
+ while ((io_u = io_u_qpop(&td->io_u_freelist)) != NULL) {
if (td->io_ops->io_u_free)
td->io_ops->io_u_free(td, io_u);
}
free_io_mem(td);
+
+ io_u_rexit(&td->io_u_requeues);
+ io_u_qexit(&td->io_u_freelist);
+ io_u_qexit(&td->io_u_all);
}
static int init_io_u(struct thread_data *td)
struct io_u *io_u;
unsigned int max_bs, min_write;
int cl_align, i, max_units;
- int data_xfer = 1;
+ int data_xfer = 1, err;
char *p;
max_units = td->o.iodepth;
if ((td->io_ops->flags & FIO_NOIO) || !(td_read(td) || td_write(td)))
data_xfer = 0;
+ err = 0;
+ err += io_u_rinit(&td->io_u_requeues, td->o.iodepth);
+ err += io_u_qinit(&td->io_u_freelist, td->o.iodepth);
+ err += io_u_qinit(&td->io_u_all, td->o.iodepth);
+
+ if (err) {
+ log_err("fio: failed setting up IO queues\n");
+ return 1;
+ }
+
+ /*
+ * if we may later need to do address alignment, then add any
+ * possible adjustment here so that we don't cause a buffer
+ * overflow later. this adjustment may be too much if we get
+ * lucky and the allocator gives us an aligned address.
+ */
+ if (td->o.odirect || td->o.mem_align || td->o.oatomic ||
+ (td->io_ops->flags & FIO_RAWIO))
+ td->orig_buffer_size += page_mask + td->o.mem_align;
+
if (td->o.mem_type == MEM_SHMHUGE || td->o.mem_type == MEM_MMAPHUGE) {
unsigned long bs;
if (data_xfer && allocate_io_mem(td))
return 1;
- if (td->o.odirect || td->o.mem_align ||
+ if (td->o.odirect || td->o.mem_align || td->o.oatomic ||
(td->io_ops->flags & FIO_RAWIO))
p = PAGE_ALIGN(td->orig_buffer) + td->o.mem_align;
else
io_u = ptr;
memset(io_u, 0, sizeof(*io_u));
- INIT_FLIST_HEAD(&io_u->list);
+ INIT_FLIST_HEAD(&io_u->verify_list);
dprint(FD_MEM, "io_u alloc %p, index %u\n", io_u, i);
if (data_xfer) {
io_u->index = i;
io_u->flags = IO_U_F_FREE;
- flist_add(&io_u->list, &td->io_u_freelist);
+ io_u_qpush(&td->io_u_freelist, io_u);
+
+ /*
+ * io_u never leaves this stack, used for iteration of all
+ * io_u buffers.
+ */
+ io_u_qpush(&td->io_u_all, io_u);
if (td->io_ops->io_u_init) {
int ret = td->io_ops->io_u_init(td, io_u);
return 0;
}
-static int exec_string(const char *string)
+static int exec_string(struct thread_options *o, const char *string, const char *mode)
{
- int ret, newlen = strlen(string) + 1 + 8;
+ int ret, newlen = strlen(string) + strlen(o->name) + strlen(mode) + 9 + 1;
char *str;
str = malloc(newlen);
- sprintf(str, "sh -c %s", string);
+ sprintf(str, "%s &> %s.%s.txt", string, o->name, mode);
+ log_info("%s : Saving output of %s in %s.%s.txt\n",o->name, mode, o->name, mode);
ret = system(str);
if (ret == -1)
log_err("fio: exec of cmd <%s> failed\n", str);
} else
td->pid = gettid();
+ /*
+ * fio_time_init() may not have been called yet if running as a server
+ */
+ fio_time_init();
+
fio_local_clock_init(o->use_thread);
dprint(FD_PROCESS, "jobs pid=%d started\n", (int) td->pid);
if (is_backend)
fio_server_send_start(td);
- INIT_FLIST_HEAD(&td->io_u_freelist);
- INIT_FLIST_HEAD(&td->io_u_busylist);
- INIT_FLIST_HEAD(&td->io_u_requeues);
INIT_FLIST_HEAD(&td->io_log_list);
INIT_FLIST_HEAD(&td->io_hist_list);
INIT_FLIST_HEAD(&td->verify_list);
if (init_random_map(td))
goto err;
- if (o->exec_prerun && exec_string(o->exec_prerun))
+ if (o->exec_prerun && exec_string(o, o->exec_prerun, (const char *)"prerun"))
goto err;
if (o->pre_read) {
fio_mutex_up(writeout_mutex);
if (o->exec_postrun)
- exec_string(o->exec_postrun);
+ exec_string(o, o->exec_postrun, (const char *)"postrun");
if (exitall_on_terminate)
fio_terminate_threads(td->groupid);
exit_value++;
done_secs += mtime_since_now(&td->epoch) / 1000;
+ profile_td_exit(td);
}
if (*nr_running == cputhreads && !pending && realthreads)
fio_terminate_threads(TERMINATE_ALL);
}
+static void do_usleep(unsigned int usecs)
+{
+ check_for_running_stats();
+ usleep(usecs);
+}
+
/*
* Main function for kicking off and reaping jobs, as needed.
*/
if (fio_gtod_offload && fio_start_gtod_thread())
return;
-
+
fio_idle_prof_init();
set_sig_handlers();
if (mtime_since_now(&this_start) > JOB_START_TIMEOUT)
break;
- usleep(100000);
+ do_usleep(100000);
for (i = 0; i < this_jobs; i++) {
td = map[i];
reap_threads(&nr_running, &t_rate, &m_rate);
if (todo)
- usleep(100000);
+ do_usleep(100000);
}
while (nr_running) {
reap_threads(&nr_running, &t_rate, &m_rate);
- usleep(10000);
+ do_usleep(10000);
}
fio_idle_prof_stop();
return 1;
set_genesis_time();
+ stat_init();
create_disk_util_thread();
cgroup_list = smalloc(sizeof(*cgroup_list));
fio_mutex_remove(startup_mutex);
fio_mutex_remove(writeout_mutex);
fio_mutex_remove(disk_thread_mutex);
+ stat_exit();
return exit_value;
}