X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=backend.c;h=4bc00e696602d681a7008512f0f9a9c1fbb73c30;hp=b43486dc7b2ff016b6d76d281dc479692e90b231;hb=5be9bf098d3766a8f27d446d82911c5ef0153676;hpb=9b87f09b1d3cac320c2da5758c1e74d4b4c0fadd diff --git a/backend.c b/backend.c index b43486dc..4bc00e69 100644 --- a/backend.c +++ b/backend.c @@ -76,9 +76,6 @@ int shm_id = 0; int temp_stall_ts; unsigned long done_secs = 0; -#define PAGE_ALIGN(buf) \ - (char *) (((uintptr_t) (buf) + page_mask) & ~page_mask) - #define JOB_START_TIMEOUT (5 * 1000) static void sig_int(int sig) @@ -180,8 +177,8 @@ static bool __check_min_rate(struct thread_data *td, struct timeval *now, * check bandwidth specified rate */ if (bytes < td->rate_bytes[ddir]) { - log_err("%s: min rate %u not met\n", td->o.name, - ratemin); + log_err("%s: rate_min=%uB/s not met, only transferred %lluB\n", + td->o.name, ratemin, bytes); return true; } else { if (spent) @@ -191,9 +188,8 @@ static bool __check_min_rate(struct thread_data *td, struct timeval *now, if (rate < ratemin || bytes < td->rate_bytes[ddir]) { - log_err("%s: min rate %u not met, got" - " %luKB/sec\n", td->o.name, - ratemin, rate); + log_err("%s: rate_min=%uB/s not met, got %luB/s\n", + td->o.name, ratemin, rate); return true; } } @@ -202,8 +198,8 @@ static bool __check_min_rate(struct thread_data *td, struct timeval *now, * checks iops specified rate */ if (iops < rate_iops) { - log_err("%s: min iops rate %u not met\n", - td->o.name, rate_iops); + log_err("%s: rate_iops_min=%u not met, only performed %lu IOs\n", + td->o.name, rate_iops, iops); return true; } else { if (spent) @@ -213,9 +209,8 @@ static bool __check_min_rate(struct thread_data *td, struct timeval *now, if (rate < rate_iops_min || iops < td->rate_blocks[ddir]) { - log_err("%s: min iops rate %u not met," - " got %lu\n", td->o.name, - rate_iops_min, rate); + log_err("%s: rate_iops_min=%u not met, got %lu IOPS\n", + td->o.name, rate_iops_min, rate); return true; } } @@ -441,11 +436,8 @@ static int wait_for_completions(struct thread_data *td, struct timeval *time) int min_evts = 0; int ret; - if (td->flags & TD_F_REGROW_LOGS) { - ret = io_u_quiesce(td); - regrow_logs(td); - return ret; - } + if (td->flags & TD_F_REGROW_LOGS) + return io_u_quiesce(td); /* * if the queue is full, we MUST reap at least 1 event @@ -771,21 +763,21 @@ static bool exceeds_number_ios(struct thread_data *td) return number_ios >= (td->o.number_ios * td->loops); } -static bool io_issue_bytes_exceeded(struct thread_data *td) +static bool io_bytes_exceeded(struct thread_data *td, uint64_t *this_bytes) { unsigned long long bytes, limit; if (td_rw(td)) - bytes = td->io_issue_bytes[DDIR_READ] + td->io_issue_bytes[DDIR_WRITE]; + bytes = this_bytes[DDIR_READ] + this_bytes[DDIR_WRITE]; else if (td_write(td)) - bytes = td->io_issue_bytes[DDIR_WRITE]; + bytes = this_bytes[DDIR_WRITE]; else if (td_read(td)) - bytes = td->io_issue_bytes[DDIR_READ]; + bytes = this_bytes[DDIR_READ]; else - bytes = td->io_issue_bytes[DDIR_TRIM]; + bytes = this_bytes[DDIR_TRIM]; - if (td->o.io_limit) - limit = td->o.io_limit; + if (td->o.io_size) + limit = td->o.io_size; else limit = td->o.size; @@ -793,26 +785,14 @@ static bool io_issue_bytes_exceeded(struct thread_data *td) return bytes >= limit || exceeds_number_ios(td); } -static bool io_complete_bytes_exceeded(struct thread_data *td) +static bool io_issue_bytes_exceeded(struct thread_data *td) { - unsigned long long bytes, limit; - - if (td_rw(td)) - bytes = td->this_io_bytes[DDIR_READ] + td->this_io_bytes[DDIR_WRITE]; - else if (td_write(td)) - bytes = td->this_io_bytes[DDIR_WRITE]; - else if (td_read(td)) - bytes = td->this_io_bytes[DDIR_READ]; - else - bytes = td->this_io_bytes[DDIR_TRIM]; - - if (td->o.io_limit) - limit = td->o.io_limit; - else - limit = td->o.size; + return io_bytes_exceeded(td, td->io_issue_bytes); +} - limit *= td->loops; - return bytes >= limit || exceeds_number_ios(td); +static bool io_complete_bytes_exceeded(struct thread_data *td) +{ + return io_bytes_exceeded(td, td->this_io_bytes); } /* @@ -871,11 +851,11 @@ static void do_io(struct thread_data *td, uint64_t *bytes_done) total_bytes = td->o.size; /* - * Allow random overwrite workloads to write up to io_limit + * Allow random overwrite workloads to write up to io_size * before starting verification phase as 'size' doesn't apply. */ if (td_write(td) && td_random(td) && td->o.norandommap) - total_bytes = max(total_bytes, (uint64_t) td->o.io_limit); + total_bytes = max(total_bytes, (uint64_t) td->o.io_size); /* * If verify_backlog is enabled, we'll run the verify in this * handler as well. For that case, we may need up to twice the @@ -1215,7 +1195,7 @@ static int init_io_u(struct thread_data *td) if (td->o.odirect || td->o.mem_align || td->o.oatomic || td_ioengine_flagged(td, FIO_RAWIO)) - p = PAGE_ALIGN(td->orig_buffer) + td->o.mem_align; + p = PTR_ALIGN(td->orig_buffer, page_mask) + td->o.mem_align; else p = td->orig_buffer; @@ -1281,6 +1261,10 @@ static int init_io_u(struct thread_data *td) return 0; } +/* + * This function is Linux specific. + * FIO_HAVE_IOSCHED_SWITCH enabled currently means it's Linux. + */ static int switch_ioscheduler(struct thread_data *td) { #ifdef FIO_HAVE_IOSCHED_SWITCH @@ -1291,7 +1275,8 @@ static int switch_ioscheduler(struct thread_data *td) if (td_ioengine_flagged(td, FIO_DISKLESSIO)) return 0; - sprintf(tmp, "%s/queue/scheduler", td->sysfs_root); + assert(td->files && td->files[0]); + sprintf(tmp, "%s/queue/scheduler", td->files[0]->du->sysfs_root); f = fopen(tmp, "r+"); if (!f) { @@ -1370,8 +1355,8 @@ static bool keep_running(struct thread_data *td) if (exceeds_number_ios(td)) return false; - if (td->o.io_limit) - limit = td->o.io_limit; + if (td->o.io_size) + limit = td->o.io_size; else limit = td->o.size; @@ -1379,14 +1364,14 @@ static bool keep_running(struct thread_data *td) uint64_t diff; /* - * If the difference is less than the minimum IO size, we + * If the difference is less than the maximum IO size, we * are done. */ diff = limit - ddir_rw_sum(td->io_bytes); if (diff < td_max_bs(td)) return false; - if (fio_files_done(td) && !td->o.io_limit) + if (fio_files_done(td) && !td->o.io_size) return false; return true; @@ -1471,6 +1456,7 @@ static void *thread_main(void *data) struct thread_data *td = fd->td; struct thread_options *o = &td->o; struct sk_out *sk_out = fd->sk_out; + int deadlock_loop_cnt; int clear_state; int ret; @@ -1675,10 +1661,11 @@ static void *thread_main(void *data) if (rate_submit_init(td, sk_out)) goto err; - fio_gettime(&td->epoch, NULL); + set_epoch_time(td, o->log_unix_epoch); fio_getrusage(&td->ru_start); memcpy(&td->bw_sample_time, &td->epoch, sizeof(td->epoch)); memcpy(&td->iops_sample_time, &td->epoch, sizeof(td->epoch)); + memcpy(&td->ss.prev_time, &td->epoch, sizeof(td->epoch)); if (o->ratemin[DDIR_READ] || o->ratemin[DDIR_WRITE] || o->ratemin[DDIR_TRIM]) { @@ -1722,6 +1709,14 @@ static void *thread_main(void *data) } } + /* + * If we took too long to shut down, the main thread could + * already consider us reaped/exited. If that happens, break + * out and clean up. + */ + if (td->runstate >= TD_EXITED) + break; + clear_state = 1; /* @@ -1731,9 +1726,19 @@ static void *thread_main(void *data) * the rusage_sem, which would never get upped because * this thread is waiting for the stat mutex. */ - check_update_rusage(td); + deadlock_loop_cnt = 0; + do { + check_update_rusage(td); + if (!fio_mutex_down_trylock(stat_mutex)) + break; + usleep(1000); + if (deadlock_loop_cnt++ > 5000) { + log_err("fio seems to be stuck grabbing stat_mutex, forcibly exiting\n"); + td->error = EDEADLK; + goto err; + } + } while (1); - fio_mutex_down(stat_mutex); if (td_read(td) && td->io_bytes[DDIR_READ]) update_runtime(td, elapsed_us, DDIR_READ); if (td_write(td) && td->io_bytes[DDIR_WRITE]) @@ -1857,8 +1862,8 @@ static void dump_td_info(struct thread_data *td) /* * Run over the job map and reap the threads that have exited, if any. */ -static void reap_threads(unsigned int *nr_running, unsigned int *t_rate, - unsigned int *m_rate) +static void reap_threads(unsigned int *nr_running, uint64_t *t_rate, + uint64_t *m_rate) { struct thread_data *td; unsigned int cputhreads, realthreads, pending; @@ -2052,7 +2057,7 @@ static bool check_mount_writes(struct thread_data *td) return false; for_each_file(td, f, i) { - if (f->filetype != FIO_TYPE_BD) + if (f->filetype != FIO_TYPE_BLOCK) continue; if (device_is_mounted(f->file_name)) goto mounted; @@ -2060,7 +2065,7 @@ static bool check_mount_writes(struct thread_data *td) return false; mounted: - log_err("fio: %s appears mounted, and 'allow_mounted_write' isn't set. Aborting.", f->file_name); + log_err("fio: %s appears mounted, and 'allow_mounted_write' isn't set. Aborting.\n", f->file_name); return true; } @@ -2096,7 +2101,8 @@ static bool waitee_running(struct thread_data *me) static void run_threads(struct sk_out *sk_out) { struct thread_data *td; - unsigned int i, todo, nr_running, m_rate, t_rate, nr_started; + unsigned int i, todo, nr_running, nr_started; + uint64_t m_rate, t_rate; uint64_t spent; if (fio_gtod_offload && fio_start_gtod_thread()) @@ -2410,6 +2416,12 @@ int fio_backend(struct sk_out *sk_out) } 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); + } + } fio_options_free(td); if (td->rusage_sem) { fio_mutex_remove(td->rusage_sem);