same time, but writes get exclusive
access.
- The option may be post-fixed with a lock batch number. If
- set, then each thread/process may do that amount of IOs to
- the file before giving up the lock. Since lock acquisition is
- expensive, batching the lock/unlocks will speed up IO.
-
readwrite=str
rw=str Type of io pattern. Accepted values are:
LIBS = -lm -lz $(EXTLIBS)
PROGS = fio
SCRIPTS = fio_generate_plots
-UNAME := $(shell uname)
ifneq ($(wildcard config-host.mak),)
all:
SOURCE += lib/inet_aton.c
endif
-ifeq ($(UNAME), Linux)
+ifeq ($(CONFIG_TARGET_OS), Linux)
SOURCE += diskutil.c fifo.c blktrace.c cgroup.c trim.c engines/sg.c \
engines/binject.c profiles/tiobench.c
LIBS += -lpthread -ldl
LDFLAGS += -rdynamic
endif
-ifeq ($(UNAME), Android)
+ifeq ($(CONFIG_TARGET_OS), Android)
SOURCE += diskutil.c fifo.c blktrace.c trim.c profiles/tiobench.c
LIBS += -ldl
LDFLAGS += -rdynamic
endif
-ifeq ($(UNAME), SunOS)
+ifeq ($(CONFIG_TARGET_OS), SunOS)
LIBS += -lpthread -ldl
CPPFLAGS += -D__EXTENSIONS__
endif
-ifeq ($(UNAME), FreeBSD)
+ifeq ($(CONFIG_TARGET_OS), FreeBSD)
LIBS += -lpthread -lrt
LDFLAGS += -rdynamic
endif
-ifeq ($(UNAME), NetBSD)
+ifeq ($(CONFIG_TARGET_OS), NetBSD)
LIBS += -lpthread -lrt
LDFLAGS += -rdynamic
endif
-ifeq ($(UNAME), AIX)
+ifeq ($(CONFIG_TARGET_OS), AIX)
LIBS += -lpthread -ldl -lrt
CPPFLAGS += -D_LARGE_FILES -D__ppc__
LDFLAGS += -L/opt/freeware/lib -Wl,-blibpath:/opt/freeware/lib:/usr/lib:/lib -Wl,-bmaxdata:0x80000000
endif
-ifeq ($(UNAME), HP-UX)
+ifeq ($(CONFIG_TARGET_OS), HP-UX)
LIBS += -lpthread -ldl -lrt
CFLAGS += -D_LARGEFILE64_SOURCE -D_XOPEN_SOURCE_EXTENDED
endif
-ifeq ($(UNAME), Darwin)
+ifeq ($(CONFIG_TARGET_OS), Darwin)
LIBS += -lpthread -ldl
endif
-ifneq (,$(findstring CYGWIN,$(UNAME)))
+ifneq (,$(findstring CYGWIN,$(CONFIG_TARGET_OS)))
SOURCE := $(filter-out engines/mmap.c,$(SOURCE))
SOURCE += os/windows/posix.c
LIBS += -lpthread -lpsapi -lws2_32
T_AXMAP_OBJS += lib/lfsr.o lib/axmap.o
T_AXMAP_PROGS = t/axmap
+T_LFSR_TEST_OBJS = t/lfsr-test.o
+T_LFSR_TEST_OBJS += lib/lfsr.o
+T_LFSR_TEST_PROGS = t/lfsr-test
+
T_OBJS = $(T_SMALLOC_OBJS)
T_OBJS += $(T_IEEE_OBJS)
T_OBJS += $(T_ZIPF_OBJS)
T_OBJS += $(T_AXMAP_OBJS)
+T_OBJS += $(T_LFSR_TEST_OBJS)
T_PROGS = $(T_SMALLOC_PROGS)
T_PROGS += $(T_IEEE_PROGS)
T_PROGS += $(T_ZIPF_PROGS)
T_PROGS += $(T_AXMAP_PROGS)
+T_PROGS += $(T_LFSR_TEST_PROGS)
ifneq ($(findstring $(MAKEFLAGS),s),s)
ifndef V
prefix = /usr/local
bindir = $(prefix)/bin
-ifeq ($(UNAME), Darwin)
+ifeq ($(CONFIG_TARGET_OS), Darwin)
mandir = /usr/share/man
else
mandir = $(prefix)/man
t/axmap: $(T_AXMAP_OBJS)
$(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_AXMAP_OBJS) $(LIBS) $(LDFLAGS)
+t/lfsr-test: $(T_LFSR_TEST_OBJS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_LFSR_TEST_OBJS) $(LIBS) $(LDFLAGS)
+
clean: FORCE
- -rm -f .depend $(GFIO_OBJS) $(OBJS) $(T_OBJS) $(PROGS) $(T_PROGS) core.* core gfio FIO-VERSION-FILE config-host.mak cscope.out *.d
+ -rm -f .depend $(GFIO_OBJS) $(OBJS) $(T_OBJS) $(PROGS) $(T_PROGS) core.* core gfio FIO-VERSION-FILE config-host.mak config-host.h cscope.out *.d
cscope:
@cscope -b -R
$ fio
--debug Enable some debugging options (see below)
+ --parse-only Parse options only, don't start any IO
--output Write output to file
--runtime Runtime in seconds
--latency-log Generate per-job latency logs
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/ipc.h>
-#ifndef FIO_NO_HAVE_SHM_H
-#include <sys/shm.h>
-#endif
#include <sys/mman.h>
#include "fio.h"
+#ifndef FIO_NO_HAVE_SHM_H
+#include <sys/shm.h>
+#endif
#include "hash.h"
#include "smalloc.h"
#include "verify.h"
return 1;
}
- if (ddir_rw_sum(td->io_bytes) < td->o.size) {
+ if (td->o.size != -1ULL && ddir_rw_sum(td->io_bytes) < td->o.size) {
uint64_t diff;
/*
o->nr_files = le32_to_cpu(top->nr_files);
o->open_files = le32_to_cpu(top->open_files);
o->file_lock_mode = le32_to_cpu(top->file_lock_mode);
- o->lockfile_batch = le32_to_cpu(top->lockfile_batch);
o->odirect = le32_to_cpu(top->odirect);
o->invalidate_cache = le32_to_cpu(top->invalidate_cache);
o->create_serialize = le32_to_cpu(top->create_serialize);
top->nr_files = cpu_to_le32(o->nr_files);
top->open_files = cpu_to_le32(o->open_files);
top->file_lock_mode = cpu_to_le32(o->file_lock_mode);
- top->lockfile_batch = cpu_to_le32(o->lockfile_batch);
top->odirect = cpu_to_le32(o->odirect);
top->invalidate_cache = cpu_to_le32(o->invalidate_cache);
top->create_serialize = cpu_to_le32(o->create_serialize);
targetos=""
cpu=""
+cross_prefix=${cross_prefix-${CROSS_COMPILE}}
cc="${CC-${cross_prefix}gcc}"
# default options
targetos=`uname -s`
fi
+echo "# Automatically generated by configure - do not modify" > $config_host_mak
+printf "# Configured with:" >> $config_host_mak
+printf " '%s'" "$0" "$@" >> $config_host_mak
+echo >> $config_host_mak
+echo "CONFIG_TARGET_OS=$targetos" >> $config_host_mak
+
# Some host OSes need non-standard checks for which CPU to use.
# Note that these checks are broken for cross-compilation: if you're
# cross-compiling to one of these OSes then you'll need to specify
echo "EXTFLAGS=$CFLAGS -include config-host.h -D_GNU_SOURCE" >> $config_host_mak
exit 0
;;
-Android)
- output_sym "CONFIG_32BIT"
- output_sym "CONFIG_LITTLE_ENDIAN"
- output_sym "CONFIG_SOCKLEN_T"
- output_sym "CONFIG_GETTIMEOFDAY"
- output_sym "CONFIG_CLOCK_GETTIME"
- output_sym "CONFIG_CLOCK_MONOTONIC"
- echo "CC=$cc" >> $config_host_mak
- echo "EXTFLAGS=$CFLAGS -include config-host.h -DFIO_NO_HAVE_SHM_H -D_GNU_SOURCE" >> $config_host_mak
- exit 0
esac
if test ! -z "$cpu" ; then
cc="${CC-${cross_prefix}gcc}"
+##########################################
+# check cross compile
+
+cross_compile="no"
+cat > $TMPC <<EOF
+int main(void)
+{
+ return 0;
+}
+EOF
+if compile_prog "" "" "cross"; then
+ $TMPE 2>/dev/null || cross_compile="yes"
+else
+ fatal "compile test failed"
+fi
+
##########################################
# check endianness
bigendian="no"
-cat > $TMPC <<EOF
+if test "$cross_compile" = "no" ; then
+ cat > $TMPC <<EOF
#include <inttypes.h>
int main(void)
{
return (*((uint8_t*)(&i))) == 0x67;
}
EOF
-if compile_prog "" "" "endian"; then
- $TMPE && bigendian="yes"
+ if compile_prog "" "" "endian"; then
+ $TMPE && bigendian="yes"
+ fi
+else
+ # If we're cross compiling, try our best to work it out and rely on the
+ # run-time check to fail if we get it wrong.
+ cat > $TMPC <<EOF
+#include <endian.h>
+int main(void)
+{
+#if __BYTE_ORDER != __BIG_ENDIAN
+# error "Unknown endianness"
+#endif
+}
+EOF
+ compile_prog "" "" "endian" && bigendian="yes"
+ check_define "__ARMEB__" && bigendian="yes"
+ check_define "__MIPSEB__" && bigendian="yes"
fi
echo "CPU $cpu"
echo "Big endian $bigendian"
echo "Compiler $cc"
+echo "Cross compile $cross_compile"
echo
##########################################
# check for wordsize
wordsize="0"
cat > $TMPC <<EOF
-#include <stdio.h>
+#include <limits.h>
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
int main(void)
{
- unsigned int wsize = sizeof(long) * 8;
- printf("%d\n", wsize);
+ BUILD_BUG_ON(sizeof(long)*CHAR_BIT != WORDSIZE);
return 0;
}
EOF
-if compile_prog "" "" "wordsize"; then
- wordsize=`$TMPE`
+if compile_prog "-DWORDSIZE=32" "" "wordsize"; then
+ wordsize="32"
+elif compile_prog "-DWORDSIZE=64" "" "wordsize"; then
+ wordsize="64"
+else
+ fatal "Unknown wordsize"
fi
echo "Wordsize $wordsize"
# socklen_t probe
socklen_t="no"
cat > $TMPC << EOF
-#include <string.h>
-#include <netinet/in.h>
+#include <sys/socket.h>
int main(int argc, char **argv)
{
socklen_t len = 0;
#############################################################################
-echo "# Automatically generated by configure - do not modify" > $config_host_mak
-printf "# Configured with:" >> $config_host_mak
-printf " '%s'" "$0" "$@" >> $config_host_mak
-echo >> $config_host_mak
-
if test "$wordsize" = "64" ; then
output_sym "CONFIG_64BIT"
elif test "$wordsize" = "32" ; then
/*
* if io is protected by a semaphore, this is set
*/
- struct fio_mutex *lock;
- void *lock_owner;
- unsigned int lock_batch;
- enum fio_ddir lock_ddir;
+ union {
+ struct fio_mutex *lock;
+ struct fio_rwlock *rwlock;
+ };
/*
* block map for random io
* racy, need the __f->lock locked
*/
f->lock = __f->lock;
- f->lock_owner = __f->lock_owner;
- f->lock_batch = __f->lock_batch;
- f->lock_ddir = __f->lock_ddir;
from_hash = 1;
} else {
dprint(FD_FILE, "file not found in hash %s\n", f->file_name);
seed = td->rand_seeds[FIO_RAND_BLOCK_OFF];
- if (!lfsr_init(&f->lfsr, blocks, seed))
+ if (!lfsr_init(&f->lfsr, blocks, seed, seed & 0xF))
continue;
} else if (!td->o.norandommap) {
f->io_axmap = axmap_new(blocks);
td->o.filename = NULL;
free(td->files);
+ free(td->file_locks);
td->files_index = 0;
td->files = NULL;
+ td->file_locks = NULL;
td->o.nr_files = 0;
}
log_err("fio: realloc OOM\n");
assert(0);
}
+ if (td->o.file_lock_mode != FILE_LOCK_NONE) {
+ td->file_locks = realloc(td->file_locks, new_size);
+ if (!td->file_locks) {
+ log_err("fio: realloc OOM\n");
+ assert(0);
+ }
+ td->file_locks[cur_files] = FILE_LOCK_NONE;
+ }
td->files_size = new_size;
}
td->files[cur_files] = f;
case FILE_LOCK_NONE:
break;
case FILE_LOCK_READWRITE:
- f->lock = fio_mutex_rw_init();
+ f->rwlock = fio_rwlock_init();
break;
case FILE_LOCK_EXCLUSIVE:
f->lock = fio_mutex_init(FIO_MUTEX_UNLOCKED);
if (!f->lock || td->o.file_lock_mode == FILE_LOCK_NONE)
return;
- if (f->lock_owner == td && f->lock_batch--)
- return;
-
if (td->o.file_lock_mode == FILE_LOCK_READWRITE) {
if (ddir == DDIR_READ)
- fio_mutex_down_read(f->lock);
+ fio_rwlock_read(f->rwlock);
else
- fio_mutex_down_write(f->lock);
+ fio_rwlock_write(f->rwlock);
} else if (td->o.file_lock_mode == FILE_LOCK_EXCLUSIVE)
fio_mutex_down(f->lock);
- f->lock_owner = td;
- f->lock_batch = td->o.lockfile_batch;
- f->lock_ddir = ddir;
+ td->file_locks[f->fileno] = td->o.file_lock_mode;
}
void unlock_file(struct thread_data *td, struct fio_file *f)
{
if (!f->lock || td->o.file_lock_mode == FILE_LOCK_NONE)
return;
- if (f->lock_batch)
- return;
-
- if (td->o.file_lock_mode == FILE_LOCK_READWRITE) {
- const int is_read = f->lock_ddir == DDIR_READ;
- int val = fio_mutex_getval(f->lock);
-
- if ((is_read && val == 1) || (!is_read && val == -1))
- f->lock_owner = NULL;
-
- if (is_read)
- fio_mutex_up_read(f->lock);
- else
- fio_mutex_up_write(f->lock);
- } else if (td->o.file_lock_mode == FILE_LOCK_EXCLUSIVE) {
- int val = fio_mutex_getval(f->lock);
-
- if (val == 0)
- f->lock_owner = NULL;
+ if (td->o.file_lock_mode == FILE_LOCK_READWRITE)
+ fio_rwlock_unlock(f->rwlock);
+ else if (td->o.file_lock_mode == FILE_LOCK_EXCLUSIVE)
fio_mutex_up(f->lock);
- }
+
+ td->file_locks[f->fileno] = FILE_LOCK_NONE;
}
void unlock_file_all(struct thread_data *td, struct fio_file *f)
{
- if (f->lock_owner != td)
- return;
-
- f->lock_batch = 0;
- unlock_file(td, f);
+ if (td->file_locks[f->fileno] != FILE_LOCK_NONE)
+ unlock_file(td, f);
}
static int recurse_dir(struct thread_data *td, const char *dirname)
td->files = malloc(org->files_index * sizeof(f));
+ if (td->o.file_lock_mode != FILE_LOCK_NONE)
+ td->file_locks = malloc(org->files_index);
+
for_each_file(org, f, i) {
struct fio_file *__f;
time, but writes get exclusive access.
.RE
.P
-The option may be post-fixed with a lock batch number. If set, then each
-thread/process may do that amount of IOs to the file before giving up the lock.
-Since lock acquisition is expensive, batching the lock/unlocks will speed up IO.
-.RE
-.P
.BI opendir \fR=\fPstr
Recursively open any files below directory \fIstr\fR.
.TP
struct rusage ru_end;
struct fio_file **files;
+ unsigned char *file_locks;
unsigned int files_size;
unsigned int files_index;
unsigned int nr_open_files;
/*
* Rate state
*/
- unsigned long long rate_bps[DDIR_RWDIR_CNT];
+ uint64_t rate_bps[DDIR_RWDIR_CNT];
long rate_pending_usleep[DDIR_RWDIR_CNT];
unsigned long rate_bytes[DDIR_RWDIR_CNT];
unsigned long rate_blocks[DDIR_RWDIR_CNT];
struct timeval lastrate[DDIR_RWDIR_CNT];
- unsigned long long total_io_size;
- unsigned long long fill_device_size;
+ uint64_t total_io_size;
+ uint64_t fill_device_size;
unsigned long io_issues[DDIR_RWDIR_CNT];
- unsigned long long io_blocks[DDIR_RWDIR_CNT];
- unsigned long long this_io_blocks[DDIR_RWDIR_CNT];
- unsigned long long io_bytes[DDIR_RWDIR_CNT];
- unsigned long long io_skip_bytes;
- unsigned long long this_io_bytes[DDIR_RWDIR_CNT];
- unsigned long long zone_bytes;
+ uint64_t io_blocks[DDIR_RWDIR_CNT];
+ uint64_t this_io_blocks[DDIR_RWDIR_CNT];
+ uint64_t io_bytes[DDIR_RWDIR_CNT];
+ uint64_t io_skip_bytes;
+ uint64_t this_io_bytes[DDIR_RWDIR_CNT];
+ uint64_t zone_bytes;
struct fio_mutex *mutex;
/*
fi
GNUPLOT=$(which gnuplot)
-if [ ! -x $GNUPLOT ]; then
+if [ ! -x "$GNUPLOT" ]; then
echo You need gnuplot installed to generate graphs
exit 1
fi
#include <string.h>
#include <errno.h>
#include <sys/ipc.h>
-#ifndef FIO_NO_HAVE_SHM_H
-#include <sys/shm.h>
-#endif
#include <sys/types.h>
#include <sys/stat.h>
#include "fio.h"
+#ifndef FIO_NO_HAVE_SHM_H
+#include <sys/shm.h>
+#endif
+
#include "parse.h"
#include "smalloc.h"
#include "filehash.h"
static int max_jobs = FIO_MAX_JOBS;
static int dump_cmdline;
static int def_timeout;
+static int parse_only;
static struct thread_data def_thread;
struct thread_data *threads = NULL;
.has_arg = required_argument,
.val = 'd' | FIO_CLIENT_FLAG,
},
+ {
+ .name = (char *) "parse-only",
+ .has_arg = no_argument,
+ .val = 'P' | FIO_CLIENT_FLAG,
+ },
{
.name = (char *) "section",
.has_arg = required_argument,
/*
* if we are just dumping the output command line, don't add the job
*/
- if (dump_cmdline) {
+ if (dump_cmdline || parse_only) {
put_job(td);
return 0;
}
printf(" --debug=options\tEnable debug logging. May be one/more of:\n"
"\t\t\tprocess,file,io,mem,blktrace,verify,random,parse,\n"
"\t\t\tdiskutil,job,mutex,profile,time,net\n");
+ printf(" --parse-only\t\tParse options only, don't start any IO\n");
printf(" --output\t\tWrite output to file\n");
printf(" --runtime\t\tRuntime in seconds\n");
printf(" --latency-log\t\tGenerate per-job latency logs\n");
if (set_debug(optarg))
do_exit++;
break;
+ case 'P':
+ parse_only = 1;
+ break;
case 'x': {
size_t new_size;
fio_options_free(&def_thread);
if (!thread_number) {
- if (dump_cmdline)
+ if (dump_cmdline || parse_only)
return 0;
if (exec_profile)
return 0;
* io's that have been actually submitted to an async engine,
* and cur_depth is meaningless for sync engines.
*/
- if (td->io_u_in_flight) {
+ while (td->io_u_in_flight) {
int fio_unused ret;
- ret = io_u_queued_complete(td, td->io_u_in_flight, NULL);
+ ret = io_u_queued_complete(td, 1, NULL);
}
fio_gettime(&t, NULL);
const char *osptr;
int opt;
+ optarg = NULL;
+
/* getopt() relies on a number of different global state
variables, which can make this really confusing if there is
more than one use of getopt() in the same program. This
#include <stdio.h>
+#include <math.h>
#include "lfsr.h"
/*
- * From table 3 of
+ * LFSR taps retrieved from:
+ * http://home1.gte.net/res0658s/electronics/LFSRtaps.html
*
- * http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
+ * The memory overhead of the following tap table should be relatively small,
+ * no more than 400 bytes.
*/
-static struct lfsr_taps lfsr_taps[] = {
- {
- .length = 16,
- .taps = { 16, 15, 13, 4, },
- },
- {
- .length = 17,
- .taps = { 17, 14, },
- },
- {
- .length = 18,
- .taps = { 18, 11, },
- },
- {
- .length = 19,
- .taps = { 19, 6, 2, 1, },
- },
- {
- .length = 20,
- .taps = { 20, 17, },
- },
- {
- .length = 21,
- .taps = { 21, 19, },
- },
- {
- .length = 22,
- .taps = { 22, 21, },
- },
- {
- .length = 23,
- .taps = { 23, 18, },
- },
- {
- .length = 24,
- .taps = { 24, 23, 22, 17, },
- },
- {
- .length = 25,
- .taps = { 25, 22, },
- },
- {
- .length = 26,
- .taps = {26, 6, 2, 1, },
- },
- {
- .length = 27,
- .taps = { 27, 5, 2, 1, },
- },
- {
- .length = 28,
- .taps = { 28, 25, },
- },
- {
- .length = 29,
- .taps = {29, 27, },
- },
- {
- .length = 30,
- .taps = { 30, 6, 4, 1, },
- },
- {
- .length = 31,
- .taps = { 31, 28, },
- },
- {
- .length = 32,
- .taps = { 32, 22, 2, 1, },
- },
- {
- .length = 33,
- .taps = { 33, 20, },
- },
- {
- .length = 34,
- .taps = { 34, 27, 2, 1, },
- },
- {
- .length = 35,
- .taps = { 35, 33, },
- },
- {
- .length = 36,
- .taps = { 36, 25, },
- },
- {
- .length = 37,
- .taps = { 37, 5, 4, 3, 2, 1, },
- },
- {
- .length = 38,
- .taps = { 38, 6, 5, 1, },
- },
- {
- .length = 39,
- .taps = { 39, 35, },
- },
- {
- .length = 40,
- .taps = { 40, 38, 21, 19, },
- },
- {
- .length = 41,
- .taps = { 41, 38, },
- },
- {
- .length = 42,
- .taps = { 42, 41, 20, 19, },
- },
- {
- .length = 43,
- .taps = { 43, 42, 38, 37, },
- },
- {
- .length = 44,
- .taps = { 44, 43, 38, 37, },
- },
- {
- .length = 45,
- .taps = { 45, 44, 42, 41, },
- },
- {
- .length = 46,
- .taps = { 46, 45, 26, 25, },
- },
- {
- .length = 47,
- .taps = { 47, 42, },
- },
- {
- .length = 48,
- .taps = { 48, 47, 21, 20, },
- },
- {
- .length = 49,
- .taps = { 49, 40, },
- },
- {
- .length = 50,
- .taps = { 50, 49, 36, 35, },
- },
- {
- .length = 51,
- .taps = { 51, 50, 36, 35, },
- },
- {
- .length = 52,
- .taps = { 52, 49, },
- },
- {
- .length = 53,
- .taps = { 53, 52, 38, 37 },
- },
- {
- .length = 54,
- .taps = { 54, 53, 18, 17 },
- },
- {
- .length = 55,
- .taps = { 55, 31, },
- },
- {
- .length = 56,
- .taps = { 56, 55, 35, 34, },
- },
- {
- .length = 57,
- .taps = { 57, 50, },
- },
- {
- .length = 58,
- .taps = { 58, 39, },
- },
- {
- .length = 59,
- .taps = { 59, 58, 38, 37, },
- },
- {
- .length = 60,
- .taps = { 60, 59, },
- },
- {
- .length = 61,
- .taps = { 61, 60, 46, 45, },
- },
- {
- .length = 62,
- .taps = { 62, 61, 6, 5, },
- },
- {
- .length = 63,
- .taps = { 63, 62, },
- },
+static uint8_t taps[64][FIO_MAX_TAPS] =
+{
+ {0}, {0}, {0}, //LFSRs with less that 3-bits cannot exist
+ {3, 2}, //Tap position for 3-bit LFSR
+ {4, 3}, //Tap position for 4-bit LFSR
+ {5, 3}, //Tap position for 5-bit LFSR
+ {6, 5}, //Tap position for 6-bit LFSR
+ {7, 6}, //Tap position for 7-bit LFSR
+ {8, 6, 5 ,4}, //Tap position for 8-bit LFSR
+ {9, 5}, //Tap position for 9-bit LFSR
+ {10, 7}, //Tap position for 10-bit LFSR
+ {11, 9}, //Tap position for 11-bit LFSR
+ {12, 6, 4, 1}, //Tap position for 12-bit LFSR
+ {13, 4, 3, 1}, //Tap position for 13-bit LFSR
+ {14, 5, 3, 1}, //Tap position for 14-bit LFSR
+ {15, 14}, //Tap position for 15-bit LFSR
+ {16, 15, 13, 4}, //Tap position for 16-bit LFSR
+ {17, 14}, //Tap position for 17-bit LFSR
+ {18, 11}, //Tap position for 18-bit LFSR
+ {19, 6, 2, 1}, //Tap position for 19-bit LFSR
+ {20, 17}, //Tap position for 20-bit LFSR
+ {21, 19}, //Tap position for 21-bit LFSR
+ {22, 21}, //Tap position for 22-bit LFSR
+ {23, 18}, //Tap position for 23-bit LFSR
+ {24, 23, 22, 17}, //Tap position for 24-bit LFSR
+ {25, 22}, //Tap position for 25-bit LFSR
+ {26, 6, 2, 1}, //Tap position for 26-bit LFSR
+ {27, 5, 2, 1}, //Tap position for 27-bit LFSR
+ {28, 25}, //Tap position for 28-bit LFSR
+ {29, 27}, //Tap position for 29-bit LFSR
+ {30, 6, 4, 1}, //Tap position for 30-bit LFSR
+ {31, 28}, //Tap position for 31-bit LFSR
+ {32, 31, 29, 1}, //Tap position for 32-bit LFSR
+ {33, 20}, //Tap position for 33-bit LFSR
+ {34, 27, 2, 1}, //Tap position for 34-bit LFSR
+ {35, 33}, //Tap position for 35-bit LFSR
+ {36, 25}, //Tap position for 36-bit LFSR
+ {37, 5, 4, 3, 2, 1}, //Tap position for 37-bit LFSR
+ {38, 6, 5, 1}, //Tap position for 38-bit LFSR
+ {39, 35}, //Tap position for 39-bit LFSR
+ {40, 38, 21, 19}, //Tap position for 40-bit LFSR
+ {41, 38}, //Tap position for 41-bit LFSR
+ {42, 41, 20, 19}, //Tap position for 42-bit LFSR
+ {43, 42, 38, 37}, //Tap position for 43-bit LFSR
+ {44, 43, 18, 17}, //Tap position for 44-bit LFSR
+ {45, 44, 42, 41}, //Tap position for 45-bit LFSR
+ {46, 45, 26, 25}, //Tap position for 46-bit LFSR
+ {47, 42}, //Tap position for 47-bit LFSR
+ {48, 47, 21, 20}, //Tap position for 48-bit LFSR
+ {49, 40}, //Tap position for 49-bit LFSR
+ {50, 49, 24, 23}, //Tap position for 50-bit LFSR
+ {51, 50, 36, 35}, //Tap position for 51-bit LFSR
+ {52, 49}, //Tap position for 52-bit LFSR
+ {53, 52, 38, 37}, //Tap position for 53-bit LFSR
+ {54, 53, 18, 17}, //Tap position for 54-bit LFSR
+ {55, 31}, //Tap position for 55-bit LFSR
+ {56, 55, 35, 34}, //Tap position for 56-bit LFSR
+ {57, 50}, //Tap position for 57-bit LFSR
+ {58, 39}, //Tap position for 58-bit LFSR
+ {59, 58, 38, 37}, //Tap position for 59-bit LFSR
+ {60, 59}, //Tap position for 60-bit LFSR
+ {61, 60, 46, 45}, //Tap position for 61-bit LFSR
+ {62, 61, 6, 5}, //Tap position for 62-bit LFSR
+ {63, 62}, //Tap position for 63-bit LFSR
};
-#define FIO_LFSR_CRANKS 128
+#define __LFSR_NEXT(__fl, __v) \
+ __v = ((__v >> 1) | __fl->cached_bit) ^ \
+ (((__v & 1UL) - 1UL) & __fl->xormask);
-static uint64_t __lfsr_next(uint64_t v, struct lfsr_taps *lt)
+static inline void __lfsr_next(struct fio_lfsr *fl, unsigned int spin)
{
- uint64_t xor_mask = 0;
- int i;
-
- for (i = 0; lt->taps[i]; i++)
- xor_mask ^= (v << (lt->taps[i] - 1));
-
- xor_mask &= ~(~0UL << 1) << (lt->length - 1);
- return xor_mask | (v >> 1);
+ /*
+ * This should be O(1) since most compilers will create a jump table for
+ * this switch.
+ */
+ switch (spin) {
+ case 16: __LFSR_NEXT(fl, fl->last_val);
+ case 15: __LFSR_NEXT(fl, fl->last_val);
+ case 14: __LFSR_NEXT(fl, fl->last_val);
+ case 13: __LFSR_NEXT(fl, fl->last_val);
+ case 12: __LFSR_NEXT(fl, fl->last_val);
+ case 11: __LFSR_NEXT(fl, fl->last_val);
+ case 10: __LFSR_NEXT(fl, fl->last_val);
+ case 9: __LFSR_NEXT(fl, fl->last_val);
+ case 8: __LFSR_NEXT(fl, fl->last_val);
+ case 7: __LFSR_NEXT(fl, fl->last_val);
+ case 6: __LFSR_NEXT(fl, fl->last_val);
+ case 5: __LFSR_NEXT(fl, fl->last_val);
+ case 4: __LFSR_NEXT(fl, fl->last_val);
+ case 3: __LFSR_NEXT(fl, fl->last_val);
+ case 2: __LFSR_NEXT(fl, fl->last_val);
+ case 1: __LFSR_NEXT(fl, fl->last_val);
+ case 0: __LFSR_NEXT(fl, fl->last_val);
+ default: break;
+ }
}
+/*
+ * lfsr_next does the following:
+ *
+ * a. Return if the number of max values has been exceeded.
+ * b. Check if we have a spin value that produces a repeating subsequence.
+ * This is previously calculated in `prepare_spin` and cycle_length should
+ * be > 0. If we do have such a spin:
+ *
+ * i. Decrement the calculated cycle.
+ * ii. If it reaches zero, add "+1" to the spin and reset the cycle_length
+ * (we have it cached in the struct fio_lfsr)
+ *
+ * In either case, continue with the calculation of the next value.
+ * c. Check if the calculated value exceeds the desirable range. In this case,
+ * go back to b, else return.
+ */
int lfsr_next(struct fio_lfsr *fl, uint64_t *off, uint64_t last)
{
- if (fl->num_vals > fl->max_val)
+ unsigned int spin = fl->spin;
+
+ if (fl->num_vals++ > fl->max_val)
return 1;
do {
- fl->last_val = __lfsr_next(fl->last_val, &fl->taps);
- if (fl->last_val - 1 <= fl->max_val &&
- fl->last_val <= last)
- break;
- } while (1);
-
- *off = fl->last_val - 1;
- fl->num_vals++;
+ if (fl->cycle_length) {
+ fl->cycle_length--;
+ if (!fl->cycle_length) {
+ __lfsr_next(fl, fl->spin + 1);
+ fl->cycle_length = fl->cached_cycle_length;
+ goto check;
+ }
+ }
+ __lfsr_next(fl, spin);
+check: ;
+ } while (fl->last_val > fl->max_val);
+
+ *off = fl->last_val;
return 0;
}
-static struct lfsr_taps *find_lfsr(uint64_t size)
+static uint64_t lfsr_create_xormask(uint8_t *taps)
{
int i;
+ uint64_t xormask = 0;
- for (i = 0; lfsr_taps[i].length; i++)
- if (((1UL << lfsr_taps[i].length) + FIO_LFSR_CRANKS) >= size)
- return &lfsr_taps[i];
+ for(i = 0; i < FIO_MAX_TAPS && taps[i] != 0; i++)
+ xormask |= 1UL << (taps[i] - 1);
- return NULL;
+ return xormask;
}
-void lfsr_reset(struct fio_lfsr *fl, unsigned long seed)
+static uint8_t *find_lfsr(uint64_t size)
{
- unsigned int i;
+ int i;
- fl->last_val = seed;
- fl->num_vals = 0;
+ for (i = 3; i < 64; i++)
+ if ((1UL << i) > size) /* TODO: Explain why. */
+ return taps[i];
- for (i = 0; i < FIO_LFSR_CRANKS; i++)
- fl->last_val = __lfsr_next(fl->last_val, &fl->taps);
+ return NULL;
}
-int lfsr_init(struct fio_lfsr *fl, uint64_t size, unsigned long seed)
+/*
+ * It is well-known that all maximal n-bit LFSRs will start repeating
+ * themselves after their 2^n iteration. The introduction of spins however, is
+ * possible to create a repetition of a sub-sequence before we hit that mark.
+ * This happens if:
+ *
+ * [1]: ((2^n - 1) * i) % (spin + 1) == 0,
+ * where "n" is LFSR's bits and "i" any number within the range [1,spin]
+ *
+ * It is important to know beforehand if a spin can cause a repetition of a
+ * sub-sequence (cycle) and its length. However, calculating (2^n - 1) * i may
+ * produce a buffer overflow for "n" close to 64, so we expand the above to:
+ *
+ * [2]: (2^n - 1) -> (x * (spin + 1) + y), where x >= 0 and 0 <= y <= spin
+ *
+ * Thus, [1] is equivalent to (y * i) % (spin + 1) == 0;
+ * Also, the cycle's length will be (x * i) + (y * i) / (spin + 1)
+ */
+int prepare_spin(struct fio_lfsr *fl, unsigned int spin)
{
- struct lfsr_taps *tap;
+ uint64_t max = (fl->cached_bit << 1) - 1;
+ uint64_t x, y;
int i;
- tap = find_lfsr(size);
- if (!tap)
+ if (spin > 15)
return 1;
- fl->max_val = size - 1;
- fl->taps.length = tap->length;
+ x = max / (spin + 1);
+ y = max % (spin + 1);
+ fl->cycle_length = 0; /* No cycle occurs, other than the expected */
+ fl->spin = spin;
- for (i = 0; i < FIO_MAX_TAPS; i++) {
- fl->taps.taps[i] = tap->taps[i];
- if (!fl->taps.taps[i])
+ for (i = 1; i <= spin; i++) {
+ if ((y * i) % (spin + 1) == 0) {
+ fl->cycle_length = (x * i) + (y * i) / (spin + 1);
break;
+ }
}
+ fl->cached_cycle_length = fl->cycle_length;
+
+ return 0;
+}
+
+int lfsr_reset(struct fio_lfsr *fl, unsigned long seed)
+{
+ uint64_t bitmask = (fl->cached_bit << 1) - 1;
+
+ fl->num_vals = 0;
+ fl->last_val = seed & bitmask;
+
+ /* All-ones state is illegal for XNOR LFSRs */
+ if (fl->last_val == bitmask)
+ return 1;
+
+ return 0;
+}
+
+int lfsr_init(struct fio_lfsr *fl, uint64_t nums, unsigned long seed,
+ unsigned int spin)
+{
+ uint8_t *lfsr_taps;
+
+ lfsr_taps = find_lfsr(nums);
+ if (!lfsr_taps)
+ return 1;
+
+ fl->max_val = nums - 1;
+ fl->xormask = lfsr_create_xormask(lfsr_taps);
+ fl->cached_bit = 1UL << (lfsr_taps[0] - 1);
+
+ if (prepare_spin(fl, spin))
+ return 1;
+
+ if (lfsr_reset(fl, seed))
+ return 1;
- lfsr_reset(fl, seed);
return 0;
}
#include <inttypes.h>
-#define FIO_MAX_TAPS 8
+#define FIO_MAX_TAPS 6
struct lfsr_taps {
unsigned int length;
struct fio_lfsr {
+ uint64_t xormask;
uint64_t last_val;
+ uint64_t cached_bit;
uint64_t max_val;
uint64_t num_vals;
- struct lfsr_taps taps;
+ uint64_t cycle_length;
+ uint64_t cached_cycle_length;
+ unsigned int spin;
};
int lfsr_next(struct fio_lfsr *fl, uint64_t *off, uint64_t);
-int lfsr_init(struct fio_lfsr *fl, uint64_t size, unsigned long seed);
-void lfsr_reset(struct fio_lfsr *fl, unsigned long seed);
+int lfsr_init(struct fio_lfsr *fl, uint64_t size,
+ unsigned long seed, unsigned int spin);
+int lfsr_reset(struct fio_lfsr *fl, unsigned long seed);
#endif
td->io_issues[i] = 0;
td->ts.total_io_u[i] = 0;
td->ts.runtime[i] = 0;
+ td->rwmix_issues = 0;
}
fio_gettime(&tv, NULL);
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
-#ifndef FIO_NO_HAVE_SHM_H
-#include <sys/shm.h>
-#endif
#include <sys/mman.h>
#include "fio.h"
+#ifndef FIO_NO_HAVE_SHM_H
+#include <sys/shm.h>
+#endif
void fio_unpin_memory(struct thread_data *td)
{
* way too early, double check.
*/
ret = pthread_cond_timedwait(&mutex->cond, &mutex->lock, &t);
- if (ret == ETIMEDOUT && !mutex_timed_out(&tv_s, seconds)) {
- pthread_mutex_lock(&mutex->lock);
+ if (ret == ETIMEDOUT && !mutex_timed_out(&tv_s, seconds))
ret = 0;
- }
mutex->waiters--;
}
pthread_mutex_unlock(&mutex->lock);
}
-void fio_mutex_down_write(struct fio_mutex *mutex)
+void fio_rwlock_write(struct fio_rwlock *lock)
{
- pthread_mutex_lock(&mutex->lock);
-
- while (mutex->value != 0) {
- mutex->waiters++;
- pthread_cond_wait(&mutex->cond, &mutex->lock);
- mutex->waiters--;
- }
-
- mutex->value--;
- pthread_mutex_unlock(&mutex->lock);
+ pthread_rwlock_wrlock(&lock->lock);
}
-void fio_mutex_down_read(struct fio_mutex *mutex)
+void fio_rwlock_read(struct fio_rwlock *lock)
{
- pthread_mutex_lock(&mutex->lock);
-
- while (mutex->value < 0) {
- mutex->waiters++;
- pthread_cond_wait(&mutex->cond, &mutex->lock);
- mutex->waiters--;
- }
+ pthread_rwlock_rdlock(&lock->lock);
+}
- mutex->value++;
- pthread_mutex_unlock(&mutex->lock);
+void fio_rwlock_unlock(struct fio_rwlock *lock)
+{
+ pthread_rwlock_unlock(&lock->lock);
}
-void fio_mutex_up_read(struct fio_mutex *mutex)
+void fio_rwlock_remove(struct fio_rwlock *lock)
{
- pthread_mutex_lock(&mutex->lock);
- mutex->value--;
- read_barrier();
- if (mutex->value >= 0 && mutex->waiters)
- pthread_cond_signal(&mutex->cond);
- pthread_mutex_unlock(&mutex->lock);
+ munmap((void *) lock, sizeof(*lock));
}
-void fio_mutex_up_write(struct fio_mutex *mutex)
+struct fio_rwlock *fio_rwlock_init(void)
{
- pthread_mutex_lock(&mutex->lock);
- mutex->value++;
- read_barrier();
- if (mutex->value >= 0 && mutex->waiters)
- pthread_cond_signal(&mutex->cond);
- pthread_mutex_unlock(&mutex->lock);
+ struct fio_rwlock *lock;
+ int ret;
+
+ lock = (void *) mmap(NULL, sizeof(struct fio_rwlock),
+ PROT_READ | PROT_WRITE,
+ OS_MAP_ANON | MAP_SHARED, -1, 0);
+ if (lock == MAP_FAILED) {
+ perror("mmap rwlock");
+ lock = NULL;
+ goto err;
+ }
+
+ ret = pthread_rwlock_init(&lock->lock, NULL);
+ if (ret) {
+ log_err("pthread_rwlock_init: %s\n", strerror(ret));
+ goto err;
+ }
+
+ return lock;
+err:
+ if (lock)
+ fio_rwlock_remove(lock);
+ return NULL;
}
int waiters;
};
+struct fio_rwlock {
+ pthread_rwlock_t lock;
+};
+
enum {
FIO_MUTEX_LOCKED = 0,
FIO_MUTEX_UNLOCKED = 1,
extern struct fio_mutex *fio_mutex_init(int);
extern void fio_mutex_remove(struct fio_mutex *);
+extern void fio_mutex_up(struct fio_mutex *);
extern void fio_mutex_down(struct fio_mutex *);
extern int fio_mutex_down_timeout(struct fio_mutex *, unsigned int);
-extern void fio_mutex_down_read(struct fio_mutex *);
-extern void fio_mutex_down_write(struct fio_mutex *);
-extern void fio_mutex_up(struct fio_mutex *);
-extern void fio_mutex_up_read(struct fio_mutex *);
-extern void fio_mutex_up_write(struct fio_mutex *);
-
-static inline struct fio_mutex *fio_mutex_rw_init(void)
-{
- return fio_mutex_init(0);
-}
-static inline int fio_mutex_getval(struct fio_mutex *mutex)
-{
- return mutex->value;
-}
+extern void fio_rwlock_read(struct fio_rwlock *);
+extern void fio_rwlock_write(struct fio_rwlock *);
+extern void fio_rwlock_unlock(struct fio_rwlock *);
+extern struct fio_rwlock *fio_rwlock_init(void);
+extern void fio_rwlock_remove(struct fio_rwlock *);
#endif
return 0;
}
-static int str_lockfile_cb(void *data, const char *str)
-{
- struct thread_data *td = data;
- char *nr = get_opt_postfix(str);
-
- td->o.lockfile_batch = 1;
- if (nr) {
- td->o.lockfile_batch = atoi(nr);
- free(nr);
- }
-
- return 0;
-}
-
static int str_gtod_reduce_cb(void *data, int *il)
{
struct thread_data *td = data;
.name = "lockfile",
.lname = "Lockfile",
.type = FIO_OPT_STR,
- .cb = str_lockfile_cb,
.off1 = td_var_offset(file_lock_mode),
.help = "Lock file when doing IO to it",
.parent = "filename",
#define FIO_HAVE_DISK_UTIL
#define FIO_HAVE_IOSCHED_SWITCH
+#define FIO_HAVE_IOPRIO
#define FIO_HAVE_ODIRECT
#define FIO_HAVE_HUGETLB
#define FIO_HAVE_BLKTRACE
#define FIO_HAVE_E4_ENG
#define FIO_HAVE_BYTEORDER_FUNCS
#define FIO_HAVE_MMAP_HUGE
+#define FIO_NO_HAVE_SHM_H
#define OS_MAP_ANON MAP_ANONYMOUS
#ifdef MADV_REMOVE
#define FIO_MADV_FREE MADV_REMOVE
#endif
+#ifndef MAP_HUGETLB
+#define MAP_HUGETLB 0x40000 /* arch specific */
+#endif
/*
#define SPLICE_DEF_SIZE (64*1024)
+static inline int ioprio_set(int which, int who, int ioprio)
+{
+ return syscall(__NR_ioprio_set, which, who, ioprio);
+}
+
+enum {
+ IOPRIO_CLASS_NONE,
+ IOPRIO_CLASS_RT,
+ IOPRIO_CLASS_BE,
+ IOPRIO_CLASS_IDLE,
+};
+
+enum {
+ IOPRIO_WHO_PROCESS = 1,
+ IOPRIO_WHO_PGRP,
+ IOPRIO_WHO_USER,
+};
+
+#define IOPRIO_BITS 16
+#define IOPRIO_CLASS_SHIFT 13
+
#ifndef BLKGETSIZE64
#define BLKGETSIZE64 _IOR(0x12,114,size_t)
#endif
static struct pool mp[MAX_POOLS];
static unsigned int nr_pools;
static unsigned int last_pool;
-static struct fio_mutex *lock;
+static struct fio_rwlock *lock;
static inline void pool_lock(struct pool *pool)
{
static inline void global_read_lock(void)
{
- fio_mutex_down_read(lock);
+ fio_rwlock_read(lock);
}
static inline void global_read_unlock(void)
{
- fio_mutex_up_read(lock);
+ fio_rwlock_unlock(lock);
}
static inline void global_write_lock(void)
{
- fio_mutex_down_write(lock);
+ fio_rwlock_write(lock);
}
static inline void global_write_unlock(void)
{
- fio_mutex_up_write(lock);
+ fio_rwlock_unlock(lock);
}
static inline int ptr_valid(struct pool *pool, void *ptr)
{
int ret;
- lock = fio_mutex_rw_init();
+ lock = fio_rwlock_init();
ret = add_pool(&mp[0], INITIAL_SIZE);
assert(!ret);
}
cleanup_pool(&mp[i]);
if (lock)
- fio_mutex_remove(lock);
+ fio_rwlock_remove(lock);
}
#ifdef SMALLOC_REDZONE
printf("Using %llu entries\n", (unsigned long long) size);
- lfsr_init(&lfsr, size, seed);
+ lfsr_init(&lfsr, size, seed, seed & 0xF);
map = axmap_new(size);
osize = size;
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <math.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "../lib/lfsr.h"
+
+void usage()
+{
+ printf("Usage: lfsr-test 0x<numbers> [seed] [spin] [verify]\n");
+ printf("-------------------------------------------------------------\n");
+ printf("*numbers: how many random numbers to produce (in hex)\n"
+ "seed: initial value\n"
+ "spin: how many iterations before we produce a number\n"
+ "verify: check if LFSR has iterated correctly\n\n"
+ "Only <numbers> is required. The rest are evaluated to 0 or false\n"
+ "Elapsed/mean time and verification results are printed at the"
+ "end of the test\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int r;
+ struct timespec start, end;
+ struct fio_lfsr *fl;
+ int verify = 0;
+ unsigned int spin = 0;
+ uint64_t seed = 0;
+ uint64_t numbers;
+ uint64_t v_size;
+ uint64_t i;
+ void *v = NULL, *v_start;
+ double total, mean;
+
+ /* Read arguments */
+ switch (argc) {
+ case 5: if (strncmp(argv[4], "verify", 7) == 0)
+ verify = 1;
+ case 4: spin = atoi(argv[3]);
+ case 3: seed = atol(argv[2]);
+ case 2: numbers = strtol(argv[1], NULL, 16);
+ break;
+ default: usage();
+ return 1;
+ }
+
+ /* Initialize LFSR */
+ fl = malloc(sizeof(struct fio_lfsr));
+ if (!fl) {
+ perror("malloc");
+ return 1;
+ }
+
+ r = lfsr_init(fl, numbers, seed, spin);
+ if (r) {
+ printf("Initialization failed.\n");
+ return r;
+ }
+
+ /* Print specs */
+ printf("LFSR specs\n");
+ printf("==========================\n");
+ printf("Size is %u\n", 64 - __builtin_clzl(fl->cached_bit));
+ printf("Max val is %lu\n", fl->max_val);
+ printf("XOR-mask is 0x%lX\n", fl->xormask);
+ printf("Seed is %lu\n", fl->last_val);
+ printf("Spin is %u\n", fl->spin);
+ printf("Cycle length is %lu\n", fl->cycle_length);
+
+ /* Create verification table */
+ if (verify) {
+ v_size = numbers * sizeof(uint8_t);
+ v = malloc(v_size);
+ memset(v, 0, v_size);
+ printf("\nVerification table is %lf KBs\n", (double)(v_size) / 1024);
+ }
+ v_start = v;
+
+ /*
+ * Iterate over a tight loop until we have produced all the requested
+ * numbers. Verifying the results should introduce some small yet not
+ * negligible overhead.
+ */
+ fprintf(stderr, "\nTest initiated... ");
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
+ while (!lfsr_next(fl, &i, fl->max_val)) {
+ if (verify)
+ *(uint8_t *)(v + i) += 1;
+ }
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);
+ fprintf(stderr, "finished.\n");
+
+
+ /* Check if all expected numbers within range have been calculated */
+ r = 0;
+ if (verify) {
+ fprintf(stderr, "Verifying results... ");
+ for (i = 0; i < numbers; i++) {
+ if (*(uint8_t *)(v + i) != 1) {
+ fprintf(stderr, "failed (%lu = %d).\n",
+ i, *(uint8_t *)(v + i));
+ r = 1;
+ break;
+ }
+ }
+ if (!r)
+ fprintf(stderr, "OK!\n");
+ }
+
+ /* Calculate elapsed time and mean time per number */
+ total = (end.tv_sec - start.tv_sec) * pow(10,9) +
+ end.tv_nsec - start.tv_nsec;
+ mean = total / fl->num_vals;
+
+ printf("\nTime results ");
+ if (verify)
+ printf("(slower due to verification)");
+ printf("\n==============================\n");
+ printf("Elapsed: %lf s\n", total / pow(10,9));
+ printf("Mean: %lf ns\n", mean);
+
+ free(v_start);
+ free(fl);
+ return r;
+}
unsigned int nr_files;
unsigned int open_files;
enum file_lock_mode file_lock_mode;
- unsigned int lockfile_batch;
unsigned int odirect;
unsigned int invalidate_cache;
uint32_t nr_files;
uint32_t open_files;
uint32_t file_lock_mode;
- uint32_t lockfile_batch;
uint32_t odirect;
uint32_t invalidate_cache;