X-Git-Url: https://git.kernel.dk/?a=blobdiff_plain;f=helper_thread.c;h=f0c717f5026db994509d88f6d86d21cebc447c3a;hb=HEAD;hp=f6cdddb8f0532af5be1a0463bb7d9fadf694500f;hpb=df9bd7d452dfdcebfc1bdf317c74c3af09cc9719;p=fio.git diff --git a/helper_thread.c b/helper_thread.c index f6cdddb8..332ccb53 100644 --- a/helper_thread.c +++ b/helper_thread.c @@ -1,11 +1,21 @@ +#include #include +#include +#include #include +#ifdef CONFIG_HAVE_TIMERFD_CREATE +#include +#endif #ifdef CONFIG_VALGRIND_DEV #include #else #define DRD_IGNORE_VAR(x) do { } while (0) #endif +#ifdef WIN32 +#include "os/os-windows.h" +#endif + #include "fio.h" #include "smalloc.h" #include "helper_thread.h" @@ -13,6 +23,7 @@ #include "pshared.h" static int sleep_accuracy_ms; +static int timerfd = -1; enum action { A_EXIT = 1, @@ -95,13 +106,14 @@ static int read_from_pipe(int fd, void *buf, size_t len) static void block_signals(void) { -#ifdef HAVE_PTHREAD_SIGMASK +#ifdef CONFIG_PTHREAD_SIGMASK sigset_t sigmask; + int ret; + ret = pthread_sigmask(SIG_UNBLOCK, NULL, &sigmask); assert(ret == 0); ret = pthread_sigmask(SIG_BLOCK, &sigmask, NULL); - assert(ret == 0); #endif } @@ -114,7 +126,10 @@ static void submit_action(enum action a) return; ret = write_to_pipe(helper_data->pipe[1], &data, sizeof(data)); - assert(ret == 1); + if (ret != 1) { + log_err("failed to write action into pipe, err %i:%s", errno, strerror(errno)); + assert(0); + } } void helper_reset(void) @@ -146,7 +161,6 @@ void helper_thread_exit(void) return; helper_data->exit = 1; - submit_action(A_EXIT); pthread_join(helper_data->thread, NULL); } @@ -179,6 +193,7 @@ static uint8_t wait_for_action(int fd, unsigned int timeout_ms) }; fd_set rfds, efds; uint8_t action = 0; + uint64_t exp; int res; res = read_from_pipe(fd, &action, sizeof(action)); @@ -188,7 +203,25 @@ static uint8_t wait_for_action(int fd, unsigned int timeout_ms) FD_SET(fd, &rfds); FD_ZERO(&efds); FD_SET(fd, &efds); - res = select(fd + 1, &rfds, NULL, &efds, &timeout); +#ifdef CONFIG_HAVE_TIMERFD_CREATE + { + /* + * If the timer frequency is 100 Hz, select() will round up + * `timeout` to the next multiple of 1 / 100 Hz = 10 ms. Hence + * use a high-resolution timer if possible to increase + * select() timeout accuracy. + */ + struct itimerspec delta = {}; + + delta.it_value.tv_sec = timeout.tv_sec; + delta.it_value.tv_nsec = timeout.tv_usec * 1000; + res = timerfd_settime(timerfd, 0, &delta, NULL); + assert(res == 0); + FD_SET(timerfd, &rfds); + } +#endif + res = select(max(fd, timerfd) + 1, &rfds, NULL, &efds, + timerfd >= 0 ? NULL : &timeout); if (res < 0) { log_err("fio: select() call in helper thread failed: %s", strerror(errno)); @@ -196,6 +229,10 @@ static uint8_t wait_for_action(int fd, unsigned int timeout_ms) } if (FD_ISSET(fd, &rfds)) read_from_pipe(fd, &action, sizeof(action)); + if (timerfd >= 0 && FD_ISSET(timerfd, &rfds)) { + res = read(timerfd, &exp, sizeof(exp)); + assert(res == sizeof(exp)); + } return action; } @@ -250,35 +287,34 @@ static void *helper_thread_main(void *data) }, { .name = "steadystate", - .interval_ms = steadystate_enabled ? STEADYSTATE_MSEC : + .interval_ms = steadystate_enabled ? ss_check_interval : 0, .func = steadystate_check, } }; struct timespec ts; - int clk_tck, ret = 0; + long clk_tck; + int ret = 0; -#ifdef _SC_CLK_TCK - clk_tck = sysconf(_SC_CLK_TCK); -#else - /* - * The timer frequence is variable on Windows. Instead of trying to - * query it, use 64 Hz, the clock frequency lower bound. See also - * https://carpediemsystems.co.uk/2019/07/18/windows-system-timer-granularity/. - */ - clk_tck = 64; -#endif - dprint(FD_HELPERTHREAD, "clk_tck = %d\n", clk_tck); + os_clk_tck(&clk_tck); + + dprint(FD_HELPERTHREAD, "clk_tck = %ld\n", clk_tck); assert(clk_tck > 0); sleep_accuracy_ms = (1000 + clk_tck - 1) / clk_tck; +#ifdef CONFIG_HAVE_TIMERFD_CREATE + timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); + assert(timerfd >= 0); + sleep_accuracy_ms = 1; +#endif + sk_out_assign(hd->sk_out); /* Let another thread handle signals. */ block_signals(); fio_get_mono_time(&ts); - msec_to_next_event = reset_timers(timer, ARRAY_SIZE(timer), &ts); + msec_to_next_event = reset_timers(timer, FIO_ARRAY_SIZE(timer), &ts); fio_sem_up(hd->startup_sem); @@ -296,9 +332,9 @@ static void *helper_thread_main(void *data) if (action == A_RESET) msec_to_next_event = reset_timers(timer, - ARRAY_SIZE(timer), &ts); + FIO_ARRAY_SIZE(timer), &ts); - for (i = 0; i < ARRAY_SIZE(timer); ++i) + for (i = 0; i < FIO_ARRAY_SIZE(timer); ++i) ret = eval_timer(&timer[i], &ts, &msec_to_next_event); if (action == A_DO_STAT) @@ -317,6 +353,11 @@ static void *helper_thread_main(void *data) print_thread_status(); } + if (timerfd >= 0) { + close(timerfd); + timerfd = -1; + } + fio_writeout_logs(false); sk_out_drop();