t/nvmept_trim: increase transfer size for some tests
[fio.git] / helper_thread.c
index f6cdddb8f0532af5be1a0463bb7d9fadf694500f..332ccb53c254e45087919f9a1f758390a9873f2f 100644 (file)
@@ -1,11 +1,21 @@
+#include <errno.h>
 #include <signal.h>
+#include <stdio.h>
+#include <string.h>
 #include <unistd.h>
+#ifdef CONFIG_HAVE_TIMERFD_CREATE
+#include <sys/timerfd.h>
+#endif
 #ifdef CONFIG_VALGRIND_DEV
 #include <valgrind/drd.h>
 #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();