*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <unistd.h>
if (ddir_rw(io_u->ddir))
td->ts.short_io_u[io_u->ddir]++;
- f = io_u->file;
if (io_u->offset == f->real_file_size)
goto sync_done;
*/
static long long usec_for_io(struct thread_data *td, enum fio_ddir ddir)
{
- uint64_t secs, remainder, bps, bytes, iops;
+ uint64_t bps = td->rate_bps[ddir];
assert(!(td->flags & TD_F_CHILD));
- bytes = td->rate_io_issue_bytes[ddir];
- bps = td->rate_bps[ddir];
if (td->o.rate_process == RATE_PROCESS_POISSON) {
- uint64_t val;
+ uint64_t val, iops;
+
iops = bps / td->o.bs[ddir];
val = (int64_t) (1000000 / iops) *
-logf(__rand_0_1(&td->poisson_state[ddir]));
td->last_usec[ddir] += val;
return td->last_usec[ddir];
} else if (bps) {
- secs = bytes / bps;
- remainder = bytes % bps;
+ uint64_t bytes = td->rate_io_issue_bytes[ddir];
+ uint64_t secs = bytes / bps;
+ uint64_t remainder = bytes % bps;
+
return remainder * 1000000 / bps + secs * 1000000;
}
return 0;
}
+static void handle_thinktime(struct thread_data *td, enum fio_ddir ddir)
+{
+ unsigned long long b;
+ uint64_t total;
+ int left;
+
+ b = ddir_rw_sum(td->io_blocks);
+ if (b % td->o.thinktime_blocks)
+ return;
+
+ io_u_quiesce(td);
+
+ total = 0;
+ if (td->o.thinktime_spin)
+ total = usec_spin(td->o.thinktime_spin);
+
+ left = td->o.thinktime - total;
+ if (left)
+ total += usec_sleep(td, left);
+
+ /*
+ * If we're ignoring thinktime for the rate, add the number of bytes
+ * we would have done while sleeping, minus one block to ensure we
+ * start issuing immediately after the sleep.
+ */
+ if (total && td->rate_bps[ddir] && td->o.rate_ign_think) {
+ uint64_t missed = (td->rate_bps[ddir] * total) / 1000000ULL;
+ uint64_t bs = td->o.min_bs[ddir];
+ uint64_t usperop = bs * 1000000ULL / td->rate_bps[ddir];
+ uint64_t over;
+
+ if (usperop <= total)
+ over = bs;
+ else
+ over = (usperop - total) / usperop * -bs;
+
+ td->rate_io_issue_bytes[ddir] += (missed - over);
+ }
+}
+
/*
* Main IO worker function. It retrieves io_u's to process and queues
* and reaps them, checking for rate and errors along the way.
int err = PTR_ERR(io_u);
io_u = NULL;
+ ddir = DDIR_INVAL;
if (err == -EBUSY) {
ret = FIO_Q_BUSY;
goto reap;
if (!in_ramp_time(td) && td->o.latency_target)
lat_target_check(td);
- if (td->o.thinktime) {
- unsigned long long b;
-
- b = ddir_rw_sum(td->io_blocks);
- if (!(b % td->o.thinktime_blocks)) {
- int left;
-
- io_u_quiesce(td);
-
- if (td->o.thinktime_spin)
- usec_spin(td->o.thinktime_spin);
-
- left = td->o.thinktime - td->o.thinktime_spin;
- if (left)
- usec_sleep(td, left);
- }
- }
+ if (ddir_rw(ddir) && td->o.thinktime)
+ handle_thinktime(td, ddir);
}
check_update_rusage(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);
+ 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");
struct sk_out *sk_out = fd->sk_out;
uint64_t bytes_done[DDIR_RWDIR_CNT];
int deadlock_loop_cnt;
- int clear_state;
+ bool clear_state, did_some_io;
int ret;
sk_out_assign(sk_out);
if (td_io_init(td))
goto err;
- if (init_random_map(td))
+ if (!init_random_map(td))
goto err;
if (o->exec_prerun && exec_string(o, o->exec_prerun, (const char *)"prerun"))
goto err;
- if (o->pre_read) {
- if (pre_read_files(td) < 0)
- goto err;
- }
+ if (o->pre_read && !pre_read_files(td))
+ goto err;
fio_verify_init(td);
}
memset(bytes_done, 0, sizeof(bytes_done));
- clear_state = 0;
+ clear_state = false;
+ did_some_io = false;
while (keep_running(td)) {
uint64_t verify_bytes;
if (td->runstate >= TD_EXITED)
break;
- clear_state = 1;
+ clear_state = true;
/*
* Make sure we've successfully updated the rusage stats
td_ioengine_flagged(td, FIO_UNIDIR))
continue;
+ if (ddir_rw_sum(bytes_done))
+ did_some_io = true;
+
clear_io_state(td, 0);
fio_gettime(&td->start, NULL);
* (Are we not missing other flags that can be ignored ?)
*/
if ((td->o.size || td->o.io_size) && !ddir_rw_sum(bytes_done) &&
+ !did_some_io && !td->o.create_only &&
!(td_ioengine_flagged(td, FIO_NOIO) ||
td_ioengine_flagged(td, FIO_DISKLESSIO)))
log_err("%s: No I/O performed by %s, "
for_each_td(td, i) {
int flags = 0;
- /*
- * ->io_ops is NULL for a thread that has closed its
- * io engine
- */
- if (td->io_ops && !strcmp(td->io_ops->name, "cpuio"))
+ if (!strcmp(td->o.ioengine, "cpuio"))
cputhreads++;
else
realthreads++;
nr_started--;
break;
}
+ fd = NULL;
ret = pthread_detach(td->thread);
if (ret)
log_err("pthread_detach: %s",
fio_terminate_threads(TERMINATE_ALL);
fio_abort = 1;
nr_started--;
+ free(fd);
break;
}
dprint(FD_MUTEX, "done waiting on startup_mutex\n");
}
for_each_td(td, i) {
- if (td->ss.dur) {
- if (td->ss.iops_data != NULL) {
- free(td->ss.iops_data);
- free(td->ss.bw_data);
- }
- }
+ steadystate_free(td);
fio_options_free(td);
if (td->rusage_sem) {
fio_mutex_remove(td->rusage_sem);