From: Jens Axboe Date: Thu, 21 Mar 2013 12:45:27 +0000 (-0600) Subject: Merge branch 'master' into gfio X-Git-Tag: fio-2.1~57^2~17 X-Git-Url: https://git.kernel.dk/?p=fio.git;a=commitdiff_plain;h=d7213923067aa49922962a469a691c3ec951064d;hp=8ea39c32d29428b17bfe9c806fc33f0c8adfe118 Merge branch 'master' into gfio Conflicts: Makefile fio.h options.c Signed-off-by: Jens Axboe --- diff --git a/HOWTO b/HOWTO index 9ac485b6..6a880a7f 100644 --- a/HOWTO +++ b/HOWTO @@ -302,11 +302,6 @@ lockfile=str Fio defaults to not locking any files before it does 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: diff --git a/Makefile b/Makefile index 4b19a593..4aa05fab 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,6 @@ CFLAGS = -std=gnu99 -Wwrite-strings -Wall $(OPTFLAGS) LIBS = -lm -lz $(EXTLIBS) PROGS = fio SCRIPTS = fio_generate_plots -UNAME := $(shell uname) ifneq ($(wildcard config-host.mak),) all: @@ -84,42 +83,42 @@ ifndef CONFIG_INET_ATON 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 @@ -150,15 +149,21 @@ T_AXMAP_OBJS = t/axmap.o 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 @@ -172,7 +177,7 @@ INSTALL = install prefix = /usr/local bindir = $(prefix)/bin -ifeq ($(UNAME), Darwin) +ifeq ($(CONFIG_TARGET_OS), Darwin) mandir = /usr/share/man else mandir = $(prefix)/man @@ -246,8 +251,11 @@ t/genzipf: $(T_ZIPF_OBJS) 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 diff --git a/README b/README index b662e714..317ddec6 100644 --- a/README +++ b/README @@ -134,6 +134,7 @@ Command line $ 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 diff --git a/backend.c b/backend.c index 4e8a4389..600f5ce2 100644 --- a/backend.c +++ b/backend.c @@ -34,12 +34,12 @@ #include #include #include -#ifndef FIO_NO_HAVE_SHM_H -#include -#endif #include #include "fio.h" +#ifndef FIO_NO_HAVE_SHM_H +#include +#endif #include "hash.h" #include "smalloc.h" #include "verify.h" @@ -1034,7 +1034,7 @@ static int keep_running(struct thread_data *td) 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; /* diff --git a/cconv.c b/cconv.c index 5d575d3d..ea25e0a1 100644 --- a/cconv.c +++ b/cconv.c @@ -84,7 +84,6 @@ void convert_thread_options_to_cpu(struct thread_options *o, 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); @@ -244,7 +243,6 @@ void convert_thread_options_to_net(struct thread_options_pack *top, 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); diff --git a/configure b/configure index 5d576e10..222befe8 100755 --- a/configure +++ b/configure @@ -126,6 +126,7 @@ output_sym() { targetos="" cpu="" +cross_prefix=${cross_prefix-${CROSS_COMPILE}} cc="${CC-${cross_prefix}gcc}" # default options @@ -179,6 +180,12 @@ else 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 @@ -232,16 +239,6 @@ CYGWIN*) 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 @@ -321,10 +318,27 @@ fi cc="${CC-${cross_prefix}gcc}" +########################################## +# check cross compile + +cross_compile="no" +cat > $TMPC </dev/null || cross_compile="yes" +else + fatal "compile test failed" +fi + ########################################## # check endianness bigendian="no" -cat > $TMPC < $TMPC < int main(void) { @@ -332,8 +346,24 @@ 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 < +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 @@ -341,22 +371,27 @@ echo "Operating system $targetos" echo "CPU $cpu" echo "Big endian $bigendian" echo "Compiler $cc" +echo "Cross compile $cross_compile" echo ########################################## # check for wordsize wordsize="0" cat > $TMPC < +#include +#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" @@ -835,8 +870,7 @@ echo "inet_aton $inet_aton" # socklen_t probe socklen_t="no" cat > $TMPC << EOF -#include -#include +#include int main(int argc, char **argv) { socklen_t len = 0; @@ -977,11 +1011,6 @@ echo "RLIMIT_MEMLOCK $rlimit_memlock" ############################################################################# -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 diff --git a/file.h b/file.h index eb0688c5..d7e05f4f 100644 --- a/file.h +++ b/file.h @@ -102,10 +102,10 @@ struct fio_file { /* * 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 diff --git a/filesetup.c b/filesetup.c index 422d706a..96be3d1c 100644 --- a/filesetup.c +++ b/filesetup.c @@ -456,9 +456,6 @@ int file_lookup_open(struct fio_file *f, int flags) * 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); @@ -966,7 +963,7 @@ int init_random_map(struct thread_data *td) 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); @@ -1028,8 +1025,10 @@ void close_and_free_files(struct thread_data *td) 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; } @@ -1086,6 +1085,14 @@ int add_file(struct thread_data *td, const char *fname) 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; @@ -1113,7 +1120,7 @@ int add_file(struct thread_data *td, const char *fname) 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); @@ -1188,57 +1195,34 @@ void lock_file(struct thread_data *td, struct fio_file *f, enum fio_ddir ddir) 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) @@ -1311,6 +1295,9 @@ void dup_files(struct thread_data *td, struct thread_data *org) 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; diff --git a/fio.1 b/fio.1 index 586edcc7..2464dd5e 100644 --- a/fio.1 +++ b/fio.1 @@ -170,11 +170,6 @@ Read-write locking on the file. Many readers may access the file at the same 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 diff --git a/fio.h b/fio.h index 5805fcbf..05406cbc 100644 --- a/fio.h +++ b/fio.h @@ -117,6 +117,7 @@ struct thread_data { 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; @@ -209,22 +210,22 @@ struct thread_data { /* * 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; /* diff --git a/fio_generate_plots b/fio_generate_plots index 4285415e..5e2febda 100755 --- a/fio_generate_plots +++ b/fio_generate_plots @@ -8,7 +8,7 @@ if [ "$1"x = "x" ]; then fi GNUPLOT=$(which gnuplot) -if [ ! -x $GNUPLOT ]; then +if [ ! -x "$GNUPLOT" ]; then echo You need gnuplot installed to generate graphs exit 1 fi diff --git a/init.c b/init.c index 347d1e91..27370bb4 100644 --- a/init.c +++ b/init.c @@ -9,13 +9,14 @@ #include #include #include -#ifndef FIO_NO_HAVE_SHM_H -#include -#endif #include #include #include "fio.h" +#ifndef FIO_NO_HAVE_SHM_H +#include +#endif + #include "parse.h" #include "smalloc.h" #include "filehash.h" @@ -34,6 +35,7 @@ static char **ini_file; 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; @@ -150,6 +152,11 @@ static struct option l_opts[FIO_NR_OPTIONS] = { .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, @@ -823,7 +830,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, /* * 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; } @@ -1252,6 +1259,7 @@ static void usage(const char *name) 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"); @@ -1571,6 +1579,9 @@ int parse_cmd_line(int argc, char *argv[], int client_type) if (set_debug(optarg)) do_exit++; break; + case 'P': + parse_only = 1; + break; case 'x': { size_t new_size; @@ -1794,7 +1805,7 @@ int parse_options(int argc, char *argv[]) fio_options_free(&def_thread); if (!thread_number) { - if (dump_cmdline) + if (dump_cmdline || parse_only) return 0; if (exec_profile) return 0; diff --git a/io_u.c b/io_u.c index e474b48f..7941a6d7 100644 --- a/io_u.c +++ b/io_u.c @@ -531,10 +531,10 @@ static enum fio_ddir rate_ddir(struct thread_data *td, enum fio_ddir ddir) * 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); diff --git a/lib/getopt_long.c b/lib/getopt_long.c index bdd524ba..11d879ad 100644 --- a/lib/getopt_long.c +++ b/lib/getopt_long.c @@ -46,6 +46,8 @@ int getopt_long_only(int argc, char *const *argv, const char *optstring, 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 diff --git a/lib/lfsr.c b/lib/lfsr.c index 61a3aaf3..b10ba7a7 100644 --- a/lib/lfsr.c +++ b/lib/lfsr.c @@ -1,278 +1,250 @@ #include +#include #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; } diff --git a/lib/lfsr.h b/lib/lfsr.h index 45d7028c..187abf2f 100644 --- a/lib/lfsr.h +++ b/lib/lfsr.h @@ -3,7 +3,7 @@ #include -#define FIO_MAX_TAPS 8 +#define FIO_MAX_TAPS 6 struct lfsr_taps { unsigned int length; @@ -12,14 +12,19 @@ struct lfsr_taps { 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 diff --git a/libfio.c b/libfio.c index 37e5c0db..867d86e3 100644 --- a/libfio.c +++ b/libfio.c @@ -127,6 +127,7 @@ void reset_all_stats(struct thread_data *td) 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); diff --git a/memory.c b/memory.c index f1cd2d77..e06cab29 100644 --- a/memory.c +++ b/memory.c @@ -5,12 +5,12 @@ #include #include #include -#ifndef FIO_NO_HAVE_SHM_H -#include -#endif #include #include "fio.h" +#ifndef FIO_NO_HAVE_SHM_H +#include +#endif void fio_unpin_memory(struct thread_data *td) { diff --git a/mutex.c b/mutex.c index 3b94beff..332e9f9e 100644 --- a/mutex.c +++ b/mutex.c @@ -106,10 +106,8 @@ int fio_mutex_down_timeout(struct fio_mutex *mutex, unsigned int seconds) * 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--; } @@ -146,50 +144,49 @@ void fio_mutex_up(struct fio_mutex *mutex) 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; } diff --git a/mutex.h b/mutex.h index 6fdf7c6d..49a66e36 100644 --- a/mutex.h +++ b/mutex.h @@ -10,6 +10,10 @@ struct fio_mutex { int waiters; }; +struct fio_rwlock { + pthread_rwlock_t lock; +}; + enum { FIO_MUTEX_LOCKED = 0, FIO_MUTEX_UNLOCKED = 1, @@ -17,22 +21,14 @@ enum { 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 diff --git a/options.c b/options.c index fcf42703..00e542b0 100644 --- a/options.c +++ b/options.c @@ -868,20 +868,6 @@ static int str_verify_pattern_cb(void *data, const char *input) 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; @@ -1165,7 +1151,6 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .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", diff --git a/os/os-android.h b/os/os-android.h index cedfdaf8..070aa1a3 100644 --- a/os/os-android.h +++ b/os/os-android.h @@ -19,6 +19,7 @@ #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 @@ -31,6 +32,7 @@ #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 @@ -41,6 +43,9 @@ #ifdef MADV_REMOVE #define FIO_MADV_FREE MADV_REMOVE #endif +#ifndef MAP_HUGETLB +#define MAP_HUGETLB 0x40000 /* arch specific */ +#endif /* @@ -74,6 +79,27 @@ static inline int shmdt (const void *__shmaddr) #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 diff --git a/smalloc.c b/smalloc.c index b0173739..5dae7e7c 100644 --- a/smalloc.c +++ b/smalloc.c @@ -52,7 +52,7 @@ struct block_hdr { 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) { @@ -66,22 +66,22 @@ static inline void pool_unlock(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) @@ -223,7 +223,7 @@ void sinit(void) { int ret; - lock = fio_mutex_rw_init(); + lock = fio_rwlock_init(); ret = add_pool(&mp[0], INITIAL_SIZE); assert(!ret); } @@ -248,7 +248,7 @@ void scleanup(void) cleanup_pool(&mp[i]); if (lock) - fio_mutex_remove(lock); + fio_rwlock_remove(lock); } #ifdef SMALLOC_REDZONE diff --git a/t/axmap.c b/t/axmap.c index 61e32207..7ab500fa 100644 --- a/t/axmap.c +++ b/t/axmap.c @@ -34,7 +34,7 @@ int main(int argc, char *argv[]) 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; diff --git a/t/lfsr-test.c b/t/lfsr-test.c new file mode 100644 index 00000000..d371087c --- /dev/null +++ b/t/lfsr-test.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../lib/lfsr.h" + +void usage() +{ + printf("Usage: lfsr-test 0x [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 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; +} diff --git a/thread_options.h b/thread_options.h index a28ccfe3..d577f617 100644 --- a/thread_options.h +++ b/thread_options.h @@ -84,7 +84,6 @@ struct thread_options { 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; @@ -292,7 +291,6 @@ struct thread_options_pack { uint32_t nr_files; uint32_t open_files; uint32_t file_lock_mode; - uint32_t lockfile_batch; uint32_t odirect; uint32_t invalidate_cache;