summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.appveyor.yml40
-rwxr-xr-xFIO-VERSION-GEN2
-rw-r--r--HOWTO24
-rw-r--r--Makefile117
-rw-r--r--backend.c5
-rwxr-xr-xci/appveyor-install.sh41
-rwxr-xr-xci/travis-build.sh8
-rwxr-xr-xci/travis-install.sh5
-rwxr-xr-xconfigure140
-rw-r--r--engines/glusterfs.c3
-rw-r--r--engines/ime.c3
-rw-r--r--engines/io_uring.c2
-rw-r--r--engines/libhdfs.c4
-rw-r--r--engines/libpmem.c1
-rw-r--r--engines/net.c5
-rw-r--r--engines/posixaio.c41
-rw-r--r--engines/windowsaio.c8
-rw-r--r--eta.c71
-rw-r--r--filesetup.c6
-rw-r--r--fio.128
-rw-r--r--fio.h27
-rw-r--r--fio_time.h2
-rw-r--r--flow.c6
-rw-r--r--gettime-thread.c2
-rw-r--r--gettime.c76
-rw-r--r--gettime.h1
-rw-r--r--goptions.c2
-rw-r--r--helper_thread.c285
-rw-r--r--init.c142
-rw-r--r--ioengines.c44
-rw-r--r--ioengines.h5
-rw-r--r--iolog.h1
-rw-r--r--libfio.c5
-rw-r--r--options.c26
-rw-r--r--os/os-linux.h2
-rw-r--r--os/os-mac.h6
-rw-r--r--os/os.h4
-rw-r--r--os/windows/cpu-affinity.c26
-rw-r--r--os/windows/dobuild.cmd10
-rwxr-xr-xos/windows/install.wxs8
-rw-r--r--os/windows/posix.c5
-rw-r--r--oslib/getopt_long.c4
-rw-r--r--parse.h2
-rw-r--r--server.c2
-rw-r--r--stat.c12
-rw-r--r--stat.h2
-rw-r--r--steadystate.c3
-rw-r--r--steadystate.h2
-rwxr-xr-xt/latency_percentiles.py4
-rw-r--r--t/memlock.c2
-rwxr-xr-xt/zbd/test-zbd-support2
-rw-r--r--zbd.c3
52 files changed, 775 insertions, 502 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
index 352caeee..fad16326 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -5,33 +5,49 @@ image:
environment:
CYG_MIRROR: http://cygwin.mirror.constant.com
- CYG_ROOT: C:\cygwin64
- MAKEFLAGS: -j 2
matrix:
- - platform: x64
- PACKAGE_ARCH: x86_64
+ - ARCHITECTURE: x64
+ CC: clang
+ CONFIGURE_OPTIONS: --enable-pdb
+ DISTRO: msys2
+# Skip 32 bit clang build
+# - ARCHITECTURE: x86
+# CC: clang
+# CONFIGURE_OPTIONS: --enable-pdb
+# DISTRO: msys2
+ - ARCHITECTURE: x64
CONFIGURE_OPTIONS:
- - platform: x86
- PACKAGE_ARCH: i686
+ DISTRO: cygwin
+ - ARCHITECTURE: x86
CONFIGURE_OPTIONS: --build-32bit-win --target-win-ver=xp
+ DISTRO: cygwin
install:
- - '%CYG_ROOT%\setup-x86_64.exe --quiet-mode --no-shortcuts --only-site --site "%CYG_MIRROR%" --packages "mingw64-%PACKAGE_ARCH%-zlib,mingw64-%PACKAGE_ARCH%-CUnit" > NUL'
- - SET PATH=C:\Python38-x64;%CYG_ROOT%\bin;%PATH% # NB: Changed env variables persist to later sections
+ - if %DISTRO%==cygwin (
+ SET "PATH=C:\cygwin64\bin;C:\cygwin64;%PATH%"
+ )
+ - if %DISTRO%==msys2 if %ARCHITECTURE%==x86 (
+ SET "PATH=C:\msys64\mingw32\bin;C:\msys64\usr\bin;%PATH%"
+ )
+ - if %DISTRO%==msys2 if %ARCHITECTURE%==x64 (
+ SET "PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%"
+ )
+ - SET PATH=C:\Python38-x64;%PATH% # NB: Changed env variables persist to later sections
- SET PYTHONUNBUFFERED=TRUE
- - python.exe -m pip install scipy six
+ - bash.exe ci\appveyor-install.sh
build_script:
- - 'bash.exe -lc "cd \"${APPVEYOR_BUILD_FOLDER}\" && ./configure --disable-native --extra-cflags=\"-Werror\" ${CONFIGURE_OPTIONS} && make.exe'
+ - bash.exe configure --extra-cflags=-Werror --disable-native %CONFIGURE_OPTIONS%
+ - make.exe -j2
after_build:
- file.exe fio.exe
- make.exe test
- - 'cd os\windows && dobuild.cmd %PLATFORM% && cd ..'
+ - 'cd os\windows && dobuild.cmd %ARCHITECTURE% && cd ..'
- ps: Get-ChildItem .\os\windows\*.msi | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name -DeploymentName fio.msi }
test_script:
- - 'bash.exe -lc "cd \"${APPVEYOR_BUILD_FOLDER}\" && [ -f fio.exe ] && python.exe t/run-fio-tests.py --artifact-root test-artifacts --debug'
+ - python.exe t/run-fio-tests.py --artifact-root test-artifacts --debug
on_finish:
- 'bash.exe -lc "cd \"${APPVEYOR_BUILD_FOLDER}\" && [ -d test-artifacts ] && 7z a -t7z test-artifacts.7z test-artifacts -xr!foo.0.0 -xr!latency.?.0 -xr!fio_jsonplus_clat2csv.test && appveyor PushArtifact test-artifacts.7z'
diff --git a/FIO-VERSION-GEN b/FIO-VERSION-GEN
index 5ee7735c..86ea0c5d 100755
--- a/FIO-VERSION-GEN
+++ b/FIO-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=FIO-VERSION-FILE
-DEF_VER=fio-3.23
+DEF_VER=fio-3.24
LF='
'
diff --git a/HOWTO b/HOWTO
index 2d8c7a02..386fd12a 100644
--- a/HOWTO
+++ b/HOWTO
@@ -1677,10 +1677,28 @@ Buffers and memory
This will be ignored if :option:`pre_read` is also specified for the
same job.
-.. option:: sync=bool
+.. option:: sync=str
+
+ Whether, and what type, of synchronous I/O to use for writes. The allowed
+ values are:
+
+ **none**
+ Do not use synchronous IO, the default.
+
+ **0**
+ Same as **none**.
+
+ **sync**
+ Use synchronous file IO. For the majority of I/O engines,
+ this means using O_SYNC.
+
+ **1**
+ Same as **sync**.
+
+ **dsync**
+ Use synchronous data IO. For the majority of I/O engines,
+ this means using O_DSYNC.
- Use synchronous I/O for buffered writes. For the majority of I/O engines,
- this means using O_SYNC. Default: false.
.. option:: iomem=str, mem=str
diff --git a/Makefile b/Makefile
index b00daca2..ecfaa3e0 100644
--- a/Makefile
+++ b/Makefile
@@ -22,16 +22,22 @@ endif
DEBUGFLAGS = -DFIO_INC_DEBUG
CPPFLAGS= -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DFIO_INTERNAL $(DEBUGFLAGS)
OPTFLAGS= -g -ffast-math
-CFLAGS := -std=gnu99 -Wwrite-strings -Wall -Wdeclaration-after-statement $(OPTFLAGS) $(EXTFLAGS) $(BUILD_CFLAGS) -I. -I$(SRCDIR) $(CFLAGS)
+FIO_CFLAGS= -std=gnu99 -Wwrite-strings -Wall -Wdeclaration-after-statement $(OPTFLAGS) $(EXTFLAGS) $(BUILD_CFLAGS) -I. -I$(SRCDIR)
LIBS += -lm $(EXTLIBS)
PROGS = fio
SCRIPTS = $(addprefix $(SRCDIR)/,tools/fio_generate_plots tools/plot/fio2gnuplot tools/genfio tools/fiologparser.py tools/hist/fiologparser_hist.py tools/hist/fio-histo-log-pctiles.py tools/fio_jsonplus_clat2csv)
ifndef CONFIG_FIO_NO_OPT
- CFLAGS := -O3 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $(CFLAGS)
+ FIO_CFLAGS += -O3 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2
endif
ifdef CONFIG_BUILD_NATIVE
- CFLAGS := -march=native $(CFLAGS)
+ FIO_CFLAGS += -march=native
+endif
+
+ifdef CONFIG_PDB
+ LINK_PDBFILE ?= -Wl,-pdb,$(dir $@)/$(basename $(@F)).pdb
+ FIO_CFLAGS += -gcodeview
+ LDFLAGS += -fuse-ld=lld $(LINK_PDBFILE)
endif
ifdef CONFIG_GFIO
@@ -54,16 +60,16 @@ SOURCE := $(sort $(patsubst $(SRCDIR)/%,%,$(wildcard $(SRCDIR)/crc/*.c)) \
ifdef CONFIG_LIBHDFS
HDFSFLAGS= -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/linux -I $(FIO_LIBHDFS_INCLUDE)
- HDFSLIB= -Wl,-rpath $(JAVA_HOME)/jre/lib/$(FIO_HDFS_CPU)/server -L$(JAVA_HOME)/jre/lib/$(FIO_HDFS_CPU)/server $(FIO_LIBHDFS_LIB)/libhdfs.a -ljvm
- CFLAGS := $(HDFSFLAGS) $(CFLAGS)
+ HDFSLIB= -Wl,-rpath $(JAVA_HOME)/lib/$(FIO_HDFS_CPU)/server -L$(JAVA_HOME)/lib/$(FIO_HDFS_CPU)/server $(FIO_LIBHDFS_LIB)/libhdfs.a -ljvm
+ FIO_CFLAGS += $(HDFSFLAGS)
SOURCE += engines/libhdfs.c
endif
ifdef CONFIG_LIBISCSI
- iscsi_SRCS = engines/libiscsi.c
- iscsi_LIBS = $(LIBISCSI_LIBS)
- iscsi_CFLAGS = $(LIBISCSI_CFLAGS)
- ENGINES += iscsi
+ libiscsi_SRCS = engines/libiscsi.c
+ libiscsi_LIBS = $(LIBISCSI_LIBS)
+ libiscsi_CFLAGS = $(LIBISCSI_CFLAGS)
+ ENGINES += libiscsi
endif
ifdef CONFIG_LIBNBD
@@ -74,20 +80,14 @@ ifdef CONFIG_LIBNBD
endif
ifdef CONFIG_64BIT
- CFLAGS := -DBITS_PER_LONG=64 $(CFLAGS)
-endif
-ifdef CONFIG_32BIT
- CFLAGS := -DBITS_PER_LONG=32 $(CFLAGS)
+ CPPFLAGS += -DBITS_PER_LONG=64
+else ifdef CONFIG_32BIT
+ CPPFLAGS += -DBITS_PER_LONG=32
endif
ifdef CONFIG_LIBAIO
- aio_SRCS = engines/libaio.c
- aio_LIBS = -laio
- ifdef CONFIG_LIBAIO_URING
- aio_LIBS = -luring
- else
- aio_LIBS = -laio
- endif
- ENGINES += aio
+ libaio_SRCS = engines/libaio.c
+ libaio_LIBS = -laio
+ ENGINES += libaio
endif
ifdef CONFIG_RDMA
rdma_SRCS = engines/rdma.c
@@ -155,7 +155,7 @@ ifdef CONFIG_GFAPI
SOURCE += engines/glusterfs_async.c
LIBS += -lgfapi -lglusterfs
ifdef CONFIG_GF_FADVISE
- CFLAGS := "-DGFAPI_USE_FADVISE" $(CFLAGS)
+ FIO_CFLAGS += "-DGFAPI_USE_FADVISE"
endif
endif
ifdef CONFIG_MTD
@@ -174,17 +174,17 @@ ifdef CONFIG_LINUX_DEVDAX
ENGINES += dev-dax
endif
ifdef CONFIG_LIBPMEM
- pmem_SRCS = engines/libpmem.c
- pmem_LIBS = -lpmem
- ENGINES += pmem
+ libpmem_SRCS = engines/libpmem.c
+ libpmem_LIBS = -lpmem
+ ENGINES += libpmem
endif
ifdef CONFIG_IME
SOURCE += engines/ime.c
endif
ifdef CONFIG_LIBZBC
- zbc_SRCS = engines/libzbc.c
- zbc_LIBS = -lzbc
- ENGINES += zbc
+ libzbc_SRCS = engines/libzbc.c
+ libzbc_LIBS = -lzbc
+ ENGINES += libzbc
endif
ifeq ($(CONFIG_TARGET_OS), Linux)
@@ -234,7 +234,7 @@ ifeq ($(CONFIG_TARGET_OS), AIX)
endif
ifeq ($(CONFIG_TARGET_OS), HP-UX)
LIBS += -lpthread -ldl -lrt
- CFLAGS := -D_LARGEFILE64_SOURCE -D_XOPEN_SOURCE_EXTENDED $(CFLAGS)
+ FIO_CFLAGS += -D_LARGEFILE64_SOURCE -D_XOPEN_SOURCE_EXTENDED
endif
ifeq ($(CONFIG_TARGET_OS), Darwin)
LIBS += -lpthread -ldl
@@ -243,7 +243,7 @@ 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
LIBS += -lpthread -lpsapi -lws2_32 -lssp
- CFLAGS := -DPSAPI_VERSION=1 -Ios/windows/posix/include -Wno-format $(CFLAGS)
+ FIO_CFLAGS += -DPSAPI_VERSION=1 -Ios/windows/posix/include -Wno-format
endif
ifdef CONFIG_DYNAMIC_ENGINES
@@ -251,19 +251,24 @@ ifdef CONFIG_DYNAMIC_ENGINES
define engine_template =
$(1)_OBJS := $$($(1)_SRCS:.c=.o)
$$($(1)_OBJS): CFLAGS := -fPIC $$($(1)_CFLAGS) $(CFLAGS)
-engines/lib$(1).so: $$($(1)_OBJS)
- $$(QUIET_LINK)$(CC) -shared -rdynamic -fPIC -Wl,-soname,lib$(1).so.1 $$($(1)_LIBS) -o $$@ $$<
-ENGS_OBJS += engines/lib$(1).so
-all install: $(ENGS_OBJS)
+engines/fio-$(1).so: $$($(1)_OBJS)
+ $$(QUIET_LINK)$(CC) -shared -rdynamic -fPIC -Wl,-soname,fio-$(1).so.1 -o $$@ $$< $$($(1)_LIBS)
+ENGS_OBJS += engines/fio-$(1).so
endef
else # !CONFIG_DYNAMIC_ENGINES
define engine_template =
SOURCE += $$($(1)_SRCS)
LIBS += $$($(1)_LIBS)
-CFLAGS := $$($(1)_CFLAGS) $(CFLAGS)
+CFLAGS += $$($(1)_CFLAGS)
endef
endif
+FIO-VERSION-FILE: FORCE
+ @$(SHELL) $(SRCDIR)/FIO-VERSION-GEN
+-include FIO-VERSION-FILE
+
+override CFLAGS := -DFIO_VERSION='"$(FIO_VERSION)"' $(FIO_CFLAGS) $(CFLAGS)
+
$(foreach eng,$(ENGINES),$(eval $(call engine_template,$(eng))))
OBJS := $(SOURCE:.c=.o)
@@ -427,17 +432,11 @@ mandir = $(prefix)/man
sharedir = $(prefix)/share/fio
endif
-all: $(PROGS) $(T_TEST_PROGS) $(UT_PROGS) $(SCRIPTS) FORCE
+all: $(PROGS) $(T_TEST_PROGS) $(UT_PROGS) $(SCRIPTS) $(ENGS_OBJS) FORCE
.PHONY: all install clean test
.PHONY: FORCE cscope
-FIO-VERSION-FILE: FORCE
- @$(SHELL) $(SRCDIR)/FIO-VERSION-GEN
--include FIO-VERSION-FILE
-
-override CFLAGS := -DFIO_VERSION='"$(FIO_VERSION)"' $(CFLAGS)
-
%.o : %.c
@mkdir -p $(dir $@)
$(QUIET_CC)$(CC) -o $@ $(CFLAGS) $(CPPFLAGS) -c $<
@@ -478,7 +477,7 @@ lexer.h: lex.yy.c
exp/test-expression-parser.o: exp/test-expression-parser.c
$(QUIET_CC)$(CC) -o $@ $(CFLAGS) $(CPPFLAGS) -c $<
exp/test-expression-parser: exp/test-expression-parser.o
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) $< y.tab.o lex.yy.o -o $@ $(LIBS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) $< y.tab.o lex.yy.o -o $@ $(LIBS)
parse.o: lex.yy.o y.tab.o
endif
@@ -514,55 +513,55 @@ printing.o: printing.c printing.h
t/io_uring.o: os/linux/io_uring.h
t/io_uring: $(T_IOU_RING_OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_IOU_RING_OBJS) $(LIBS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $(T_IOU_RING_OBJS) $(LIBS)
t/read-to-pipe-async: $(T_PIPE_ASYNC_OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_PIPE_ASYNC_OBJS) $(LIBS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $(T_PIPE_ASYNC_OBJS) $(LIBS)
t/memlock: $(T_MEMLOCK_OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_MEMLOCK_OBJS) $(LIBS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $(T_MEMLOCK_OBJS) $(LIBS)
t/stest: $(T_SMALLOC_OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_SMALLOC_OBJS) $(LIBS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $(T_SMALLOC_OBJS) $(LIBS)
t/ieee754: $(T_IEEE_OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_IEEE_OBJS) $(LIBS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $(T_IEEE_OBJS) $(LIBS)
fio: $(FIO_OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(FIO_OBJS) $(LIBS) $(HDFSLIB)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $(FIO_OBJS) $(LIBS) $(HDFSLIB)
gfio: $(GFIO_OBJS)
$(QUIET_LINK)$(CC) $(filter-out -static, $(LDFLAGS)) -o gfio $(GFIO_OBJS) $(LIBS) $(GFIO_LIBS) $(GTK_LDFLAGS) $(HDFSLIB)
t/fio-genzipf: $(T_ZIPF_OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_ZIPF_OBJS) $(LIBS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $(T_ZIPF_OBJS) $(LIBS)
t/axmap: $(T_AXMAP_OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_AXMAP_OBJS) $(LIBS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $(T_AXMAP_OBJS) $(LIBS)
t/lfsr-test: $(T_LFSR_TEST_OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_LFSR_TEST_OBJS) $(LIBS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $(T_LFSR_TEST_OBJS) $(LIBS)
t/gen-rand: $(T_GEN_RAND_OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_GEN_RAND_OBJS) $(LIBS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $(T_GEN_RAND_OBJS) $(LIBS)
ifeq ($(CONFIG_TARGET_OS), Linux)
t/fio-btrace2fio: $(T_BTRACE_FIO_OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_BTRACE_FIO_OBJS) $(LIBS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $(T_BTRACE_FIO_OBJS) $(LIBS)
endif
t/fio-dedupe: $(T_DEDUPE_OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_DEDUPE_OBJS) $(LIBS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $(T_DEDUPE_OBJS) $(LIBS)
t/fio-verify-state: $(T_VS_OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_VS_OBJS) $(LIBS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $(T_VS_OBJS) $(LIBS)
t/time-test: $(T_TT_OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_TT_OBJS) $(LIBS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $(T_TT_OBJS) $(LIBS)
ifdef CONFIG_HAVE_CUNIT
unittests/unittest: $(UT_OBJS) $(UT_TARGET_OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(UT_OBJS) $(UT_TARGET_OBJS) -lcunit $(LIBS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $(UT_OBJS) $(UT_TARGET_OBJS) -lcunit $(LIBS)
endif
clean: FORCE
@@ -603,7 +602,7 @@ fulltest:
sudo t/zbd/run-tests-against-zoned-nullb; \
fi
-install: $(PROGS) $(SCRIPTS) tools/plot/fio2gnuplot.1 FORCE
+install: $(PROGS) $(SCRIPTS) $(ENGS_OBJS) tools/plot/fio2gnuplot.1 FORCE
$(INSTALL) -m 755 -d $(DESTDIR)$(bindir)
$(INSTALL) $(PROGS) $(SCRIPTS) $(DESTDIR)$(bindir)
ifdef CONFIG_DYNAMIC_ENGINES
diff --git a/backend.c b/backend.c
index f91f3caf..2e6a377c 100644
--- a/backend.c
+++ b/backend.c
@@ -62,8 +62,9 @@ struct io_log *agg_io_log[DDIR_RWDIR_CNT];
int groupid = 0;
unsigned int thread_number = 0;
+unsigned int nr_segments = 0;
+unsigned int cur_segment = 0;
unsigned int stat_number = 0;
-int shm_id = 0;
int temp_stall_ts;
unsigned long done_secs = 0;
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
@@ -76,7 +77,7 @@ pthread_mutex_t overlap_check = PTHREAD_MUTEX_INITIALIZER;
static void sig_int(int sig)
{
- if (threads) {
+ if (nr_segments) {
if (is_backend)
fio_server_got_signal(sig);
else {
diff --git a/ci/appveyor-install.sh b/ci/appveyor-install.sh
new file mode 100755
index 00000000..c73e4cb5
--- /dev/null
+++ b/ci/appveyor-install.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+# The PATH to appropriate distro commands must already be set before invoking
+# this script
+# The following environment variables must be set:
+# PLATFORM={i686,x64}
+# DISTRO={cygwin,msys2}
+# The following environment can optionally be set:
+# CYG_MIRROR=<URL>
+set -eu
+
+case "${ARCHITECTURE}" in
+ "x64")
+ PACKAGE_ARCH="x86_64"
+ ;;
+ "x86")
+ PACKAGE_ARCH="i686"
+ ;;
+esac
+
+echo "Installing packages..."
+case "${DISTRO}" in
+ "cygwin")
+ CYG_MIRROR=${CYG_MIRROR:-"http://cygwin.mirror.constant.com"}
+ setup-x86_64.exe --quiet-mode --no-shortcuts --only-site \
+ --site "${CYG_MIRROR}" --packages \
+ "mingw64-${PACKAGE_ARCH}-CUnit,mingw64-${PACKAGE_ARCH}-zlib"
+ ;;
+ "msys2")
+ #pacman --noconfirm -Syuu # MSYS2 core update
+ #pacman --noconfirm -Syuu # MSYS2 normal update
+ pacman.exe --noconfirm -S \
+ mingw-w64-${PACKAGE_ARCH}-clang \
+ mingw-w64-${PACKAGE_ARCH}-cunit \
+ mingw-w64-${PACKAGE_ARCH}-lld
+ ;;
+esac
+
+python.exe -m pip install scipy six
+
+echo "Python3 path: $(type -p python3 2>&1)"
+echo "Python3 version: $(python3 -V 2>&1)"
diff --git a/ci/travis-build.sh b/ci/travis-build.sh
index 231417e2..923d882d 100755
--- a/ci/travis-build.sh
+++ b/ci/travis-build.sh
@@ -1,8 +1,9 @@
#!/bin/bash
+set -eu
CI_TARGET_ARCH="${BUILD_ARCH:-$TRAVIS_CPU_ARCH}"
EXTRA_CFLAGS="-Werror"
-PYTHONUNBUFFERED=TRUE
+export PYTHONUNBUFFERED=TRUE
CONFIGURE_FLAGS=()
case "$TRAVIS_OS_NAME" in
@@ -11,6 +12,7 @@ case "$TRAVIS_OS_NAME" in
case "$CI_TARGET_ARCH" in
"x86")
EXTRA_CFLAGS="${EXTRA_CFLAGS} -m32"
+ export LDFLAGS="-m32"
;;
"amd64")
CONFIGURE_FLAGS+=(--enable-cuda)
@@ -24,7 +26,7 @@ CONFIGURE_FLAGS+=(--extra-cflags="${EXTRA_CFLAGS}")
make &&
make test &&
if [[ "$CI_TARGET_ARCH" == "arm64" ]]; then
- sudo python3 t/run-fio-tests.py --skip 6 1007 1008 --debug -p 1010:"--skip 15 16 17 18 19 20"
+ sudo python3 t/run-fio-tests.py --skip 6 1007 1008 --debug -p 1010:"--skip 15 16 17 18 19 20"
else
- sudo python3 t/run-fio-tests.py --skip 6 1007 1008 --debug
+ sudo python3 t/run-fio-tests.py --skip 6 1007 1008 --debug
fi
diff --git a/ci/travis-install.sh b/ci/travis-install.sh
index b6895e82..103695dc 100755
--- a/ci/travis-install.sh
+++ b/ci/travis-install.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-set -e
+set -eu
CI_TARGET_ARCH="${BUILD_ARCH:-$TRAVIS_CPU_ARCH}"
case "$TRAVIS_OS_NAME" in
@@ -51,6 +51,5 @@ case "$TRAVIS_OS_NAME" in
;;
esac
-echo "Python version: $(/usr/bin/python -V 2>&1)"
-echo "Python3 path: $(which python3 2>&1)"
+echo "Python3 path: $(type -p python3 2>&1)"
echo "Python3 version: $(python3 -V 2>&1)"
diff --git a/configure b/configure
index 08571fb0..d2ca8934 100755
--- a/configure
+++ b/configure
@@ -168,7 +168,6 @@ disable_native="no"
march_set="no"
libiscsi="no"
libnbd="no"
-libaio_uring="no"
libzbc=""
dynamic_engines="no"
prefix=/usr/local
@@ -193,6 +192,8 @@ for opt do
;;
--target-win-ver=*) target_win_ver="$optarg"
;;
+ --enable-pdb) pdb="yes"
+ ;;
--build-static) build_static="yes"
;;
--enable-gfio) gfio_check="yes"
@@ -235,8 +236,6 @@ for opt do
;;
--disable-tcmalloc) disable_tcmalloc="yes"
;;
- --enable-libaio-uring) libaio_uring="yes"
- ;;
--dynamic-libengines) dynamic_engines="yes"
;;
--help)
@@ -256,6 +255,7 @@ if test "$show_help" = "yes" ; then
echo "--extra-cflags= Specify extra CFLAGS to pass to compiler"
echo "--build-32bit-win Enable 32-bit build on Windows"
echo "--target-win-ver= Minimum version of Windows to target (XP or 7)"
+ echo "--enable-pdb Enable Windows PDB symbols generation (needs clang/lld)"
echo "--build-static Build a static fio"
echo "--esx Configure build options for esx"
echo "--enable-gfio Enable building of gtk gfio"
@@ -278,7 +278,6 @@ if test "$show_help" = "yes" ; then
echo "--enable-libnbd Enable libnbd (NBD engine) support"
echo "--disable-libzbc Disable libzbc even if found"
echo "--disable-tcmalloc Disable tcmalloc support"
- echo "--enable-libaio-uring Enable libaio emulated over io_uring"
echo "--dynamic-libengines Lib-based ioengines as dynamic libraries"
exit $exit_val
fi
@@ -394,6 +393,8 @@ CYGWIN*)
fi
if test "$target_win_ver" = "XP"; then
output_sym "CONFIG_WINDOWS_XP"
+ # Technically the below is targeting 2003
+ CFLAGS="$CFLAGS -D_WIN32_WINNT=0x0502"
elif test "$target_win_ver" = "7"; then
output_sym "CONFIG_WINDOWS_7"
CFLAGS="$CFLAGS -D_WIN32_WINNT=0x0601"
@@ -648,22 +649,13 @@ int main(void)
return 0;
}
EOF
- if test "$libaio_uring" = "yes"; then
- if compile_prog "" "-luring" "libaio io_uring" ; then
- libaio=yes
- LIBS="-luring $LIBS"
- else
- feature_not_found "libaio io_uring" ""
- fi
- elif compile_prog "" "-laio" "libaio" ; then
+ if compile_prog "" "-laio" "libaio" ; then
libaio=yes
- libaio_uring=no
else
if test "$libaio" = "yes" ; then
feature_not_found "linux AIO" "libaio-dev or libaio-devel"
fi
libaio=no
- libaio_uring=no
fi
cat > $TMPC <<EOF
@@ -684,7 +676,6 @@ EOF
fi
print_config "Linux AIO support" "$libaio"
print_config "Linux AIO support rw flags" "$libaio_rw_flags"
-print_config "Linux AIO over io_uring" "$libaio_uring"
##########################################
# posix aio probe
@@ -939,7 +930,8 @@ cat > $TMPC << EOF
int main(int argc, char **argv)
{
- return asprintf(NULL, "%s", "str") == 0;
+ char *buf;
+ return asprintf(&buf, "%s", "str") == 0;
}
EOF
if compile_prog "" "" "have_asprintf"; then
@@ -956,7 +948,8 @@ cat > $TMPC << EOF
int main(int argc, char **argv)
{
va_list ap;
- return vasprintf(NULL, "%s", ap) == 0;
+ char *buf;
+ return vasprintf(&buf, "%s", ap) == 0;
}
EOF
if compile_prog "" "" "have_vasprintf"; then
@@ -1098,46 +1091,6 @@ fi
print_config "CLOCK_MONOTONIC" "$clock_monotonic"
##########################################
-# CLOCK_MONOTONIC_RAW probe
-if test "$clock_monotonic_raw" != "yes" ; then
- clock_monotonic_raw="no"
-fi
-if test "$clock_gettime" = "yes" ; then
- cat > $TMPC << EOF
-#include <stdio.h>
-#include <time.h>
-int main(int argc, char **argv)
-{
- return clock_gettime(CLOCK_MONOTONIC_RAW, NULL);
-}
-EOF
- if compile_prog "" "$LIBS" "clock monotonic"; then
- clock_monotonic_raw="yes"
- fi
-fi
-print_config "CLOCK_MONOTONIC_RAW" "$clock_monotonic_raw"
-
-##########################################
-# CLOCK_MONOTONIC_PRECISE probe
-if test "$clock_monotonic_precise" != "yes" ; then
- clock_monotonic_precise="no"
-fi
-if test "$clock_gettime" = "yes" ; then
- cat > $TMPC << EOF
-#include <stdio.h>
-#include <time.h>
-int main(int argc, char **argv)
-{
- return clock_gettime(CLOCK_MONOTONIC_PRECISE, NULL);
-}
-EOF
- if compile_prog "" "$LIBS" "clock monotonic precise"; then
- clock_monotonic_precise="yes"
- fi
-fi
-print_config "CLOCK_MONOTONIC_PRECISE" "$clock_monotonic_precise"
-
-##########################################
# clockid_t probe
if test "$clockid_t" != "yes" ; then
clockid_t="no"
@@ -2234,19 +2187,14 @@ lex="no"
arith="no"
if test "$disable_lex" = "no" || test -z "$disable_lex" ; then
if test "$targetos" != "SunOS" ; then
-LEX=$(which lex 2> /dev/null)
-if test -x "$LEX" ; then
+if has lex; then
lex="yes"
fi
-YACC=$(which bison 2> /dev/null)
-if test -x "$YACC" ; then
+if has bison; then
yacc="yes"
yacc_is_bison="yes"
-else
- YACC=$(which yacc 2> /dev/null)
- if test -x "$YACC" ; then
- yacc="yes"
- fi
+elif has yacc; then
+ yacc="yes"
fi
if test "$yacc" = "yes" && test "$lex" = "yes" ; then
arith="yes"
@@ -2262,7 +2210,9 @@ int main(int argc, char **argv)
return 0;
}
EOF
-if compile_prog "" "-ll" "lex"; then
+if compile_prog "" "-lfl" "flex"; then
+ LIBS="-lfl $LIBS"
+elif compile_prog "" "-ll" "lex"; then
LIBS="-ll $LIBS"
else
arith="no"
@@ -2276,8 +2226,7 @@ if test "$arith" = "yes" ; then
if test "$force_no_lex_o" = "yes" ; then
lex_use_o="no"
else
-$LEX -o lex.yy.c exp/expression-parser.l 2> /dev/null
-if test "$?" = "0" ; then
+if lex -o lex.yy.c exp/expression-parser.l 2> /dev/null; then
lex_use_o="yes"
else
lex_use_o="no"
@@ -2698,6 +2647,45 @@ if compile_prog "" "" "statx_syscall"; then
fi
print_config "statx(2)/syscall" "$statx_syscall"
+##########################################
+# check for Windows PDB generation support
+if test "pdb" != "no" ; then
+ cat > $TMPC <<EOF
+int main(void)
+{
+ return 0;
+}
+EOF
+ if compile_prog "-g -gcodeview" "-fuse-ld=lld -Wl,-pdb,$TMPO" "pdb"; then
+ pdb=yes
+ else
+ if test "$pdb" = "yes"; then
+ feature_not_found "PDB" "clang and lld"
+ fi
+ pdb=no
+ fi
+else
+ pdb=no
+fi
+print_config "Windows PDB generation" "$pdb"
+
+##########################################
+# check for timerfd support
+timerfd_create="no"
+cat > $TMPC << EOF
+#include <sys/time.h>
+#include <sys/timerfd.h>
+
+int main(int argc, char **argv)
+{
+ return timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
+}
+EOF
+if compile_prog "" "" "timerfd_create"; then
+ timerfd_create="yes"
+fi
+print_config "timerfd_create" "$timerfd_create"
+
#############################################################################
if test "$wordsize" = "64" ; then
@@ -2720,9 +2708,6 @@ if test "$libaio" = "yes" ; then
if test "$libaio_rw_flags" = "yes" ; then
output_sym "CONFIG_LIBAIO_RW_FLAGS"
fi
- if test "$libaio_uring" = "yes" ; then
- output_sym "CONFIG_LIBAIO_URING"
- fi
fi
if test "$posix_aio" = "yes" ; then
output_sym "CONFIG_POSIXAIO"
@@ -2931,9 +2916,9 @@ fi
if test "$arith" = "yes" ; then
output_sym "CONFIG_ARITHMETIC"
if test "$yacc_is_bison" = "yes" ; then
- echo "YACC=$YACC -y" >> $config_host_mak
+ echo "YACC=bison -y" >> $config_host_mak
else
- echo "YACC=$YACC" >> $config_host_mak
+ echo "YACC=yacc" >> $config_host_mak
fi
if test "$lex_use_o" = "yes" ; then
echo "CONFIG_LEX_USE_O=y" >> $config_host_mak
@@ -2999,6 +2984,9 @@ fi
if test "$statx_syscall" = "yes"; then
output_sym "CONFIG_HAVE_STATX_SYSCALL"
fi
+if test "$timerfd_create" = "yes"; then
+ output_sym "CONFIG_HAVE_TIMERFD_CREATE"
+fi
if test "$fallthrough" = "yes"; then
CFLAGS="$CFLAGS -Wimplicit-fallthrough"
fi
@@ -3020,6 +3008,10 @@ fi
if test "$dynamic_engines" = "yes" ; then
output_sym "CONFIG_DYNAMIC_ENGINES"
fi
+if test "$pdb" = yes; then
+ output_sym "CONFIG_PDB"
+fi
+
print_config "Lib-based ioengines dynamic" "$dynamic_engines"
cat > $TMPC << EOF
int main(int argc, char **argv)
diff --git a/engines/glusterfs.c b/engines/glusterfs.c
index f2b84a2a..fc6fee19 100644
--- a/engines/glusterfs.c
+++ b/engines/glusterfs.c
@@ -271,8 +271,7 @@ int fio_gf_open_file(struct thread_data *td, struct fio_file *f)
if (td->o.odirect)
flags |= OS_O_DIRECT;
- if (td->o.sync_io)
- flags |= O_SYNC;
+ flags |= td->o.sync_io;
dprint(FD_FILE, "fio file %s open mode %s td rw %s\n", f->file_name,
flags & O_RDONLY ? "ro" : "rw", td_read(td) ? "read" : "write");
diff --git a/engines/ime.c b/engines/ime.c
index 42984021..440cc29e 100644
--- a/engines/ime.c
+++ b/engines/ime.c
@@ -194,8 +194,7 @@ static int fio_ime_open_file(struct thread_data *td, struct fio_file *f)
}
if (td->o.odirect)
flags |= O_DIRECT;
- if (td->o.sync_io)
- flags |= O_SYNC;
+ flags |= td->o.sync_io;
if (td->o.create_on_open && td->o.allow_create)
flags |= O_CREAT;
diff --git a/engines/io_uring.c b/engines/io_uring.c
index 69f48859..b997c8d8 100644
--- a/engines/io_uring.c
+++ b/engines/io_uring.c
@@ -806,7 +806,7 @@ static int fio_ioring_close_file(struct thread_data *td, struct fio_file *f)
static struct ioengine_ops ioengine = {
.name = "io_uring",
.version = FIO_IOOPS_VERSION,
- .flags = FIO_ASYNCIO_SYNC_TRIM,
+ .flags = FIO_ASYNCIO_SYNC_TRIM | FIO_NO_OFFLOAD,
.init = fio_ioring_init,
.post_init = fio_ioring_post_init,
.io_u_init = fio_ioring_io_u_init,
diff --git a/engines/libhdfs.c b/engines/libhdfs.c
index 9ca82f78..eb55c3c5 100644
--- a/engines/libhdfs.c
+++ b/engines/libhdfs.c
@@ -240,7 +240,7 @@ int fio_hdfsio_close_file(struct thread_data *td, struct fio_file *f)
return 0;
}
-static int fio_hdfsio_init(struct thread_data *td)
+static int fio_hdfsio_io_u_init(struct thread_data *td, struct io_u *io_u)
{
struct hdfsio_options *options = td->eo;
struct hdfsio_data *hd = td->io_ops_data;
@@ -349,7 +349,7 @@ static int fio_hdfsio_setup(struct thread_data *td)
return 0;
}
-static int fio_hdfsio_io_u_init(struct thread_data *td, struct io_u *io_u)
+static int fio_hdfsio_init(struct thread_data *td)
{
struct hdfsio_data *hd = td->io_ops_data;
struct hdfsio_options *options = td->eo;
diff --git a/engines/libpmem.c b/engines/libpmem.c
index a9b3e29b..eefb7767 100644
--- a/engines/libpmem.c
+++ b/engines/libpmem.c
@@ -193,6 +193,7 @@ static enum fio_q_status fio_libpmem_queue(struct thread_data *td,
dprint(FD_IO, "DEBUG fio_libpmem_queue\n");
dprint(FD_IO,"td->o.odirect %d td->o.sync_io %d \n",td->o.odirect, td->o.sync_io);
+ /* map both O_SYNC / DSYNC to not using NODRAIN */
flags = td->o.sync_io ? 0 : PMEM_F_MEM_NODRAIN;
flags |= td->o.odirect ? PMEM_F_MEM_NONTEMPORAL : PMEM_F_MEM_TEMPORAL;
diff --git a/engines/net.c b/engines/net.c
index 91f25774..c6cec584 100644
--- a/engines/net.c
+++ b/engines/net.c
@@ -938,8 +938,9 @@ static int fio_netio_udp_recv_open(struct thread_data *td, struct fio_file *f)
if (ntohl(msg.magic) != FIO_LINK_OPEN_CLOSE_MAGIC ||
ntohl(msg.cmd) != FIO_LINK_OPEN) {
- log_err("fio: bad udp open magic %x/%x\n", ntohl(msg.magic),
- ntohl(msg.cmd));
+ log_err("fio: bad udp open magic %x/%x\n",
+ (unsigned int) ntohl(msg.magic),
+ (unsigned int) ntohl(msg.cmd));
return -1;
}
diff --git a/engines/posixaio.c b/engines/posixaio.c
index 82c6aa65..135d088c 100644
--- a/engines/posixaio.c
+++ b/engines/posixaio.c
@@ -17,47 +17,14 @@ struct posixaio_data {
unsigned int queued;
};
-static int fill_timespec(struct timespec *ts)
+static unsigned long long ts_utime_since_now(const struct timespec *start)
{
-#ifdef CONFIG_CLOCK_GETTIME
-#ifdef CONFIG_CLOCK_MONOTONIC
- clockid_t clk = CLOCK_MONOTONIC;
-#else
- clockid_t clk = CLOCK_REALTIME;
-#endif
- if (!clock_gettime(clk, ts))
- return 0;
-
- perror("clock_gettime");
- return 1;
-#else
- struct timeval tv;
-
- gettimeofday(&tv, NULL);
- ts->tv_sec = tv.tv_sec;
- ts->tv_nsec = tv.tv_usec * 1000;
- return 0;
-#endif
-}
-
-static unsigned long long ts_utime_since_now(struct timespec *t)
-{
- long long sec, nsec;
struct timespec now;
- if (fill_timespec(&now))
+ if (fio_get_mono_time(&now) < 0)
return 0;
-
- sec = now.tv_sec - t->tv_sec;
- nsec = now.tv_nsec - t->tv_nsec;
- if (sec > 0 && nsec < 0) {
- sec--;
- nsec += 1000000000;
- }
- sec *= 1000000;
- nsec /= 1000;
- return sec + nsec;
+ return utime_since(start, &now);
}
static int fio_posixaio_cancel(struct thread_data fio_unused *td,
@@ -102,7 +69,7 @@ static int fio_posixaio_getevents(struct thread_data *td, unsigned int min,
unsigned int r;
int i;
- if (t && !fill_timespec(&start))
+ if (t && fio_get_mono_time(&start) == 0)
have_timeout = 1;
else
memset(&start, 0, sizeof(start));
diff --git a/engines/windowsaio.c b/engines/windowsaio.c
index 5c7e7964..9868e816 100644
--- a/engines/windowsaio.c
+++ b/engines/windowsaio.c
@@ -161,15 +161,15 @@ static int windowsaio_invalidate_cache(struct fio_file *f)
if (ihFile != INVALID_HANDLE_VALUE) {
if (!CloseHandle(ihFile)) {
error = GetLastError();
- log_info("windowsaio: invalidation fd close %s "
- "failed: error %d\n", f->file_name, error);
+ log_info("windowsaio: invalidation fd close %s failed: error %lu\n",
+ f->file_name, error);
rc = 1;
}
} else {
error = GetLastError();
if (error != ERROR_FILE_NOT_FOUND) {
- log_info("windowsaio: cache invalidation of %s failed: "
- "error %d\n", f->file_name, error);
+ log_info("windowsaio: cache invalidation of %s failed: error %lu\n",
+ f->file_name, error);
rc = 1;
}
}
diff --git a/eta.c b/eta.c
index e8c72780..97843012 100644
--- a/eta.c
+++ b/eta.c
@@ -507,6 +507,7 @@ bool calc_thread_status(struct jobs_eta *je, int force)
calc_rate(unified_rw_rep, rate_time, io_bytes, rate_io_bytes,
je->rate);
memcpy(&rate_prev_time, &now, sizeof(now));
+ regrow_agg_logs();
for_each_rw_ddir(ddir) {
add_agg_sample(sample_val(je->rate[ddir]), ddir, 0, 0);
}
@@ -534,56 +535,38 @@ bool calc_thread_status(struct jobs_eta *je, int force)
static int gen_eta_str(struct jobs_eta *je, char *p, size_t left,
char **rate_str, char **iops_str)
{
- bool has_r = je->rate[DDIR_READ] || je->iops[DDIR_READ];
- bool has_w = je->rate[DDIR_WRITE] || je->iops[DDIR_WRITE];
- bool has_t = je->rate[DDIR_TRIM] || je->iops[DDIR_TRIM];
+ static const char c[DDIR_RWDIR_CNT] = {'r', 'w', 't'};
+ bool has[DDIR_RWDIR_CNT];
+ bool has_any = false;
+ const char *sep;
int l = 0;
- if (!has_r && !has_w && !has_t)
+ for_each_rw_ddir(ddir) {
+ has[ddir] = (je->rate[ddir] || je->iops[ddir]);
+ has_any |= has[ddir];
+ }
+ if (!has_any)
return 0;
- if (has_r) {
- l += snprintf(p + l, left - l, "[r=%s", rate_str[DDIR_READ]);
- if (!has_w)
- l += snprintf(p + l, left - l, "]");
- }
- if (has_w) {
- if (has_r)
- l += snprintf(p + l, left - l, ",");
- else
- l += snprintf(p + l, left - l, "[");
- l += snprintf(p + l, left - l, "w=%s", rate_str[DDIR_WRITE]);
- if (!has_t)
- l += snprintf(p + l, left - l, "]");
- }
- if (has_t) {
- if (has_r || has_w)
- l += snprintf(p + l, left - l, ",");
- else if (!has_r && !has_w)
- l += snprintf(p + l, left - l, "[");
- l += snprintf(p + l, left - l, "t=%s]", rate_str[DDIR_TRIM]);
- }
- if (has_r) {
- l += snprintf(p + l, left - l, "[r=%s", iops_str[DDIR_READ]);
- if (!has_w)
- l += snprintf(p + l, left - l, " IOPS]");
- }
- if (has_w) {
- if (has_r)
- l += snprintf(p + l, left - l, ",");
- else
- l += snprintf(p + l, left - l, "[");
- l += snprintf(p + l, left - l, "w=%s", iops_str[DDIR_WRITE]);
- if (!has_t)
- l += snprintf(p + l, left - l, " IOPS]");
+ l += snprintf(p + l, left - l, "[");
+ sep = "";
+ for_each_rw_ddir(ddir) {
+ if (has[ddir]) {
+ l += snprintf(p + l, left - l, "%s%c=%s",
+ sep, c[ddir], rate_str[ddir]);
+ sep = ",";
+ }
}
- if (has_t) {
- if (has_r || has_w)
- l += snprintf(p + l, left - l, ",");
- else if (!has_r && !has_w)
- l += snprintf(p + l, left - l, "[");
- l += snprintf(p + l, left - l, "t=%s IOPS]", iops_str[DDIR_TRIM]);
+ l += snprintf(p + l, left - l, "][");
+ sep = "";
+ for_each_rw_ddir(ddir) {
+ if (has[ddir]) {
+ l += snprintf(p + l, left - l, "%s%c=%s",
+ sep, c[ddir], iops_str[ddir]);
+ sep = ",";
+ }
}
+ l += snprintf(p + l, left - l, " IOPS]");
return l;
}
diff --git a/filesetup.c b/filesetup.c
index e44f31c7..42c5f630 100644
--- a/filesetup.c
+++ b/filesetup.c
@@ -231,13 +231,12 @@ static int extend_file(struct thread_data *td, struct fio_file *f)
break;
log_info("fio: ENOSPC on laying out "
"file, stopping\n");
- break;
}
td_verror(td, errno, "write");
} else
td_verror(td, EIO, "write");
- break;
+ goto err;
}
}
@@ -655,8 +654,7 @@ int generic_open_file(struct thread_data *td, struct fio_file *f)
}
flags |= OS_O_DIRECT | FIO_O_ATOMIC;
}
- if (td->o.sync_io)
- flags |= O_SYNC;
+ flags |= td->o.sync_io;
if (td->o.create_on_open && td->o.allow_create)
flags |= O_CREAT;
skip_flags:
diff --git a/fio.1 b/fio.1
index a881277c..48119325 100644
--- a/fio.1
+++ b/fio.1
@@ -1462,9 +1462,31 @@ starting I/O if the platform and file type support it. Defaults to true.
This will be ignored if \fBpre_read\fR is also specified for the
same job.
.TP
-.BI sync \fR=\fPbool
-Use synchronous I/O for buffered writes. For the majority of I/O engines,
-this means using O_SYNC. Default: false.
+.BI sync \fR=\fPstr
+Whether, and what type, of synchronous I/O to use for writes. The allowed
+values are:
+.RS
+.RS
+.TP
+.B none
+Do not use synchronous IO, the default.
+.TP
+.B 0
+Same as \fBnone\fR.
+.TP
+.B sync
+Use synchronous file IO. For the majority of I/O engines,
+this means using O_SYNC.
+.TP
+.B 1
+Same as \fBsync\fR.
+.TP
+.B dsync
+Use synchronous data IO. For the majority of I/O engines,
+this means using O_DSYNC.
+.PD
+.RE
+.RE
.TP
.BI iomem \fR=\fPstr "\fR,\fP mem" \fR=\fPstr
Fio can use various types of memory as the I/O unit buffer. The allowed
diff --git a/fio.h b/fio.h
index 9d189eb8..fffec001 100644
--- a/fio.h
+++ b/fio.h
@@ -467,6 +467,12 @@ struct thread_data {
};
+struct thread_segment {
+ struct thread_data *threads;
+ int shm_id;
+ int nr_threads;
+};
+
/*
* when should interactive ETA output be generated
*/
@@ -510,10 +516,15 @@ enum {
#define __fio_stringify_1(x) #x
#define __fio_stringify(x) __fio_stringify_1(x)
+#define REAL_MAX_JOBS 4096
+#define JOBS_PER_SEG 8
+#define REAL_MAX_SEG (REAL_MAX_JOBS / JOBS_PER_SEG)
+
extern bool exitall_on_terminate;
extern unsigned int thread_number;
extern unsigned int stat_number;
-extern int shm_id;
+extern unsigned int nr_segments;
+extern unsigned int cur_segment;
extern int groupid;
extern int output_format;
extern int append_terse_output;
@@ -542,7 +553,15 @@ extern char *trigger_remote_cmd;
extern long long trigger_timeout;
extern char *aux_path;
-extern struct thread_data *threads;
+extern struct thread_segment segments[REAL_MAX_SEG];
+
+static inline struct thread_data *tnumber_to_td(unsigned int tnumber)
+{
+ struct thread_segment *seg;
+
+ seg = &segments[tnumber / JOBS_PER_SEG];
+ return &seg->threads[tnumber & (JOBS_PER_SEG - 1)];
+}
static inline bool is_running_backend(void)
{
@@ -557,8 +576,6 @@ static inline void fio_ro_check(const struct thread_data *td, struct io_u *io_u)
!(io_u->ddir == DDIR_TRIM && !td_trim(td)));
}
-#define REAL_MAX_JOBS 4096
-
static inline bool should_fsync(struct thread_data *td)
{
if (td->last_was_sync)
@@ -709,7 +726,7 @@ extern void lat_target_reset(struct thread_data *);
* Iterates all threads/processes within all the defined jobs
*/
#define for_each_td(td, i) \
- for ((i) = 0, (td) = &threads[0]; (i) < (int) thread_number; (i)++, (td)++)
+ for ((i) = 0, (td) = &segments[0].threads[0]; (i) < (int) thread_number; (i)++, (td) = tnumber_to_td((i)))
#define for_each_file(td, f, i) \
if ((td)->files_index) \
for ((i) = 0, (f) = (td)->files[0]; \
diff --git a/fio_time.h b/fio_time.h
index c00f8e78..b3bbd4c0 100644
--- a/fio_time.h
+++ b/fio_time.h
@@ -13,6 +13,8 @@ extern uint64_t ntime_since(const struct timespec *, const struct timespec *);
extern uint64_t ntime_since_now(const struct timespec *);
extern uint64_t utime_since(const struct timespec *, const struct timespec *);
extern uint64_t utime_since_now(const struct timespec *);
+extern int64_t rel_time_since(const struct timespec *,
+ const struct timespec *);
extern uint64_t mtime_since(const struct timespec *, const struct timespec *);
extern uint64_t mtime_since_now(const struct timespec *);
extern uint64_t mtime_since_tv(const struct timeval *, const struct timeval *);
diff --git a/flow.c b/flow.c
index ee4d761d..ea6b0ec9 100644
--- a/flow.c
+++ b/flow.c
@@ -5,9 +5,9 @@
struct fio_flow {
unsigned int refs;
- struct flist_head list;
unsigned int id;
- unsigned long long flow_counter;
+ struct flist_head list;
+ unsigned long flow_counter;
unsigned int total_weight;
};
@@ -90,7 +90,7 @@ static struct fio_flow *flow_get(unsigned int id)
return flow;
}
-static void flow_put(struct fio_flow *flow, unsigned long long flow_counter,
+static void flow_put(struct fio_flow *flow, unsigned long flow_counter,
unsigned int weight)
{
if (!flow_lock)
diff --git a/gettime-thread.c b/gettime-thread.c
index 953e4e67..86c2e2ef 100644
--- a/gettime-thread.c
+++ b/gettime-thread.c
@@ -58,7 +58,7 @@ static void *gtod_thread_main(void *data)
* but I'm not sure what to use outside of a simple CPU nop to relax
* it - we don't want to lose precision.
*/
- while (threads) {
+ while (nr_segments) {
fio_gtod_update();
nop;
}
diff --git a/gettime.c b/gettime.c
index c3a4966b..f85da6e0 100644
--- a/gettime.c
+++ b/gettime.c
@@ -127,18 +127,33 @@ static void fio_init gtod_init(void)
#endif /* FIO_DEBUG_TIME */
-#ifdef CONFIG_CLOCK_GETTIME
-static int fill_clock_gettime(struct timespec *ts)
+/*
+ * Queries the value of the monotonic clock if a monotonic clock is available
+ * or the wall clock time if no monotonic clock is available. Returns 0 if
+ * querying the clock succeeded or -1 if querying the clock failed.
+ */
+int fio_get_mono_time(struct timespec *ts)
{
-#if defined(CONFIG_CLOCK_MONOTONIC_RAW)
- return clock_gettime(CLOCK_MONOTONIC_RAW, ts);
-#elif defined(CONFIG_CLOCK_MONOTONIC)
- return clock_gettime(CLOCK_MONOTONIC, ts);
+ int ret;
+
+#ifdef CONFIG_CLOCK_GETTIME
+#if defined(CONFIG_CLOCK_MONOTONIC)
+ ret = clock_gettime(CLOCK_MONOTONIC, ts);
#else
- return clock_gettime(CLOCK_REALTIME, ts);
+ ret = clock_gettime(CLOCK_REALTIME, ts);
#endif
-}
+#else
+ struct timeval tv;
+
+ ret = gettimeofday(&tv, NULL);
+ if (ret == 0) {
+ ts->tv_sec = tv.tv_sec;
+ ts->tv_nsec = tv.tv_usec * 1000;
+ }
#endif
+ assert(ret <= 0);
+ return ret;
+}
static void __fio_gettime(struct timespec *tp)
{
@@ -155,8 +170,8 @@ static void __fio_gettime(struct timespec *tp)
#endif
#ifdef CONFIG_CLOCK_GETTIME
case CS_CGETTIME: {
- if (fill_clock_gettime(tp) < 0) {
- log_err("fio: clock_gettime fails\n");
+ if (fio_get_mono_time(tp) < 0) {
+ log_err("fio: fio_get_mono_time() fails\n");
assert(0);
}
break;
@@ -224,19 +239,13 @@ static unsigned long get_cycles_per_msec(void)
{
struct timespec s, e;
uint64_t c_s, c_e;
- enum fio_cs old_cs = fio_clock_source;
uint64_t elapsed;
-#ifdef CONFIG_CLOCK_GETTIME
- fio_clock_source = CS_CGETTIME;
-#else
- fio_clock_source = CS_GTOD;
-#endif
- __fio_gettime(&s);
+ fio_get_mono_time(&s);
c_s = get_cpu_clock();
do {
- __fio_gettime(&e);
+ fio_get_mono_time(&e);
c_e = get_cpu_clock();
elapsed = ntime_since(&s, &e);
@@ -244,7 +253,6 @@ static unsigned long get_cycles_per_msec(void)
break;
} while (1);
- fio_clock_source = old_cs;
return (c_e - c_s) * 1000000 / elapsed;
}
@@ -516,23 +524,33 @@ uint64_t mtime_since_now(const struct timespec *s)
return mtime_since(s, &t);
}
-uint64_t mtime_since(const struct timespec *s, const struct timespec *e)
+/*
+ * Returns *e - *s in milliseconds as a signed integer. Note: rounding is
+ * asymmetric. If the difference yields +1 ns then 0 is returned. If the
+ * difference yields -1 ns then -1 is returned.
+ */
+int64_t rel_time_since(const struct timespec *s, const struct timespec *e)
{
- int64_t sec, usec;
+ int64_t sec, nsec;
sec = e->tv_sec - s->tv_sec;
- usec = (e->tv_nsec - s->tv_nsec) / 1000;
- if (sec > 0 && usec < 0) {
+ nsec = e->tv_nsec - s->tv_nsec;
+ if (nsec < 0) {
sec--;
- usec += 1000000;
+ nsec += 1000ULL * 1000 * 1000;
}
+ assert(0 <= nsec && nsec < 1000ULL * 1000 * 1000);
- if (sec < 0 || (sec == 0 && usec < 0))
- return 0;
+ return sec * 1000 + nsec / (1000 * 1000);
+}
- sec *= 1000;
- usec /= 1000;
- return sec + usec;
+/*
+ * Returns *e - *s in milliseconds as an unsigned integer. Returns 0 if
+ * *e < *s.
+ */
+uint64_t mtime_since(const struct timespec *s, const struct timespec *e)
+{
+ return max(rel_time_since(s, e), (int64_t)0);
}
uint64_t time_since_now(const struct timespec *s)
diff --git a/gettime.h b/gettime.h
index c55f5cba..f1d619ad 100644
--- a/gettime.h
+++ b/gettime.h
@@ -16,6 +16,7 @@ enum fio_cs {
CS_INVAL,
};
+extern int fio_get_mono_time(struct timespec *);
extern void fio_gettime(struct timespec *, void *);
extern void fio_gtod_init(void);
extern void fio_clock_init(void);
diff --git a/goptions.c b/goptions.c
index f44254bf..0b8c56a2 100644
--- a/goptions.c
+++ b/goptions.c
@@ -826,7 +826,7 @@ static struct gopt *gopt_new_str_val(struct gopt_job_view *gjv,
unsigned long long *p, unsigned int idx)
{
struct gopt_str_val *g;
- const gchar *postfix[] = { "B", "KiB", "MiB", "GiB", "PiB", "PiB", "" };
+ const gchar *postfix[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" };
GtkWidget *label;
int i;
diff --git a/helper_thread.c b/helper_thread.c
index a2fb7c29..2d553654 100644
--- a/helper_thread.c
+++ b/helper_thread.c
@@ -1,4 +1,8 @@
#include <signal.h>
+#include <unistd.h>
+#ifdef CONFIG_HAVE_TIMERFD_CREATE
+#include <sys/timerfd.h>
+#endif
#ifdef CONFIG_VALGRIND_DEV
#include <valgrind/drd.h>
#else
@@ -11,6 +15,9 @@
#include "steadystate.h"
#include "pshared.h"
+static int sleep_accuracy_ms;
+static int timerfd = -1;
+
enum action {
A_EXIT = 1,
A_RESET = 2,
@@ -25,6 +32,13 @@ static struct helper_data {
struct fio_sem *startup_sem;
} *helper_data;
+struct interval_timer {
+ const char *name;
+ struct timespec expires;
+ uint32_t interval_ms;
+ int (*func)(void);
+};
+
void helper_thread_destroy(void)
{
if (!helper_data)
@@ -83,6 +97,18 @@ static int read_from_pipe(int fd, void *buf, size_t len)
}
#endif
+static void block_signals(void)
+{
+#ifdef HAVE_PTHREAD_SIGMASK
+ sigset_t sigmask;
+
+ ret = pthread_sigmask(SIG_UNBLOCK, NULL, &sigmask);
+ assert(ret == 0);
+ ret = pthread_sigmask(SIG_BLOCK, &sigmask, NULL);
+ assert(ret == 0);
+#endif
+}
+
static void submit_action(enum action a)
{
const char data = a;
@@ -128,128 +154,207 @@ void helper_thread_exit(void)
pthread_join(helper_data->thread, NULL);
}
-static unsigned int task_helper(struct timespec *last, struct timespec *now, unsigned int period, void do_task())
+/* Resets timers and returns the time in milliseconds until the next event. */
+static int reset_timers(struct interval_timer timer[], int num_timers,
+ struct timespec *now)
{
- unsigned int next, since;
-
- since = mtime_since(last, now);
- if (since >= period || period - since < 10) {
- do_task();
- timespec_add_msec(last, since);
- if (since > period)
- next = period - (since - period);
- else
- next = period;
- } else
- next = period - since;
-
- return next;
+ uint32_t msec_to_next_event = INT_MAX;
+ int i;
+
+ for (i = 0; i < num_timers; ++i) {
+ timer[i].expires = *now;
+ timespec_add_msec(&timer[i].expires, timer[i].interval_ms);
+ msec_to_next_event = min_not_zero(msec_to_next_event,
+ timer[i].interval_ms);
+ }
+
+ return msec_to_next_event;
}
-static void *helper_thread_main(void *data)
+/*
+ * Waits for an action from fd during at least timeout_ms. `fd` must be in
+ * non-blocking mode.
+ */
+static uint8_t wait_for_action(int fd, unsigned int timeout_ms)
{
- struct helper_data *hd = data;
- unsigned int msec_to_next_event, next_log, next_si = status_interval;
- unsigned int next_ss = STEADYSTATE_MSEC;
- struct timespec ts, last_du, last_ss, last_si;
- char action;
- int ret = 0;
-
- sk_out_assign(hd->sk_out);
+ struct timeval timeout = {
+ .tv_sec = timeout_ms / 1000,
+ .tv_usec = (timeout_ms % 1000) * 1000,
+ };
+ fd_set rfds, efds;
+ uint8_t action = 0;
+ uint64_t exp;
+ int res;
-#ifdef HAVE_PTHREAD_SIGMASK
+ res = read_from_pipe(fd, &action, sizeof(action));
+ if (res > 0 || timeout_ms == 0)
+ return action;
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+ FD_ZERO(&efds);
+ FD_SET(fd, &efds);
+#ifdef CONFIG_HAVE_TIMERFD_CREATE
{
- sigset_t sigmask;
-
- /* Let another thread handle signals. */
- ret = pthread_sigmask(SIG_UNBLOCK, NULL, &sigmask);
- assert(ret == 0);
- ret = pthread_sigmask(SIG_BLOCK, &sigmask, NULL);
- assert(ret == 0);
+ /*
+ * 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));
+ return A_EXIT;
+ }
+ 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;
+}
+
+/*
+ * Verify whether or not timer @it has expired. If timer @it has expired, call
+ * @it->func(). @now is the current time. @msec_to_next_event is an
+ * input/output parameter that represents the time until the next event.
+ */
+static int eval_timer(struct interval_timer *it, const struct timespec *now,
+ unsigned int *msec_to_next_event)
+{
+ int64_t delta_ms;
+ bool expired;
+
+ /* interval == 0 means that the timer is disabled. */
+ if (it->interval_ms == 0)
+ return 0;
+
+ delta_ms = rel_time_since(now, &it->expires);
+ expired = delta_ms <= sleep_accuracy_ms;
+ if (expired) {
+ timespec_add_msec(&it->expires, it->interval_ms);
+ delta_ms = rel_time_since(now, &it->expires);
+ if (delta_ms < it->interval_ms - sleep_accuracy_ms ||
+ delta_ms > it->interval_ms + sleep_accuracy_ms) {
+ dprint(FD_HELPERTHREAD,
+ "%s: delta = %" PRIi64 " <> %u. Clock jump?\n",
+ it->name, delta_ms, it->interval_ms);
+ delta_ms = it->interval_ms;
+ it->expires = *now;
+ timespec_add_msec(&it->expires, it->interval_ms);
+ }
+ }
+ *msec_to_next_event = min((unsigned int)delta_ms, *msec_to_next_event);
+ return expired ? it->func() : 0;
+}
+
+static void *helper_thread_main(void *data)
+{
+ struct helper_data *hd = data;
+ unsigned int msec_to_next_event, next_log;
+ struct interval_timer timer[] = {
+ {
+ .name = "disk_util",
+ .interval_ms = DISK_UTIL_MSEC,
+ .func = update_io_ticks,
+ },
+ {
+ .name = "status_interval",
+ .interval_ms = status_interval,
+ .func = __show_running_run_stats,
+ },
+ {
+ .name = "steadystate",
+ .interval_ms = steadystate_enabled ? STEADYSTATE_MSEC :
+ 0,
+ .func = steadystate_check,
+ }
+ };
+ struct timespec ts;
+ int clk_tck, ret = 0;
-#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
- clock_gettime(CLOCK_MONOTONIC, &ts);
+#ifdef _SC_CLK_TCK
+ clk_tck = sysconf(_SC_CLK_TCK);
#else
- clock_gettime(CLOCK_REALTIME, &ts);
+ /*
+ * 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);
+ 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
- memcpy(&last_du, &ts, sizeof(ts));
- memcpy(&last_ss, &ts, sizeof(ts));
- memcpy(&last_si, &ts, sizeof(ts));
+
+ 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);
fio_sem_up(hd->startup_sem);
- msec_to_next_event = DISK_UTIL_MSEC;
while (!ret && !hd->exit) {
- uint64_t since_du;
- struct timeval timeout = {
- .tv_sec = msec_to_next_event / 1000,
- .tv_usec = (msec_to_next_event % 1000) * 1000,
- };
- fd_set rfds, efds;
-
- if (read_from_pipe(hd->pipe[0], &action, sizeof(action)) < 0) {
- FD_ZERO(&rfds);
- FD_SET(hd->pipe[0], &rfds);
- FD_ZERO(&efds);
- FD_SET(hd->pipe[0], &efds);
- if (select(1, &rfds, NULL, &efds, &timeout) < 0) {
- log_err("fio: select() call in helper thread failed: %s",
- strerror(errno));
- ret = 1;
- }
- if (read_from_pipe(hd->pipe[0], &action, sizeof(action)) <
- 0)
- action = 0;
- }
+ uint8_t action;
+ int i;
-#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
- clock_gettime(CLOCK_MONOTONIC, &ts);
-#else
- clock_gettime(CLOCK_REALTIME, &ts);
-#endif
+ action = wait_for_action(hd->pipe[0], msec_to_next_event);
+ if (action == A_EXIT)
+ break;
- if (action == A_RESET) {
- last_du = ts;
- last_ss = ts;
- }
+ fio_get_mono_time(&ts);
+
+ msec_to_next_event = INT_MAX;
- since_du = mtime_since(&last_du, &ts);
- if (since_du >= DISK_UTIL_MSEC || DISK_UTIL_MSEC - since_du < 10) {
- ret = update_io_ticks();
- timespec_add_msec(&last_du, DISK_UTIL_MSEC);
- msec_to_next_event = DISK_UTIL_MSEC;
- if (since_du >= DISK_UTIL_MSEC)
- msec_to_next_event -= (since_du - DISK_UTIL_MSEC);
- } else
- msec_to_next_event = DISK_UTIL_MSEC - since_du;
+ if (action == A_RESET)
+ msec_to_next_event = reset_timers(timer,
+ ARRAY_SIZE(timer), &ts);
+
+ for (i = 0; i < ARRAY_SIZE(timer); ++i)
+ ret = eval_timer(&timer[i], &ts, &msec_to_next_event);
if (action == A_DO_STAT)
__show_running_run_stats();
- if (status_interval) {
- next_si = task_helper(&last_si, &ts, status_interval, __show_running_run_stats);
- msec_to_next_event = min(next_si, msec_to_next_event);
- }
-
next_log = calc_log_samples();
if (!next_log)
next_log = DISK_UTIL_MSEC;
- if (steadystate_enabled) {
- next_ss = task_helper(&last_ss, &ts, STEADYSTATE_MSEC, steadystate_check);
- msec_to_next_event = min(next_ss, msec_to_next_event);
- }
-
msec_to_next_event = min(next_log, msec_to_next_event);
- dprint(FD_HELPERTHREAD, "next_si: %u, next_ss: %u, next_log: %u, msec_to_next_event: %u\n",
- next_si, next_ss, next_log, msec_to_next_event);
+ dprint(FD_HELPERTHREAD,
+ "next_log: %u, msec_to_next_event: %u\n",
+ next_log, msec_to_next_event);
if (!is_backend)
print_thread_status();
}
+ if (timerfd >= 0) {
+ close(timerfd);
+ timerfd = -1;
+ }
+
fio_writeout_logs(false);
sk_out_drop();
diff --git a/init.c b/init.c
index 7f64ce21..f9c20bdb 100644
--- a/init.c
+++ b/init.c
@@ -45,13 +45,12 @@ const char fio_version_string[] = FIO_VERSION;
#define FIO_RANDSEED (0xb1899bedUL)
static char **ini_file;
-static int max_jobs = FIO_MAX_JOBS;
static bool dump_cmdline;
static bool parse_only;
static bool merge_blktrace_only;
static struct thread_data def_thread;
-struct thread_data *threads = NULL;
+struct thread_segment segments[REAL_MAX_SEG];
static char **job_sections;
static int nr_job_sections;
@@ -301,25 +300,34 @@ static struct option l_opts[FIO_NR_OPTIONS] = {
void free_threads_shm(void)
{
- if (threads) {
- void *tp = threads;
+ int i;
+
+ for (i = 0; i < nr_segments; i++) {
+ struct thread_segment *seg = &segments[i];
+
+ if (seg->threads) {
+ void *tp = seg->threads;
#ifndef CONFIG_NO_SHM
- struct shmid_ds sbuf;
+ struct shmid_ds sbuf;
- threads = NULL;
- shmdt(tp);
- shmctl(shm_id, IPC_RMID, &sbuf);
- shm_id = -1;
+ seg->threads = NULL;
+ shmdt(tp);
+ shmctl(seg->shm_id, IPC_RMID, &sbuf);
+ seg->shm_id = -1;
#else
- threads = NULL;
- free(tp);
+ seg->threads = NULL;
+ free(tp);
#endif
+ }
}
+
+ nr_segments = 0;
+ cur_segment = 0;
}
static void free_shm(void)
{
- if (threads) {
+ if (nr_segments) {
flow_exit();
fio_debug_jobp = NULL;
fio_warned = NULL;
@@ -337,71 +345,79 @@ static void free_shm(void)
scleanup();
}
-/*
- * The thread area is shared between the main process and the job
- * threads/processes. So setup a shared memory segment that will hold
- * all the job info. We use the end of the region for keeping track of
- * open files across jobs, for file sharing.
- */
-static int setup_thread_area(void)
+static int add_thread_segment(void)
{
+ struct thread_segment *seg = &segments[nr_segments];
+ size_t size = JOBS_PER_SEG * sizeof(struct thread_data);
int i;
- if (threads)
- return 0;
-
- /*
- * 1024 is too much on some machines, scale max_jobs if
- * we get a failure that looks like too large a shm segment
- */
- do {
- size_t size = max_jobs * sizeof(struct thread_data);
+ if (nr_segments + 1 >= REAL_MAX_SEG) {
+ log_err("error: maximum number of jobs reached.\n");
+ return -1;
+ }
- size += 2 * sizeof(unsigned int);
+ size += 2 * sizeof(unsigned int);
#ifndef CONFIG_NO_SHM
- shm_id = shmget(0, size, IPC_CREAT | 0600);
- if (shm_id != -1)
- break;
- if (errno != EINVAL && errno != ENOMEM && errno != ENOSPC) {
+ seg->shm_id = shmget(0, size, IPC_CREAT | 0600);
+ if (seg->shm_id == -1) {
+ if (errno != EINVAL && errno != ENOMEM && errno != ENOSPC)
perror("shmget");
- break;
- }
+ return -1;
+ }
#else
- threads = malloc(size);
- if (threads)
- break;
+ seg->threads = malloc(size);
+ if (!seg->threads)
+ return -1;
#endif
- max_jobs >>= 1;
- } while (max_jobs);
-
#ifndef CONFIG_NO_SHM
- if (shm_id == -1)
- return 1;
-
- threads = shmat(shm_id, NULL, 0);
- if (threads == (void *) -1) {
+ seg->threads = shmat(seg->shm_id, NULL, 0);
+ if (seg->threads == (void *) -1) {
perror("shmat");
return 1;
}
if (shm_attach_to_open_removed())
- shmctl(shm_id, IPC_RMID, NULL);
+ shmctl(seg->shm_id, IPC_RMID, NULL);
#endif
- memset(threads, 0, max_jobs * sizeof(struct thread_data));
- for (i = 0; i < max_jobs; i++)
- DRD_IGNORE_VAR(threads[i]);
- fio_debug_jobp = (unsigned int *)(threads + max_jobs);
+ nr_segments++;
+
+ memset(seg->threads, 0, JOBS_PER_SEG * sizeof(struct thread_data));
+ for (i = 0; i < JOBS_PER_SEG; i++)
+ DRD_IGNORE_VAR(seg->threads[i]);
+ seg->nr_threads = 0;
+
+ /* Not first segment, we're done */
+ if (nr_segments != 1) {
+ cur_segment++;
+ return 0;
+ }
+
+ fio_debug_jobp = (unsigned int *)(seg->threads + JOBS_PER_SEG);
*fio_debug_jobp = -1;
fio_warned = fio_debug_jobp + 1;
*fio_warned = 0;
flow_init();
-
return 0;
}
+/*
+ * The thread areas are shared between the main process and the job
+ * threads/processes, and is split into chunks of JOBS_PER_SEG. If the current
+ * segment has no more room, add a new chunk.
+ */
+static int expand_thread_area(void)
+{
+ struct thread_segment *seg = &segments[cur_segment];
+
+ if (nr_segments && seg->nr_threads < JOBS_PER_SEG)
+ return 0;
+
+ return add_thread_segment();
+}
+
static void dump_print_option(struct print_option *p)
{
const char *delim;
@@ -470,21 +486,19 @@ static void copy_opt_list(struct thread_data *dst, struct thread_data *src)
static struct thread_data *get_new_job(bool global, struct thread_data *parent,
bool preserve_eo, const char *jobname)
{
+ struct thread_segment *seg;
struct thread_data *td;
if (global)
return &def_thread;
- if (setup_thread_area()) {
+ if (expand_thread_area()) {
log_err("error: failed to setup shm segment\n");
return NULL;
}
- if (thread_number >= max_jobs) {
- log_err("error: maximum number of jobs (%d) reached.\n",
- max_jobs);
- return NULL;
- }
- td = &threads[thread_number++];
+ seg = &segments[cur_segment];
+ td = &seg->threads[seg->nr_threads++];
+ thread_number++;
*td = *parent;
INIT_FLIST_HEAD(&td->opt_list);
@@ -534,7 +548,8 @@ static void put_job(struct thread_data *td)
if (td->o.name)
free(td->o.name);
- memset(&threads[td->thread_number - 1], 0, sizeof(*td));
+ memset(td, 0, sizeof(*td));
+ segments[cur_segment].nr_threads--;
thread_number--;
}
@@ -2722,12 +2737,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
warnings_fatal = 1;
break;
case 'j':
- max_jobs = atoi(optarg);
- if (!max_jobs || max_jobs > REAL_MAX_JOBS) {
- log_err("fio: invalid max jobs: %d\n", max_jobs);
- do_exit++;
- exit_val = 1;
- }
+ /* we don't track/need this anymore, ignore it */
break;
case 'S':
did_arg = true;
diff --git a/ioengines.c b/ioengines.c
index d3be8026..5ac512ae 100644
--- a/ioengines.c
+++ b/ioengines.c
@@ -15,6 +15,8 @@
#include <dlfcn.h>
#include <fcntl.h>
#include <assert.h>
+#include <sys/types.h>
+#include <dirent.h>
#include "fio.h"
#include "diskutil.h"
@@ -45,7 +47,7 @@ static bool check_engine_ops(struct thread_data *td, struct ioengine_ops *ops)
* async engines aren't reliable with offload
*/
if ((td->o.io_submit_mode == IO_MODE_OFFLOAD) &&
- !(ops->flags & FIO_FAKEIO)) {
+ (ops->flags & FIO_NO_OFFLOAD)) {
log_err("%s: can't be used with offloaded submit. Use a sync "
"engine\n", ops->name);
return true;
@@ -91,7 +93,7 @@ static void *dlopen_external(struct thread_data *td, const char *engine)
char engine_path[PATH_MAX];
void *dlhandle;
- sprintf(engine_path, "%s/lib%s.so", FIO_EXT_ENG_DIR, engine);
+ sprintf(engine_path, "%s/fio-%s.so", FIO_EXT_ENG_DIR, engine);
dlhandle = dlopen(engine_path, RTLD_LAZY);
if (!dlhandle)
@@ -110,6 +112,10 @@ static struct ioengine_ops *dlopen_ioengine(struct thread_data *td,
struct ioengine_ops *ops;
void *dlhandle;
+ if (!strncmp(engine_lib, "linuxaio", 8) ||
+ !strncmp(engine_lib, "aio", 3))
+ engine_lib = "libaio";
+
dprint(FD_IO, "dload engine %s\n", engine_lib);
dlerror();
@@ -158,7 +164,7 @@ static struct ioengine_ops *__load_ioengine(const char *engine)
/*
* linux libaio has alias names, so convert to what we want
*/
- if (!strncmp(engine, "linuxaio", 8)) {
+ if (!strncmp(engine, "linuxaio", 8) || !strncmp(engine, "aio", 3)) {
dprint(FD_IO, "converting ioengine name: %s -> libaio\n",
engine);
engine = "libaio";
@@ -630,6 +636,34 @@ int td_io_get_file_size(struct thread_data *td, struct fio_file *f)
return td->io_ops->get_file_size(td, f);
}
+#ifdef CONFIG_DYNAMIC_ENGINES
+/* Load all dynamic engines in FIO_EXT_ENG_DIR for enghelp command */
+static void
+fio_load_dynamic_engines(struct thread_data *td)
+{
+ DIR *dirhandle = NULL;
+ struct dirent *dirent = NULL;
+ char engine_path[PATH_MAX];
+
+ dirhandle = opendir(FIO_EXT_ENG_DIR);
+ if (!dirhandle)
+ return;
+
+ while ((dirent = readdir(dirhandle)) != NULL) {
+ if (!strcmp(dirent->d_name, ".") ||
+ !strcmp(dirent->d_name, ".."))
+ continue;
+
+ sprintf(engine_path, "%s/%s", FIO_EXT_ENG_DIR, dirent->d_name);
+ dlopen_ioengine(td, engine_path);
+ }
+
+ closedir(dirhandle);
+}
+#else
+#define fio_load_dynamic_engines(td) do { } while (0)
+#endif
+
int fio_show_ioengine_help(const char *engine)
{
struct flist_head *entry;
@@ -638,8 +672,11 @@ int fio_show_ioengine_help(const char *engine)
char *sep;
int ret = 1;
+ memset(&td, 0, sizeof(struct thread_data));
+
if (!engine || !*engine) {
log_info("Available IO engines:\n");
+ fio_load_dynamic_engines(&td);
flist_for_each(entry, &engine_list) {
io_ops = flist_entry(entry, struct ioengine_ops, list);
log_info("\t%s\n", io_ops->name);
@@ -652,7 +689,6 @@ int fio_show_ioengine_help(const char *engine)
sep++;
}
- memset(&td, 0, sizeof(struct thread_data));
td.o.ioengine = (char *)engine;
io_ops = load_ioengine(&td);
diff --git a/ioengines.h b/ioengines.h
index 54dadba2..a928b211 100644
--- a/ioengines.h
+++ b/ioengines.h
@@ -8,7 +8,7 @@
#include "io_u.h"
#include "zbd_types.h"
-#define FIO_IOOPS_VERSION 26
+#define FIO_IOOPS_VERSION 27
#ifndef CONFIG_DYNAMIC_ENGINES
#define FIO_STATIC static
@@ -77,7 +77,8 @@ enum fio_ioengine_flags {
FIO_NOSTATS = 1 << 12, /* don't do IO stats */
FIO_NOFILEHASH = 1 << 13, /* doesn't hash the files for lookup later. */
FIO_ASYNCIO_SYNC_TRIM
- = 1 << 14 /* io engine has async ->queue except for trim */
+ = 1 << 14, /* io engine has async ->queue except for trim */
+ FIO_NO_OFFLOAD = 1 << 15, /* no async offload */
};
/*
diff --git a/iolog.h b/iolog.h
index 981081f9..9e382cc0 100644
--- a/iolog.h
+++ b/iolog.h
@@ -182,6 +182,7 @@ static inline struct io_sample *__get_sample(void *samples, int log_offset,
struct io_logs *iolog_cur_log(struct io_log *);
uint64_t iolog_nr_samples(struct io_log *);
void regrow_logs(struct thread_data *);
+void regrow_agg_logs(void);
static inline struct io_sample *get_sample(struct io_log *iolog,
struct io_logs *cur_log,
diff --git a/libfio.c b/libfio.c
index 7348b164..6144a474 100644
--- a/libfio.c
+++ b/libfio.c
@@ -156,8 +156,13 @@ void reset_all_stats(struct thread_data *td)
void reset_fio_state(void)
{
+ int i;
+
groupid = 0;
thread_number = 0;
+ cur_segment = 0;
+ for (i = 0; i < nr_segments; i++)
+ segments[i].nr_threads = 0;
stat_number = 0;
done_secs = 0;
}
diff --git a/options.c b/options.c
index b497d973..1e91b3e9 100644
--- a/options.c
+++ b/options.c
@@ -3733,14 +3733,32 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
{
.name = "sync",
.lname = "Synchronous I/O",
- .type = FIO_OPT_BOOL,
+ .type = FIO_OPT_STR,
.off1 = offsetof(struct thread_options, sync_io),
- .help = "Use O_SYNC for buffered writes",
- .def = "0",
- .parent = "buffered",
+ .help = "Use synchronous write IO",
+ .def = "none",
.hide = 1,
.category = FIO_OPT_C_IO,
.group = FIO_OPT_G_IO_TYPE,
+ .posval = {
+ { .ival = "none",
+ .oval = 0,
+ },
+ { .ival = "0",
+ .oval = 0,
+ },
+ { .ival = "sync",
+ .oval = O_SYNC,
+ },
+ { .ival = "1",
+ .oval = O_SYNC,
+ },
+#ifdef O_DSYNC
+ { .ival = "dsync",
+ .oval = O_DSYNC,
+ },
+#endif
+ },
},
#ifdef FIO_HAVE_WRITE_HINT
{
diff --git a/os/os-linux.h b/os/os-linux.h
index 65d3b429..5562b0da 100644
--- a/os/os-linux.h
+++ b/os/os-linux.h
@@ -58,7 +58,7 @@
#define OS_MAP_ANON MAP_ANONYMOUS
-#define FIO_EXT_ENG_DIR "/usr/lib/fio"
+#define FIO_EXT_ENG_DIR "/usr/local/lib/fio"
typedef cpu_set_t os_cpu_mask_t;
diff --git a/os/os-mac.h b/os/os-mac.h
index 2852ac67..683aab32 100644
--- a/os/os-mac.h
+++ b/os/os-mac.h
@@ -27,12 +27,6 @@
#define fio_swap32(x) OSSwapInt32(x)
#define fio_swap64(x) OSSwapInt64(x)
-/*
- * OSX has a pitifully small shared memory segment by default,
- * so default to a lower number of max jobs supported
- */
-#define FIO_MAX_JOBS 128
-
#ifndef CONFIG_CLOCKID_T
typedef unsigned int clockid_t;
#endif
diff --git a/os/os.h b/os/os.h
index 9a280e54..b46f4164 100644
--- a/os/os.h
+++ b/os/os.h
@@ -172,10 +172,6 @@ extern int fio_cpus_split(os_cpu_mask_t *mask, unsigned int cpu);
#endif
#endif
-#ifndef FIO_MAX_JOBS
-#define FIO_MAX_JOBS 4096
-#endif
-
#ifndef CONFIG_SOCKLEN_T
typedef unsigned int socklen_t;
#endif
diff --git a/os/windows/cpu-affinity.c b/os/windows/cpu-affinity.c
index 69997b24..46fd048d 100644
--- a/os/windows/cpu-affinity.c
+++ b/os/windows/cpu-affinity.c
@@ -14,7 +14,7 @@ int fio_setaffinity(int pid, os_cpu_mask_t cpumask)
bSuccess = SetThreadAffinityMask(h, cpumask);
if (!bSuccess)
log_err("fio_setaffinity failed: failed to set thread affinity (pid %d, mask %.16llx)\n",
- pid, cpumask);
+ pid, (long long unsigned) cpumask);
CloseHandle(h);
} else {
@@ -83,7 +83,7 @@ unsigned int cpus_online(void)
static void print_mask(os_cpu_mask_t *cpumask)
{
for (int i = 0; i < FIO_CPU_MASK_ROWS; i++)
- dprint(FD_PROCESS, "cpumask[%d]=%lu\n", i, cpumask->row[i]);
+ dprint(FD_PROCESS, "cpumask[%d]=%" PRIu64 "\n", i, cpumask->row[i]);
}
/* Return the index of the least significant set CPU in cpumask or -1 if no
@@ -99,7 +99,7 @@ int first_set_cpu(os_cpu_mask_t *cpumask)
int row_first_cpu;
row_first_cpu = __builtin_ffsll(cpumask->row[row]) - 1;
- dprint(FD_PROCESS, "row_first_cpu=%d cpumask->row[%d]=%lu\n",
+ dprint(FD_PROCESS, "row_first_cpu=%d cpumask->row[%d]=%" PRIu64 "\n",
row_first_cpu, row, cpumask->row[row]);
if (row_first_cpu > -1) {
mask_first_cpu = cpus_offset + row_first_cpu;
@@ -136,7 +136,7 @@ static int last_set_cpu(os_cpu_mask_t *cpumask)
row_last_cpu++;
}
- dprint(FD_PROCESS, "row_last_cpu=%d cpumask->row[%d]=%lu\n",
+ dprint(FD_PROCESS, "row_last_cpu=%d cpumask->row[%d]=%" PRIu64 "\n",
row_last_cpu, row, cpumask->row[row]);
if (row_last_cpu > -1) {
mask_last_cpu = cpus_offset + row_last_cpu;
@@ -213,13 +213,17 @@ static int mask_to_group_mask(os_cpu_mask_t *cpumask, int *processor_group, uint
needed_shift = FIO_CPU_MASK_STRIDE - bit_offset;
needed_mask_shift = FIO_CPU_MASK_STRIDE - needed;
needed_mask = (uint64_t)-1 >> needed_mask_shift;
- dprint(FD_PROCESS, "bit_offset=%d end=%d needed=%d needed_shift=%d needed_mask=%ld needed_mask_shift=%d\n", bit_offset, end, needed, needed_shift, needed_mask, needed_mask_shift);
+ dprint(FD_PROCESS,
+ "bit_offset=%d end=%d needed=%d needed_shift=%d needed_mask=%" PRIu64 "needed_mask_shift=%d\n",
+ bit_offset, end, needed, needed_shift, needed_mask,
+ needed_mask_shift);
group_cpumask |= (cpumask->row[row + 1] & needed_mask) << needed_shift;
}
group_cpumask &= (uint64_t)-1 >> (FIO_CPU_MASK_STRIDE - group_size);
/* Return group and mask */
- dprint(FD_PROCESS, "Returning group=%d group_mask=%lu\n", group, group_cpumask);
+ dprint(FD_PROCESS, "Returning group=%d group_mask=%" PRIu64 "\n",
+ group, group_cpumask);
*processor_group = group;
*affinity_mask = group_cpumask;
@@ -257,10 +261,8 @@ int fio_setaffinity(int pid, os_cpu_mask_t cpumask)
if (SetThreadGroupAffinity(handle, &new_group_affinity, NULL) != 0)
ret = 0;
else {
- log_err("fio_setaffinity: failed to set thread affinity "
- "(pid %d, group %d, mask %" PRIx64 ", "
- "GetLastError=%d)\n", pid, group, group_mask,
- GetLastError());
+ log_err("fio_setaffinity: failed to set thread affinity (pid %d, group %d, mask %" PRIx64 ", GetLastError=%lu)\n",
+ pid, group, group_mask, GetLastError());
goto err;
}
@@ -319,7 +321,7 @@ int fio_getaffinity(int pid, os_cpu_mask_t *mask)
goto err;
}
if (!GetProcessGroupAffinity(handle, &group_count, current_groups)) {
- log_err("%s: failed to get single group affinity for pid %d (%d)\n",
+ log_err("%s: failed to get single group affinity for pid %d (%lu)\n",
__func__, pid, GetLastError());
goto err;
}
@@ -329,7 +331,7 @@ int fio_getaffinity(int pid, os_cpu_mask_t *mask)
goto err;
}
if (!GetProcessAffinityMask(handle, &process_mask, &system_mask)) {
- log_err("%s: GetProcessAffinityMask() failed for pid\n",
+ log_err("%s: GetProcessAffinityMask() failed for pid %d\n",
__func__, pid);
goto err;
}
diff --git a/os/windows/dobuild.cmd b/os/windows/dobuild.cmd
index d06a2afa..08df3e87 100644
--- a/os/windows/dobuild.cmd
+++ b/os/windows/dobuild.cmd
@@ -34,7 +34,13 @@ if defined SIGN_FIO (
signtool sign /as /n "%SIGNING_CN%" /tr http://timestamp.digicert.com /td sha256 /fd sha256 ..\..\t\*.exe
)
-"%WIX%bin\candle" -nologo -arch %FIO_ARCH% -dFioVersionNumbers="%FIO_VERSION_NUMBERS%" install.wxs
+if exist ..\..\fio.pdb (
+ set FIO_PDB=true
+) else (
+ set FIO_PDB=false
+)
+
+"%WIX%bin\candle" -nologo -arch %FIO_ARCH% -dFioVersionNumbers="%FIO_VERSION_NUMBERS%" -dFioPDB="%FIO_PDB%" install.wxs
@if ERRORLEVEL 1 goto end
"%WIX%bin\candle" -nologo -arch %FIO_ARCH% examples.wxs
@if ERRORLEVEL 1 goto end
@@ -43,4 +49,4 @@ if defined SIGN_FIO (
if defined SIGN_FIO (
signtool sign /n "%SIGNING_CN%" /tr http://timestamp.digicert.com /td sha256 /fd sha256 %FIO_VERSION%-%FIO_ARCH%.msi
-) \ No newline at end of file
+)
diff --git a/os/windows/install.wxs b/os/windows/install.wxs
index dcb8c92c..f73ec5e2 100755
--- a/os/windows/install.wxs
+++ b/os/windows/install.wxs
@@ -27,6 +27,11 @@
<File Source="..\..\fio.exe"/>
<Environment Action="set" Part="last" Id="PATH" Name="PATH" Value="[INSTALLDIR]fio\" System="yes"/>
</Component>
+ <?if $(var.FioPDB) = true?>
+ <Component>
+ <File Id="fio.pdb" Name="fio.pdb" Source="..\..\fio.pdb"/>
+ </Component>
+ <?endif?>
<Component>
<File Id="README" Name="README.txt" Source="..\..\README"/>
</Component>
@@ -76,6 +81,9 @@
<Feature Id="AlwaysInstall" Absent="disallow" ConfigurableDirectory="INSTALLDIR" Display="hidden" Level="1" Title="Flexible I/O Tester">
<ComponentRef Id="fio.exe"/>
+ <?if $(var.FioPDB) = true?>
+ <ComponentRef Id="fio.pdb"/>
+ <?endif?>
<ComponentRef Id="HOWTO"/>
<ComponentRef Id="README"/>
<ComponentRef Id="REPORTING_BUGS"/>
diff --git a/os/windows/posix.c b/os/windows/posix.c
index 31271de0..9e9f12ef 100644
--- a/os/windows/posix.c
+++ b/os/windows/posix.c
@@ -168,7 +168,7 @@ int win_to_posix_error(DWORD winerr)
case ERROR_FILE_INVALID:
return ENXIO;
default:
- log_err("fio: windows error %d not handled\n", winerr);
+ log_err("fio: windows error %lu not handled\n", winerr);
return EIO;
}
@@ -188,7 +188,8 @@ int GetNumLogicalProcessors(void)
if (error == ERROR_INSUFFICIENT_BUFFER)
processor_info = malloc(len);
else {
- log_err("Error: GetLogicalProcessorInformation failed: %d\n", error);
+ log_err("Error: GetLogicalProcessorInformation failed: %lu\n",
+ error);
return -1;
}
diff --git a/oslib/getopt_long.c b/oslib/getopt_long.c
index 8ec77413..463919fb 100644
--- a/oslib/getopt_long.c
+++ b/oslib/getopt_long.c
@@ -16,8 +16,8 @@
#include "getopt.h"
-char *optarg = NULL;
-int optind = 0, opterr = 0, optopt = 0;
+char *optarg;
+int optind, opterr, optopt;
static struct getopt_private_state {
const char *optptr;
diff --git a/parse.h b/parse.h
index 1d2cbf74..e6663ed4 100644
--- a/parse.h
+++ b/parse.h
@@ -125,7 +125,7 @@ static inline void *td_var(void *to, const struct fio_option *o,
else
ret = to;
- return ret + offset;
+ return (void *) ((uintptr_t) ret + offset);
}
static inline int parse_is_percent(unsigned long long val)
diff --git a/server.c b/server.c
index 248a2d44..1b65297e 100644
--- a/server.c
+++ b/server.c
@@ -950,7 +950,7 @@ static int handle_update_job_cmd(struct fio_net_cmd *cmd)
return 0;
}
- td = &threads[tnumber - 1];
+ td = tnumber_to_td(tnumber);
convert_thread_options_to_cpu(&td->o, &pdu->top);
send_update_job_reply(cmd->tag, 0);
return 0;
diff --git a/stat.c b/stat.c
index 7f987c7f..d42586e7 100644
--- a/stat.c
+++ b/stat.c
@@ -2299,7 +2299,7 @@ void __show_run_stats(void)
free(opt_lists);
}
-void __show_running_run_stats(void)
+int __show_running_run_stats(void)
{
struct thread_data *td;
unsigned long long *rt;
@@ -2350,6 +2350,8 @@ void __show_running_run_stats(void)
free(rt);
fio_sem_up(stat_sem);
+
+ return 0;
}
static bool status_file_disabled;
@@ -2534,6 +2536,14 @@ void regrow_logs(struct thread_data *td)
td->flags &= ~TD_F_REGROW_LOGS;
}
+void regrow_agg_logs(void)
+{
+ enum fio_ddir ddir;
+
+ for (ddir = 0; ddir < DDIR_RWDIR_CNT; ddir++)
+ regrow_log(agg_io_log[ddir]);
+}
+
static struct io_logs *get_cur_log(struct io_log *iolog)
{
struct io_logs *cur_log;
diff --git a/stat.h b/stat.h
index 0d141666..6dd5ef74 100644
--- a/stat.h
+++ b/stat.h
@@ -319,7 +319,7 @@ extern void show_group_stats(struct group_run_stats *rs, struct buf_output *);
extern bool calc_thread_status(struct jobs_eta *je, int force);
extern void display_thread_status(struct jobs_eta *je);
extern void __show_run_stats(void);
-extern void __show_running_run_stats(void);
+extern int __show_running_run_stats(void);
extern void show_running_run_stats(void);
extern void check_for_running_stats(void);
extern void sum_thread_stats(struct thread_stat *dst, struct thread_stat *src, bool first);
diff --git a/steadystate.c b/steadystate.c
index bd2f70dd..2e3da1db 100644
--- a/steadystate.c
+++ b/steadystate.c
@@ -196,7 +196,7 @@ static bool steadystate_deviation(uint64_t iops, uint64_t bw,
return false;
}
-void steadystate_check(void)
+int steadystate_check(void)
{
int i, j, ddir, prev_groupid, group_ramp_time_over = 0;
unsigned long rate_time;
@@ -302,6 +302,7 @@ void steadystate_check(void)
}
}
}
+ return 0;
}
int td_steadystate_init(struct thread_data *td)
diff --git a/steadystate.h b/steadystate.h
index 51472c46..bbb86fbb 100644
--- a/steadystate.h
+++ b/steadystate.h
@@ -4,7 +4,7 @@
#include "thread_options.h"
extern void steadystate_free(struct thread_data *);
-extern void steadystate_check(void);
+extern int steadystate_check(void);
extern void steadystate_setup(void);
extern int td_steadystate_init(struct thread_data *);
extern uint64_t steadystate_bw_mean(struct thread_stat *);
diff --git a/t/latency_percentiles.py b/t/latency_percentiles.py
index 6ce4579a..cc437426 100755
--- a/t/latency_percentiles.py
+++ b/t/latency_percentiles.py
@@ -216,7 +216,7 @@ class FioLatTest():
file_data = file.read()
#
- # Read the first few lines and see if any of them begin with '3;fio-'
+ # Read the first few lines and see if any of them begin with '3;'
# If so, the line is probably terse output. Obviously, this only
# works for fio terse version 3 and it does not work for
# multi-line terse output
@@ -224,7 +224,7 @@ class FioLatTest():
lines = file_data.splitlines()
for i in range(8):
file_data = lines[i]
- if file_data.startswith('3;fio-'):
+ if file_data.startswith('3;'):
self.terse_data = file_data.split(';')
return True
diff --git a/t/memlock.c b/t/memlock.c
index 418dc3c4..9f5a3ea8 100644
--- a/t/memlock.c
+++ b/t/memlock.c
@@ -22,7 +22,7 @@ static void *worker(void *data)
for (index = 0; index + 4096 < size; index += 4096)
memset(&buf[index+512], 0x89, 512);
if (first) {
- printf("loop%d: did %lu MiB\n", i+1, size/(1024UL*1024UL));
+ printf("loop%d: did %lu MiB\n", i+1, td->mib);
first = 0;
}
}
diff --git a/t/zbd/test-zbd-support b/t/zbd/test-zbd-support
index 248423bb..acde3b3a 100755
--- a/t/zbd/test-zbd-support
+++ b/t/zbd/test-zbd-support
@@ -913,7 +913,7 @@ test48() {
for ((i=0;i<jobs;i++)); do
opts+=("--name=job$i" "--filename=$dev" "--offset=$off" "--bs=16K")
opts+=("--io_size=$zone_size" "--iodepth=256" "--thread=1")
- opts+=("--group_reporting=1")
+ opts+=("--size=$size" "--group_reporting=1")
# max_open_zones is already specified
opts+=($(job_var_opts_exclude "--max_open_zones"))
done
diff --git a/zbd.c b/zbd.c
index 905c0c2b..9327816a 100644
--- a/zbd.c
+++ b/zbd.c
@@ -718,6 +718,9 @@ static int zbd_reset_zone(struct thread_data *td, struct fio_file *f,
uint64_t length = (z+1)->start - offset;
int ret = 0;
+ if (z->wp == z->start)
+ return 0;
+
assert(is_valid_offset(f, offset + length - 1));
dprint(FD_ZBD, "%s: resetting wp of zone %u.\n", f->file_name,