X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=backend.c;h=faa861cf64d303e993d3fe2c3044dcda2b3367a4;hp=ec42a5cd23cc7e6e90c7c21206bcf8ff4f206c7a;hb=36d80bc7c7f7fbc2612941b7dd7ceaf645798c7f;hpb=a5e371a61c9e37a2389f7473d65e35b29dec1ccd diff --git a/backend.c b/backend.c index ec42a5cd..faa861cf 100644 --- a/backend.c +++ b/backend.c @@ -34,7 +34,9 @@ #include #include #include +#ifndef FIO_NO_HAVE_SHM_H #include +#endif #include #include "fio.h" @@ -50,6 +52,7 @@ #include "server.h" static pthread_t disk_util_thread; +static struct fio_mutex *disk_thread_mutex; static struct fio_mutex *startup_mutex; static struct fio_mutex *writeout_mutex; static struct flist_head *cgroup_list; @@ -57,15 +60,17 @@ static char *cgroup_mnt; static int exit_value; static volatile int fio_abort; -struct io_log *agg_io_log[2]; +struct io_log *agg_io_log[DDIR_RWDIR_CNT]; int groupid = 0; unsigned int thread_number = 0; +unsigned int stat_number = 0; unsigned int nr_process = 0; unsigned int nr_thread = 0; int shm_id = 0; int temp_stall_ts; unsigned long done_secs = 0; +volatile int disk_util_exit = 0; #define PAGE_ALIGN(buf) \ (char *) (((uintptr_t) (buf) + page_mask) & ~page_mask) @@ -87,6 +92,11 @@ static void sig_int(int sig) } } +static void sig_show_status(int sig) +{ + show_running_run_stats(); +} + static void set_sig_handlers(void) { struct sigaction act; @@ -101,6 +111,19 @@ static void set_sig_handlers(void) act.sa_flags = SA_RESTART; sigaction(SIGTERM, &act, NULL); +/* Windows uses SIGBREAK as a quit signal from other applications */ +#ifdef WIN32 + memset(&act, 0, sizeof(act)); + act.sa_handler = sig_int; + act.sa_flags = SA_RESTART; + sigaction(SIGBREAK, &act, NULL); +#endif + + memset(&act, 0, sizeof(act)); + act.sa_handler = sig_show_status; + act.sa_flags = SA_RESTART; + sigaction(SIGUSR1, &act, NULL); + if (is_backend) { memset(&act, 0, sizeof(act)); act.sa_handler = sig_int; @@ -197,10 +220,12 @@ static int check_min_rate(struct thread_data *td, struct timeval *now, { int ret = 0; - if (bytes_done[0]) - ret |= __check_min_rate(td, now, 0); - if (bytes_done[1]) - ret |= __check_min_rate(td, now, 1); + if (bytes_done[DDIR_READ]) + ret |= __check_min_rate(td, now, DDIR_READ); + if (bytes_done[DDIR_WRITE]) + ret |= __check_min_rate(td, now, DDIR_WRITE); + if (bytes_done[DDIR_TRIM]) + ret |= __check_min_rate(td, now, DDIR_TRIM); return ret; } @@ -324,17 +349,17 @@ static int break_on_this_error(struct thread_data *td, enum fio_ddir ddir, int ret = *retptr; if (ret < 0 || td->error) { - int err; + int err = td->error; + enum error_type_bit eb; if (ret < 0) err = -ret; - else - err = td->error; - if (!(td->o.continue_on_error & td_error_type(ddir, err))) + eb = td_error_type(ddir, err); + if (!(td->o.continue_on_error & (1 << eb))) return 1; - if (td_non_fatal_error(err)) { + if (td_non_fatal_error(td, eb, err)) { /* * Continue with the I/Os in case of * a non fatal error. @@ -534,11 +559,13 @@ static int io_bytes_exceeded(struct thread_data *td) unsigned long long bytes; if (td_rw(td)) - bytes = td->this_io_bytes[0] + td->this_io_bytes[1]; + bytes = td->this_io_bytes[DDIR_READ] + td->this_io_bytes[DDIR_WRITE]; else if (td_write(td)) - bytes = td->this_io_bytes[1]; + 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[0]; + bytes = td->this_io_bytes[DDIR_TRIM]; return bytes >= td->o.size; } @@ -561,13 +588,13 @@ static void do_io(struct thread_data *td) (!flist_empty(&td->trim_list)) || !io_bytes_exceeded(td) || td->o.time_based) { struct timeval comp_time; - unsigned long bytes_done[2] = { 0, 0 }; + unsigned long bytes_done[DDIR_RWDIR_CNT] = { 0, 0, 0 }; int min_evts = 0; struct io_u *io_u; int ret2, full; enum fio_ddir ddir; - if (td->terminate) + if (td->terminate || td->done) break; update_tv_cache(td); @@ -638,8 +665,9 @@ static void do_io(struct thread_data *td) requeue_io_u(td, &io_u); } else { sync_done: - if (__should_check_rate(td, 0) || - __should_check_rate(td, 1)) + if (__should_check_rate(td, DDIR_READ) || + __should_check_rate(td, DDIR_WRITE) || + __should_check_rate(td, DDIR_TRIM)) fio_gettime(&comp_time, NULL); ret = io_u_sync_complete(td, io_u, bytes_done); @@ -686,8 +714,9 @@ sync_done: if (full && !min_evts) min_evts = 1; - if (__should_check_rate(td, 0) || - __should_check_rate(td, 1)) + if (__should_check_rate(td, DDIR_READ) || + __should_check_rate(td, DDIR_WRITE) || + __should_check_rate(td, DDIR_TRIM)) fio_gettime(&comp_time, NULL); do { @@ -700,7 +729,7 @@ sync_done: if (ret < 0) break; - if (!(bytes_done[0] + bytes_done[1])) + if (!ddir_rw_sum(bytes_done) && !(td->io_ops->flags & FIO_NOIO)) continue; if (!in_ramp_time(td) && should_check_rate(td, bytes_done)) { @@ -715,7 +744,7 @@ sync_done: if (td->o.thinktime) { unsigned long long b; - b = td->io_blocks[0] + td->io_blocks[1]; + b = ddir_rw_sum(td->io_blocks); if (!(b % td->o.thinktime_blocks)) { int left; @@ -761,7 +790,7 @@ sync_done: /* * stop job if we failed doing any IO */ - if ((td->this_io_bytes[0] + td->this_io_bytes[1]) == 0) + if (!ddir_rw_sum(td->this_io_bytes)) td->done = 1; } @@ -785,14 +814,19 @@ 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; char *p; max_units = td->o.iodepth; max_bs = max(td->o.max_bs[DDIR_READ], td->o.max_bs[DDIR_WRITE]); + max_bs = max(td->o.max_bs[DDIR_TRIM], max_bs); min_write = td->o.min_bs[DDIR_WRITE]; td->orig_buffer_size = (unsigned long long) max_bs * (unsigned long long) max_units; + if ((td->io_ops->flags & FIO_NOIO) || !(td_read(td) || td_write(td))) + data_xfer = 0; + if (td->o.mem_type == MEM_SHMHUGE || td->o.mem_type == MEM_MMAPHUGE) { unsigned long bs; @@ -805,7 +839,7 @@ static int init_io_u(struct thread_data *td) return 1; } - if (allocate_io_mem(td)) + if (data_xfer && allocate_io_mem(td)) return 1; if (td->o.odirect || td->o.mem_align || @@ -833,7 +867,7 @@ static int init_io_u(struct thread_data *td) INIT_FLIST_HEAD(&io_u->list); dprint(FD_MEM, "io_u alloc %p, index %u\n", io_u, i); - if (!(td->io_ops->flags & FIO_NOIO)) { + if (data_xfer) { io_u->buf = p; dprint(FD_MEM, "io_u %p, mem %p\n", io_u, io_u->buf); @@ -915,8 +949,6 @@ static int switch_ioscheduler(struct thread_data *td) static int keep_running(struct thread_data *td) { - unsigned long long io_done; - if (td->done) return 0; if (td->o.time_based) @@ -926,9 +958,7 @@ static int keep_running(struct thread_data *td) return 1; } - io_done = td->io_bytes[DDIR_READ] + td->io_bytes[DDIR_WRITE] - + td->io_skip_bytes; - if (io_done < td->o.size) + if (ddir_rw_sum(td->io_bytes) < td->o.size) return 1; return 0; @@ -1025,6 +1055,49 @@ static void *thread_main(void *data) goto err; } +#ifdef FIO_HAVE_LIBNUMA + /* numa node setup */ + if (td->o.numa_cpumask_set || td->o.numa_memmask_set) { + int ret; + + if (numa_available() < 0) { + td_verror(td, errno, "Does not support NUMA API\n"); + goto err; + } + + if (td->o.numa_cpumask_set) { + ret = numa_run_on_node_mask(td->o.numa_cpunodesmask); + if (ret == -1) { + td_verror(td, errno, \ + "numa_run_on_node_mask failed\n"); + goto err; + } + } + + if (td->o.numa_memmask_set) { + + switch (td->o.numa_mem_mode) { + case MPOL_INTERLEAVE: + numa_set_interleave_mask(td->o.numa_memnodesmask); + break; + case MPOL_BIND: + numa_set_membind(td->o.numa_memnodesmask); + break; + case MPOL_LOCAL: + numa_set_localalloc(); + break; + case MPOL_PREFERRED: + numa_set_preferred(td->o.numa_mem_prefer_node); + break; + case MPOL_DEFAULT: + default: + break; + } + + } + } +#endif + /* * May alter parameters that init_io_u() will use, so we need to * do this first. @@ -1045,7 +1118,7 @@ static void *thread_main(void *data) } } - if (td->o.cgroup_weight && cgroup_setup(td, cgroup_list, &cgroup_mnt)) + if (td->o.cgroup && cgroup_setup(td, cgroup_list, &cgroup_mnt)) goto err; errno = 0; @@ -1086,10 +1159,13 @@ static void *thread_main(void *data) memcpy(&td->iops_sample_time, &td->start, sizeof(td->start)); memcpy(&td->tv_cache, &td->start, sizeof(td->start)); - if (td->o.ratemin[0] || td->o.ratemin[1]) { - memcpy(&td->lastrate[0], &td->bw_sample_time, + if (td->o.ratemin[DDIR_READ] || td->o.ratemin[DDIR_WRITE] || + td->o.ratemin[DDIR_TRIM]) { + memcpy(&td->lastrate[DDIR_READ], &td->bw_sample_time, + sizeof(td->bw_sample_time)); + memcpy(&td->lastrate[DDIR_WRITE], &td->bw_sample_time, sizeof(td->bw_sample_time)); - memcpy(&td->lastrate[1], &td->bw_sample_time, + memcpy(&td->lastrate[DDIR_TRIM], &td->bw_sample_time, sizeof(td->bw_sample_time)); } @@ -1110,6 +1186,10 @@ static void *thread_main(void *data) elapsed = utime_since_now(&td->start); td->ts.runtime[DDIR_WRITE] += elapsed; } + if (td_trim(td) && td->io_bytes[DDIR_TRIM]) { + elapsed = utime_since_now(&td->start); + td->ts.runtime[DDIR_TRIM] += elapsed; + } if (td->error || td->terminate) break; @@ -1132,11 +1212,13 @@ static void *thread_main(void *data) } update_rusage_stat(td); - td->ts.runtime[0] = (td->ts.runtime[0] + 999) / 1000; - td->ts.runtime[1] = (td->ts.runtime[1] + 999) / 1000; + td->ts.runtime[DDIR_READ] = (td->ts.runtime[DDIR_READ] + 999) / 1000; + td->ts.runtime[DDIR_WRITE] = (td->ts.runtime[DDIR_WRITE] + 999) / 1000; + td->ts.runtime[DDIR_TRIM] = (td->ts.runtime[DDIR_TRIM] + 999) / 1000; td->ts.total_run_time = mtime_since_now(&td->epoch); - td->ts.io_bytes[0] = td->io_bytes[0]; - td->ts.io_bytes[1] = td->io_bytes[1]; + td->ts.io_bytes[DDIR_READ] = td->io_bytes[DDIR_READ]; + td->ts.io_bytes[DDIR_WRITE] = td->io_bytes[DDIR_WRITE]; + td->ts.io_bytes[DDIR_TRIM] = td->io_bytes[DDIR_TRIM]; fio_mutex_down(writeout_mutex); if (td->bw_log) { @@ -1303,7 +1385,7 @@ static void reap_threads(unsigned int *nr_running, unsigned int *t_rate, if (WIFSIGNALED(status)) { int sig = WTERMSIG(status); - if (sig != SIGTERM) + if (sig != SIGTERM && sig != SIGUSR2) log_err("fio: pid=%d, got signal=%d\n", (int) td->pid, sig); td->sig = sig; @@ -1326,8 +1408,8 @@ static void reap_threads(unsigned int *nr_running, unsigned int *t_rate, continue; reaped: (*nr_running)--; - (*m_rate) -= (td->o.ratemin[0] + td->o.ratemin[1]); - (*t_rate) -= (td->o.rate[0] + td->o.rate[1]); + (*m_rate) -= ddir_rw_sum(td->o.ratemin); + (*t_rate) -= ddir_rw_sum(td->o.rate); if (!td->pid) pending--; @@ -1358,7 +1440,7 @@ static void run_threads(void) set_sig_handlers(); - if (!terse_output) { + if (output_format == FIO_OUTPUT_NORMAL) { log_info("Starting "); if (nr_thread) log_info("%d thread%s", nr_thread, @@ -1549,8 +1631,8 @@ static void run_threads(void) td_set_runstate(td, TD_RUNNING); nr_running++; nr_started--; - m_rate += td->o.ratemin[0] + td->o.ratemin[1]; - t_rate += td->o.rate[0] + td->o.rate[1]; + m_rate += ddir_rw_sum(td->o.ratemin); + t_rate += ddir_rw_sum(td->o.rate); todo--; fio_mutex_up(td->mutex); } @@ -1578,20 +1660,35 @@ static void run_threads(void) fio_unpin_memory(); } +void wait_for_disk_thread_exit(void) +{ + fio_mutex_down(disk_thread_mutex); +} + +static void free_disk_util(void) +{ + disk_util_start_exit(); + wait_for_disk_thread_exit(); + disk_util_prune_entries(); +} + static void *disk_thread_main(void *data) { + int ret = 0; + fio_mutex_up(startup_mutex); - while (threads) { + while (threads && !ret) { usleep(DISK_UTIL_MSEC * 1000); if (!threads) break; - update_io_ticks(); + ret = update_io_ticks(); if (!is_backend) print_thread_status(); } + fio_mutex_up(disk_thread_mutex); return NULL; } @@ -1599,14 +1696,20 @@ static int create_disk_util_thread(void) { int ret; + setup_disk_util(); + + disk_thread_mutex = fio_mutex_init(FIO_MUTEX_LOCKED); + ret = pthread_create(&disk_util_thread, NULL, disk_thread_main, NULL); if (ret) { + fio_mutex_remove(disk_thread_mutex); log_err("Can't create disk util thread: %s\n", strerror(ret)); return 1; } ret = pthread_detach(disk_util_thread); if (ret) { + fio_mutex_remove(disk_thread_mutex); log_err("Can't detatch disk util thread: %s\n", strerror(ret)); return 1; } @@ -1634,12 +1737,13 @@ int fio_backend(void) if (write_bw_log) { setup_log(&agg_io_log[DDIR_READ], 0); setup_log(&agg_io_log[DDIR_WRITE], 0); + setup_log(&agg_io_log[DDIR_TRIM], 0); } - startup_mutex = fio_mutex_init(0); + startup_mutex = fio_mutex_init(FIO_MUTEX_LOCKED); if (startup_mutex == NULL) return 1; - writeout_mutex = fio_mutex_init(1); + writeout_mutex = fio_mutex_init(FIO_MUTEX_UNLOCKED); if (writeout_mutex == NULL) return 1; @@ -1657,17 +1761,21 @@ int fio_backend(void) __finish_log(agg_io_log[DDIR_READ], "agg-read_bw.log"); __finish_log(agg_io_log[DDIR_WRITE], "agg-write_bw.log"); + __finish_log(agg_io_log[DDIR_TRIM], + "agg-write_bw.log"); } } for_each_td(td, i) fio_options_free(td); + free_disk_util(); cgroup_kill(cgroup_list); sfree(cgroup_list); sfree(cgroup_mnt); fio_mutex_remove(startup_mutex); fio_mutex_remove(writeout_mutex); + fio_mutex_remove(disk_thread_mutex); return exit_value; }