Query Windows clock frequency and use reported max
authorBrandon Paupore <brandon.paupore@wdc.com>
Tue, 12 Oct 2021 19:00:41 +0000 (14:00 -0500)
committerBrandon Paupore <brandon.paupore@wdc.com>
Tue, 12 Oct 2021 19:00:51 +0000 (14:00 -0500)
Previously FIO used the Windows lower-bound clock frequency of 64 Hz for
its helper-thread. This caused IOPS/BW logs to have large drift between
timestamps when not using per-unit logging for those measurements.

Now query the current resolution and set to use the maximum for more
accurate timestamps. Note that the resolution is automatically restored
after FIO terminates.

Signed-off-by: Brandon Paupore <brandon.paupore@wdc.com>
Makefile
helper_thread.c
os/os.h
os/windows/dlls.c [new file with mode: 0644]
stat.c

index 5198f70e1aa8ada287da3d1fc03eab6c2265f0f3..c3feb53f1615014cd9c415be3c80ef3bb1fd33c8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -275,8 +275,8 @@ ifeq ($(CONFIG_TARGET_OS), Darwin)
   LIBS  += -lpthread -ldl
 endif
 ifneq (,$(findstring CYGWIN,$(CONFIG_TARGET_OS)))
-  SOURCE += os/windows/cpu-affinity.c os/windows/posix.c
-  WINDOWS_OBJS = os/windows/cpu-affinity.o os/windows/posix.o lib/hweight.o
+  SOURCE += os/windows/cpu-affinity.c os/windows/posix.c os/windows/dlls.c
+  WINDOWS_OBJS = os/windows/cpu-affinity.o os/windows/posix.o os/windows/dlls.o lib/hweight.o
   LIBS  += -lpthread -lpsapi -lws2_32 -lssp
   FIO_CFLAGS += -DPSAPI_VERSION=1 -Ios/windows/posix/include -Wno-format
 endif
index d8e7ebfe573ef5531fb2c60d00e87e4cb2127308..b9b83db3057435f6fd2918d84cc3e96bdb7c4252 100644 (file)
@@ -9,6 +9,10 @@
 #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"
@@ -283,19 +287,12 @@ static void *helper_thread_main(void *data)
                }
        };
        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;
 
diff --git a/os/os.h b/os/os.h
index 827b61e90d745211edb0635a028342ca7da42361..5965d7b806b055bf8f2c679da818516a503eb6db 100644 (file)
--- a/os/os.h
+++ b/os/os.h
@@ -412,4 +412,13 @@ static inline bool os_cpu_has(cpu_features feature)
 # define fio_mkdir(path, mode) mkdir(path, mode)
 #endif
 
+#ifdef _SC_CLK_TCK
+static inline void os_clk_tck(long *clk_tck)
+{
+       *clk_tck = sysconf(_SC_CLK_TCK);
+}
+#else
+extern void os_clk_tck(long *clk_tck);
+#endif
+
 #endif /* FIO_OS_H */
diff --git a/os/windows/dlls.c b/os/windows/dlls.c
new file mode 100644 (file)
index 0000000..774b1c6
--- /dev/null
@@ -0,0 +1,33 @@
+#include "os/os.h"
+
+#include <windows.h>
+
+void os_clk_tck(long *clk_tck)
+{
+       /*
+        * The timer resolution is variable on Windows. Try to query it 
+        * or use 64 Hz, the clock frequency lower bound. See also
+        * https://carpediemsystems.co.uk/2019/07/18/windows-system-timer-granularity/.
+        */
+       unsigned long minRes, maxRes, curRes;
+       HMODULE lib;
+       FARPROC queryTimer;
+       FARPROC setTimer;
+
+       if (!(lib = LoadLibrary(TEXT("ntdll.dll"))) ||
+               !(queryTimer = GetProcAddress(lib, "NtQueryTimerResolution")) ||
+               !(setTimer = GetProcAddress(lib, "NtSetTimerResolution"))) {
+               dprint(FD_HELPERTHREAD, 
+                       "Failed to load ntdll library, set to lower bound 64 Hz\n");
+               *clk_tck = 64;
+       } else {
+               queryTimer(&minRes, &maxRes, &curRes);
+               dprint(FD_HELPERTHREAD, 
+                       "minRes = %lu, maxRes = %lu, curRes = %lu\n",
+                       minRes, maxRes, curRes);
+
+               /* Use maximum resolution for most accurate timestamps */
+               setTimer(maxRes, 1, &curRes);
+               *clk_tck = (long) (10000000L / maxRes);
+       }
+}
\ No newline at end of file
diff --git a/stat.c b/stat.c
index ac53463d04642026512d8e9db961483c29dee1fe..30f9b5c1e995d49174aebc2fd48ebe6e51d34acf 100644 (file)
--- a/stat.c
+++ b/stat.c
 #include "zbd.h"
 #include "oslib/asprintf.h"
 
+#ifdef WIN32
+#define LOG_MSEC_SLACK 2
+#else
 #define LOG_MSEC_SLACK 1
+#endif
 
 struct fio_sem *stat_sem;