Merge branch 'master' into gfio
authorJens Axboe <axboe@kernel.dk>
Mon, 3 Dec 2012 13:37:23 +0000 (14:37 +0100)
committerJens Axboe <axboe@kernel.dk>
Mon, 3 Dec 2012 13:37:23 +0000 (14:37 +0100)
Conflicts:
Makefile
fio.h
io_u.c
ioengine.h
memory.c

Signed-off-by: Jens Axboe <axboe@kernel.dk>
36 files changed:
FIO-VERSION-GEN
HOWTO
Makefile
backend.c
cconv.c
engines/net.c
engines/windowsaio.c
file.h
filesetup.c
fio.1
fio.h
helpers.c
helpers.h
init.c
io_ddir.h
io_u.c
ioengine.h
lib/axmap.c [new file with mode: 0644]
lib/axmap.h [new file with mode: 0644]
lib/lfsr.c [new file with mode: 0644]
lib/lfsr.h [new file with mode: 0644]
libfio.c
memory.c
options.c
os/os-android.h [new file with mode: 0644]
os/os-linux.h
os/os-solaris.h
os/os.h
os/windows/examples.wxs
os/windows/install.wxs
parse.c
profile.c
t/axmap.c [new file with mode: 0644]
t/genzipf.c
thread_options.h
verify.c

index cc7eb83cca8e589b5a5f85b682049db1e4707dc6..035ddaf18711cee99a25be1db9cf109b210c0dd3 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=FIO-VERSION-FILE
-DEF_VER=fio-2.0.10
+DEF_VER=fio-2.0.11
 
 LF='
 '
diff --git a/HOWTO b/HOWTO
index 56118140621803d434264910e0329e196d7db2a4..a8a3d956a13ed5c4a0a94548bc33da7019d414fd 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -61,7 +61,7 @@ bottom, it contains the following basic parameters:
 
        Num threads     How many threads or processes should we spread
                        this workload over.
-       
+
 The above are the basic parameters defined for a workload, in addition
 there's a multitude of parameters that modify other aspects of how this
 job behaves.
@@ -274,11 +274,14 @@ filename=str      Fio normally makes up a filename based on the job name,
                as the two working files, you would use
                filename=/dev/sda:/dev/sdb. On Windows, disk devices are accessed
                as \\.\PhysicalDrive0 for the first device, \\.\PhysicalDrive1
-               for the second etc.  If the wanted filename does need to 
-               include a colon, then escape that with a '\' character. 
-               For instance, if the filename is "/dev/dsk/foo@3,0:c", 
-               then you would use filename="/dev/dsk/foo@3,0\:c". 
-               '-' is a reserved name, meaning stdin or stdout. Which of the 
+               for the second etc.
+               Note: Windows and FreeBSD prevent write access to areas of the disk
+               containing in-use data (e.g. filesystems).
+               If the wanted filename does need to include a colon, then escape that
+               with a '\' character.
+               For instance, if the filename is "/dev/dsk/foo@3,0:c",
+               then you would use filename="/dev/dsk/foo@3,0\:c".
+               '-' is a reserved name, meaning stdin or stdout. Which of the
                two depends on the read/write direction set.
 
 opendir=str    Tell fio to recursively add any file it can find in this
@@ -716,6 +719,25 @@ rwmixwrite=int     How large a percentage of the mix should be writes. If both
                if fio is asked to limit reads or writes to a certain rate.
                If that is the case, then the distribution may be skewed.
 
+random_distribution=str:float  By default, fio will use a completely uniform
+               random distribution when asked to perform random IO. Sometimes
+               it is useful to skew the distribution in specific ways,
+               ensuring that some parts of the data is more hot than others.
+               fio includes the following distribution models:
+
+               random          Uniform random distribution
+               zipf            Zipf distribution
+               pareto          Pareto distribution
+
+               When using a zipf or pareto distribution, an input value
+               is also needed to define the access pattern. For zipf, this
+               is the zipf theta. For pareto, it's the pareto power. Fio
+               includes a test program, genzipf, that can be used visualize
+               what the given input values will yield in terms of hit rates.
+               If you wanted to use zipf with a theta of 1.2, you would use
+               random_distribution=zipf:1.2 as the option. If a non-uniform
+               model is used, fio will disable use of the random map.
+
 norandommap    Normally fio will cover every block of the file when doing
                random IO. If this option is given, fio will just get a
                new random offset without looking at past io history. This
@@ -1067,7 +1089,7 @@ verify_backlog_batch=int  Control how many blocks fio will verify
                less than verify_backlog then not all blocks will be verified,
                if verify_backlog_batch is larger than verify_backlog, some
                blocks will be verified more than once.
-               
+
 stonewall
 wait_for_previous Wait for preceeding jobs in the job file to exit, before
                starting this one. Can be used to insert serialization
@@ -1113,7 +1135,7 @@ read_iolog=str    Open an iolog with the specified file name and replay the
                for how to capture such logging data. For blktrace replay,
                the file needs to be turned into a blkparse binary data
                file first (blkparse <device> -o /dev/null -d file_for_fio.bin).
-               
+
 replay_no_stall=int When replaying I/O with read_iolog the default behavior
                is to attempt to respect the time stamps within the log and
                replay them with the appropriate delay between IOPS.  By
@@ -1270,12 +1292,12 @@ ignore_error=str Sometimes you want to ignore some errors during test
                 may be symbol ('ENOSPC', 'ENOMEM') or integer.
                 Example:
                        ignore_error=EAGAIN,ENOSPC:122
-                This option will ignore EAGAIN from READ, and ENOSPC and 
-                122(EDQUOT) from WRITE. 
+                This option will ignore EAGAIN from READ, and ENOSPC and
+                122(EDQUOT) from WRITE.
 
 error_dump=bool If set dump every error even if it is non fatal, true
                by default. If disabled only fatal error will be dumped
-                                
+
 cgroup=str     Add job to this control group. If it doesn't exist, it will
                be created. The system must have a mounted cgroup blkio
                mount point for this to work. If your system doesn't have it
@@ -1362,7 +1384,7 @@ that defines them is selected.
 [e4defrag] donorname=str
                File will be used as a block donor(swap extents between files)
 [e4defrag] inplace=int
-               Configure donor file blocks allocation strategy         
+               Configure donor file blocks allocation strategy
                0(default): Preallocate donor's file on init
                1         : allocate space immidietly inside defragment event,
                            and free right after event
@@ -1550,8 +1572,8 @@ Split up, the format is as follows:
                          Read merges, write merges,
                          Read ticks, write ticks,
                          Time spent in queue, disk utilization percentage
-       Additional Info (dependant on continue_on_error, default off): total # errors, first error code 
-       
+       Additional Info (dependant on continue_on_error, default off): total # errors, first error code
+
        Additional Info (dependant on description being set): Text description
 
 Completion latency percentiles can be a grouping of up to 20 sets, so
@@ -1567,7 +1589,7 @@ there will be a disk utilization section.
 
 8.0 Trace file format
 ---------------------
-There are two trace file format that you can encounter. The older (v1) format 
+There are two trace file format that you can encounter. The older (v1) format
 is unsupported since version 1.20-rc3 (March 2008). It will still be described
 below in case that you get an old trace and want to understand it.
 
@@ -1604,7 +1626,7 @@ filename action
 The filename is given as an absolute path. The action can be one of these:
 
 add          Add the given filename to the trace
-open         Open the file with the given filename. The filename has to have 
+open         Open the file with the given filename. The filename has to have
              been added with the add action before.
 close        Close the file with the given filename. The file has to have been
              opened before.
@@ -1615,7 +1637,7 @@ The file io action format:
 filename action offset length
 
 The filename is given as an absolute path, and has to have been added and opened
-before it can be used with this format. The offset and length are given in 
+before it can be used with this format. The offset and length are given in
 bytes. The action can be one of these:
 
 wait       Wait for 'offset' microseconds. Everything below 100 is discarded.
index b0b68574b7a40da8e36796b42ac96e7498d8996b..a521220f8f7d0d36a4d4b097ac2e2e52e6d74216 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,10 @@
 ifneq ($(origin CC), environment)
-CC     = gcc
+CC     = $(CROSS_COMPILE)gcc
 endif
 DEBUGFLAGS = -D_FORTIFY_SOURCE=2 -DFIO_INC_DEBUG
 CPPFLAGS= -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 \
        $(DEBUGFLAGS)
-OPTFLAGS= -O3 -fno-omit-frame-pointer -g $(EXTFLAGS)
+OPTFLAGS= -O3 -g $(EXTFLAGS)
 CFLAGS = -std=gnu99 -Wwrite-strings -Wall $(OPTFLAGS)
 LIBS   = -lm -lz $(EXTLIBS)
 PROGS  = fio
@@ -20,7 +20,8 @@ SOURCE := gettime.c ioengines.c init.c stat.c log.c time.c filesetup.c \
                lib/num2str.c lib/ieee754.c $(wildcard crc/*.c) engines/cpu.c \
                engines/mmap.c engines/sync.c engines/null.c engines/net.c \
                memalign.c server.c client.c iolog.c backend.c libfio.c flow.c \
-               cconv.c lib/prio_tree.c lib/zipf.c json.c gettime-thread.c
+               cconv.c json.c lib/zipf.c lib/axmap.c lib/lfsr.c \
+               gettime-thread.c
 
 ifeq ($(UNAME), Linux)
   SOURCE += diskutil.c fifo.c blktrace.c helpers.c cgroup.c trim.c \
@@ -31,6 +32,14 @@ ifeq ($(UNAME), Linux)
   LIBS += -lpthread -ldl -lrt -laio
   LDFLAGS += -rdynamic
 endif
+ifeq ($(UNAME), Android)
+  SOURCE += diskutil.c fifo.c blktrace.c helpers.c trim.c \
+               engines/splice.c profiles/tiobench.c engines/falloc.c \
+               engines/e4defrag.c
+  LIBS += -ldl
+  LDFLAGS += -rdynamic
+  CPPFLAGS += -DFIO_NO_HAVE_SHM_H
+endif
 ifeq ($(UNAME), SunOS)
   SOURCE += fifo.c lib/strsep.c helpers.c engines/posixaio.c \
                engines/solarisaio.c
@@ -88,13 +97,19 @@ T_ZIPF_OBS = t/genzipf.o
 T_ZIPF_OBJS += t/log.o lib/ieee754.o lib/rand.o lib/zipf.o t/genzipf.o
 T_ZIPF_PROGS = t/genzipf
 
+T_AXMAP_OBJS = t/axmap.o
+T_AXMAP_OBJS += lib/lfsr.o lib/axmap.o
+T_AXMAP_PROGS = t/axmap
+
 T_OBJS = $(T_SMALLOC_OBJS)
 T_OBJS += $(T_IEEE_OBJS)
 T_OBJS += $(T_ZIPF_OBJS)
+T_OBJS += $(T_AXMAP_OBJS)
 
 T_PROGS = $(T_SMALLOC_PROGS)
 T_PROGS += $(T_IEEE_PROGS)
 T_PROGS += $(T_ZIPF_PROGS)
+T_PROGS += $(T_AXMAP_PROGS)
 
 ifneq ($(findstring $(MAKEFLAGS),s),s)
 ifndef V
@@ -172,6 +187,9 @@ gfio: $(GFIO_OBJS)
 t/genzipf: $(T_ZIPF_OBJS)
        $(QUIET_CC)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_ZIPF_OBJS) $(LIBS) $(LDFLAGS)
 
+t/axmap: $(T_AXMAP_OBJS)
+       $(QUIET_CC)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_AXMAP_OBJS) $(LIBS) $(LDFLAGS)
+
 .depend: $(SOURCE)
        $(QUIET_DEP)$(CC) -MM $(CFLAGS) $(CPPFLAGS) $(SOURCE) 1> .depend
 
index 39ef759f3187fcf89b18ee748bf97441a96e2df0..d56c7d017333340281b05419f533ec232d2ee9c4 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -34,7 +34,9 @@
 #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"
@@ -1398,7 +1400,7 @@ static void reap_threads(unsigned int *nr_running, unsigned int *t_rate,
                        if (WIFSIGNALED(status)) {
                                int sig = WTERMSIG(status);
 
-                               if (sig != SIGTERM)
+                               if (sig != SIGTERM && sig != SIGUSR2)
                                        log_err("fio: pid=%d, got signal=%d\n",
                                                        (int) td->pid, sig);
                                td->sig = sig;
diff --git a/cconv.c b/cconv.c
index ca97c7379f8527d5255a60991f064b245e95119b..173312311b336b32e8522db2582aef31460d6e10 100644 (file)
--- a/cconv.c
+++ b/cconv.c
@@ -121,6 +121,7 @@ void convert_thread_options_to_cpu(struct thread_options *o,
        o->random_distribution = le32_to_cpu(top->random_distribution);
        o->zipf_theta.u.f = fio_uint64_to_double(le64_to_cpu(top->zipf_theta.u.i));
        o->pareto_h.u.f = fio_uint64_to_double(le64_to_cpu(top->pareto_h.u.i));
+       o->random_generator = le32_to_cpu(top->random_generator);
        o->hugepage_size = le32_to_cpu(top->hugepage_size);
        o->rw_min_bs = le32_to_cpu(top->rw_min_bs);
        o->thinktime = le32_to_cpu(top->thinktime);
@@ -274,6 +275,7 @@ void convert_thread_options_to_net(struct thread_options_pack *top,
        top->random_distribution = cpu_to_le32(o->random_distribution);
        top->zipf_theta.u.i = __cpu_to_le64(fio_double_to_uint64(o->zipf_theta.u.f));
        top->pareto_h.u.i = __cpu_to_le64(fio_double_to_uint64(o->pareto_h.u.f));
+       top->random_generator = cpu_to_le32(o->random_generator);
        top->hugepage_size = cpu_to_le32(o->hugepage_size);
        top->rw_min_bs = cpu_to_le32(o->rw_min_bs);
        top->thinktime = cpu_to_le32(o->thinktime);
index 468bc7c81746a8f73935903e8c99d3990c2286e1..bbfce811cc67d3605c7154281c5d1195a717b313 100644 (file)
@@ -7,6 +7,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <signal.h>
 #include <errno.h>
 #include <assert.h>
 #include <netinet/in.h>
@@ -33,6 +34,7 @@ struct netio_options {
        unsigned int port;
        unsigned int proto;
        unsigned int listen;
+       unsigned int pingpong;
 };
 
 struct udp_close_msg {
@@ -42,7 +44,8 @@ struct udp_close_msg {
 
 enum {
        FIO_LINK_CLOSE = 0x89,
-       FIO_LINK_CLOSE_MAGIC = 0x6c696e6b,
+       FIO_LINK_OPEN_CLOSE_MAGIC = 0x6c696e6b,
+       FIO_LINK_OPEN = 0x98,
 
        FIO_TYPE_TCP    = 1,
        FIO_TYPE_UDP    = 2,
@@ -101,6 +104,12 @@ static struct fio_option options[] = {
                .help   = "Listen for incoming TCP connections",
                .category = FIO_OPT_C_IO,
        },
+       {
+               .name   = "pingpong",
+               .type   = FIO_OPT_STR_SET,
+               .off1   = offsetof(struct netio_options, pingpong),
+               .help   = "Ping-pong IO requests",
+       },
        {
                .name   = NULL,
        },
@@ -295,7 +304,7 @@ static int fio_netio_send(struct thread_data *td, struct io_u *io_u)
 {
        struct netio_data *nd = td->io_ops->data;
        struct netio_options *o = td->eo;
-       int ret, flags = OS_MSG_DONTWAIT;
+       int ret, flags = 0;
 
        do {
                if (o->proto == FIO_TYPE_UDP) {
@@ -309,8 +318,8 @@ static int fio_netio_send(struct thread_data *td, struct io_u *io_u)
                         * if we are going to write more, set MSG_MORE
                         */
 #ifdef MSG_MORE
-                       if (td->this_io_bytes[DDIR_WRITE] + io_u->xfer_buflen <
-                           td->o.size)
+                       if ((td->this_io_bytes[DDIR_WRITE] + io_u->xfer_buflen <
+                           td->o.size) && !o->pingpong)
                                flags |= MSG_MORE;
 #endif
                        ret = send(io_u->file->fd, io_u->xfer_buf,
@@ -322,8 +331,6 @@ static int fio_netio_send(struct thread_data *td, struct io_u *io_u)
                ret = poll_wait(td, io_u->file->fd, POLLOUT);
                if (ret <= 0)
                        break;
-
-               flags &= ~OS_MSG_DONTWAIT;
        } while (1);
 
        return ret;
@@ -337,7 +344,7 @@ static int is_udp_close(struct io_u *io_u, int len)
                return 0;
 
        msg = io_u->xfer_buf;
-       if (ntohl(msg->magic) != FIO_LINK_CLOSE_MAGIC)
+       if (ntohl(msg->magic) != FIO_LINK_OPEN_CLOSE_MAGIC)
                return 0;
        if (ntohl(msg->cmd) != FIO_LINK_CLOSE)
                return 0;
@@ -349,7 +356,7 @@ static int fio_netio_recv(struct thread_data *td, struct io_u *io_u)
 {
        struct netio_data *nd = td->io_ops->data;
        struct netio_options *o = td->eo;
-       int ret, flags = OS_MSG_DONTWAIT;
+       int ret, flags = 0;
 
        do {
                if (o->proto == FIO_TYPE_UDP) {
@@ -368,32 +375,32 @@ static int fio_netio_recv(struct thread_data *td, struct io_u *io_u)
                }
                if (ret > 0)
                        break;
+               else if (!ret && (flags & MSG_WAITALL))
+                       break;
 
                ret = poll_wait(td, io_u->file->fd, POLLIN);
                if (ret <= 0)
                        break;
-               flags &= ~OS_MSG_DONTWAIT;
                flags |= MSG_WAITALL;
        } while (1);
 
        return ret;
 }
 
-static int fio_netio_queue(struct thread_data *td, struct io_u *io_u)
+static int __fio_netio_queue(struct thread_data *td, struct io_u *io_u,
+                            enum fio_ddir ddir)
 {
        struct netio_data *nd = td->io_ops->data;
        struct netio_options *o = td->eo;
        int ret;
 
-       fio_ro_check(td, io_u);
-
-       if (io_u->ddir == DDIR_WRITE) {
+       if (ddir == DDIR_WRITE) {
                if (!nd->use_splice || o->proto == FIO_TYPE_UDP ||
                    o->proto == FIO_TYPE_UNIX)
                        ret = fio_netio_send(td, io_u);
                else
                        ret = fio_netio_splice_out(td, io_u);
-       } else if (io_u->ddir == DDIR_READ) {
+       } else if (ddir == DDIR_READ) {
                if (!nd->use_splice || o->proto == FIO_TYPE_UDP ||
                    o->proto == FIO_TYPE_UNIX)
                        ret = fio_netio_recv(td, io_u);
@@ -410,7 +417,7 @@ static int fio_netio_queue(struct thread_data *td, struct io_u *io_u)
                } else {
                        int err = errno;
 
-                       if (io_u->ddir == DDIR_WRITE && err == EMSGSIZE)
+                       if (ddir == DDIR_WRITE && err == EMSGSIZE)
                                return FIO_Q_BUSY;
 
                        io_u->error = err;
@@ -423,6 +430,28 @@ static int fio_netio_queue(struct thread_data *td, struct io_u *io_u)
        return FIO_Q_COMPLETED;
 }
 
+static int fio_netio_queue(struct thread_data *td, struct io_u *io_u)
+{
+       struct netio_options *o = td->eo;
+       int ret;
+
+       fio_ro_check(td, io_u);
+
+       ret = __fio_netio_queue(td, io_u, io_u->ddir);
+       if (!o->pingpong || ret != FIO_Q_COMPLETED)
+               return ret;
+
+       /*
+        * For ping-pong mode, receive or send reply as needed
+        */
+       if (td_read(td) && io_u->ddir == DDIR_READ)
+               ret = __fio_netio_queue(td, io_u, DDIR_WRITE);
+       else if (td_write(td) && io_u->ddir == DDIR_WRITE)
+               ret = __fio_netio_queue(td, io_u, DDIR_READ);
+
+       return ret;
+}
+
 static int fio_netio_connect(struct thread_data *td, struct fio_file *f)
 {
        struct netio_data *nd = td->io_ops->data;
@@ -481,39 +510,33 @@ static int fio_netio_accept(struct thread_data *td, struct fio_file *f)
        struct netio_data *nd = td->io_ops->data;
        struct netio_options *o = td->eo;
        fio_socklen_t socklen = sizeof(nd->addr);
+       int state;
 
        if (o->proto == FIO_TYPE_UDP) {
                f->fd = nd->listenfd;
                return 0;
        }
 
+       state = td->runstate;
+       td_set_runstate(td, TD_SETTING_UP);
+
        log_info("fio: waiting for connection\n");
 
        if (poll_wait(td, nd->listenfd, POLLIN) < 0)
-               return 1;
+               goto err;
 
        f->fd = accept(nd->listenfd, (struct sockaddr *) &nd->addr, &socklen);
        if (f->fd < 0) {
                td_verror(td, errno, "accept");
-               return 1;
+               goto err;
        }
 
+       reset_all_stats(td);
+       td_set_runstate(td, state);
        return 0;
-}
-
-static int fio_netio_open_file(struct thread_data *td, struct fio_file *f)
-{
-       int ret;
-       struct netio_options *o = td->eo;
-
-       if (o->listen)
-               ret = fio_netio_accept(td, f);
-       else
-               ret = fio_netio_connect(td, f);
-
-       if (ret)
-               f->fd = -1;
-       return ret;
+err:
+       td_set_runstate(td, state);
+       return 1;
 }
 
 static void fio_netio_udp_close(struct thread_data *td, struct fio_file *f)
@@ -523,7 +546,7 @@ static void fio_netio_udp_close(struct thread_data *td, struct fio_file *f)
        struct sockaddr *to = (struct sockaddr *) &nd->addr;
        int ret;
 
-       msg.magic = htonl(FIO_LINK_CLOSE_MAGIC);
+       msg.magic = htonl(FIO_LINK_OPEN_CLOSE_MAGIC);
        msg.cmd = htonl(FIO_LINK_CLOSE);
 
        ret = sendto(f->fd, &msg, sizeof(msg), MSG_WAITALL, to,
@@ -546,11 +569,98 @@ static int fio_netio_close_file(struct thread_data *td, struct fio_file *f)
        return generic_close_file(td, f);
 }
 
+static int fio_netio_udp_recv_open(struct thread_data *td, struct fio_file *f)
+{
+       struct netio_data *nd = td->io_ops->data;
+       struct udp_close_msg msg;
+       struct sockaddr *to = (struct sockaddr *) &nd->addr;
+       fio_socklen_t len = sizeof(nd->addr);
+       int ret;
+
+       ret = recvfrom(f->fd, &msg, sizeof(msg), MSG_WAITALL, to, &len);
+       if (ret < 0) {
+               td_verror(td, errno, "sendto udp link open");
+               return ret;
+       }
+
+       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));
+               return -1;
+       }
+
+       return 0;
+}
+
+static int fio_netio_udp_send_open(struct thread_data *td, struct fio_file *f)
+{
+       struct netio_data *nd = td->io_ops->data;
+       struct udp_close_msg msg;
+       struct sockaddr *to = (struct sockaddr *) &nd->addr;
+       int ret;
+
+       msg.magic = htonl(FIO_LINK_OPEN_CLOSE_MAGIC);
+       msg.cmd = htonl(FIO_LINK_OPEN);
+
+       ret = sendto(f->fd, &msg, sizeof(msg), MSG_WAITALL, to,
+                       sizeof(nd->addr));
+       if (ret < 0) {
+               td_verror(td, errno, "sendto udp link open");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int fio_netio_open_file(struct thread_data *td, struct fio_file *f)
+{
+       int ret;
+       struct netio_options *o = td->eo;
+
+       if (o->listen)
+               ret = fio_netio_accept(td, f);
+       else
+               ret = fio_netio_connect(td, f);
+
+       if (ret) {
+               f->fd = -1;
+               return ret;
+       }
+
+       if (o->proto == FIO_TYPE_UDP) {
+               if (td_write(td))
+                       ret = fio_netio_udp_send_open(td, f);
+               else {
+                       int state;
+
+                       state = td->runstate;
+                       td_set_runstate(td, TD_SETTING_UP);
+                       ret = fio_netio_udp_recv_open(td, f);
+                       td_set_runstate(td, state);
+               }
+       }
+
+       if (ret)
+               fio_netio_close_file(td, f);
+
+       return ret;
+}
+
 static int fio_netio_setup_connect_inet(struct thread_data *td,
                                        const char *host, unsigned short port)
 {
        struct netio_data *nd = td->io_ops->data;
 
+       if (!host) {
+               log_err("fio: connect with no host to connect to.\n");
+               if (td_read(td))
+                       log_err("fio: did you forget to set 'listen'?\n");
+
+               td_verror(td, EINVAL, "no hostname= set");
+               return 1;
+       }
+
        nd->addr.sin_family = AF_INET;
        nd->addr.sin_port = htons(port);
 
@@ -780,6 +890,11 @@ static int fio_netio_setup(struct thread_data *td)
        return 0;
 }
 
+static void fio_netio_terminate(struct thread_data *td)
+{
+       kill(td->pid, SIGUSR2);
+}
+
 #ifdef FIO_HAVE_SPLICE
 static int fio_netio_setup_splice(struct thread_data *td)
 {
@@ -808,11 +923,12 @@ static struct ioengine_ops ioengine_splice = {
        .init                   = fio_netio_init,
        .cleanup                = fio_netio_cleanup,
        .open_file              = fio_netio_open_file,
-       .close_file             = generic_close_file,
+       .close_file             = fio_netio_close_file,
+       .terminate              = fio_netio_terminate,
        .options                = options,
        .option_struct_size     = sizeof(struct netio_options),
        .flags                  = FIO_SYNCIO | FIO_DISKLESSIO | FIO_UNIDIR |
-                                 FIO_SIGTERM | FIO_PIPEIO,
+                                 FIO_PIPEIO,
 };
 #endif
 
@@ -826,10 +942,11 @@ static struct ioengine_ops ioengine_rw = {
        .cleanup                = fio_netio_cleanup,
        .open_file              = fio_netio_open_file,
        .close_file             = fio_netio_close_file,
+       .terminate              = fio_netio_terminate,
        .options                = options,
        .option_struct_size     = sizeof(struct netio_options),
        .flags                  = FIO_SYNCIO | FIO_DISKLESSIO | FIO_UNIDIR |
-                                 FIO_SIGTERM | FIO_PIPEIO,
+                                 FIO_PIPEIO,
 };
 
 static int str_hostname_cb(void *data, const char *input)
index ea899698b25e1474406e3c9a1fd7e3ddcc63c5a5..db7573049600b6686c74c241c719057544a0d099 100644 (file)
@@ -14,6 +14,8 @@
 
 typedef BOOL (WINAPI *CANCELIOEX)(HANDLE hFile, LPOVERLAPPED lpOverlapped);
 
+int geterrno_from_win_error (DWORD code, int deferrno);
+
 struct fio_overlapped {
        OVERLAPPED o;
        struct io_u *io_u;
@@ -48,6 +50,82 @@ static DWORD WINAPI IoCompletionRoutine(LPVOID lpParameter);
 static int fio_windowsaio_init(struct thread_data *td);
 static int fio_windowsaio_open_file(struct thread_data *td, struct fio_file *f);
 static int fio_windowsaio_close_file(struct thread_data fio_unused *td, struct fio_file *f);
+static int win_to_poxix_error(DWORD winerr);
+
+static int win_to_poxix_error(DWORD winerr)
+{
+       switch (winerr)
+       {
+       case ERROR_FILE_NOT_FOUND:              return ENOENT;
+       case ERROR_PATH_NOT_FOUND:              return ENOENT;
+       case ERROR_ACCESS_DENIED:               return EACCES;
+       case ERROR_INVALID_HANDLE:              return EBADF;
+       case ERROR_NOT_ENOUGH_MEMORY:   return ENOMEM;
+       case ERROR_INVALID_DATA:                return EINVAL;
+       case ERROR_OUTOFMEMORY:                 return ENOMEM;
+       case ERROR_INVALID_DRIVE:               return ENODEV;
+       case ERROR_NOT_SAME_DEVICE:             return EXDEV;
+       case ERROR_WRITE_PROTECT:               return EROFS;
+       case ERROR_BAD_UNIT:                    return ENODEV;
+       case ERROR_SHARING_VIOLATION:   return EACCES;
+       case ERROR_LOCK_VIOLATION:              return EACCES;
+       case ERROR_SHARING_BUFFER_EXCEEDED:     return ENOLCK;
+       case ERROR_HANDLE_DISK_FULL:    return ENOSPC;
+       case ERROR_NOT_SUPPORTED:               return ENOSYS;
+       case ERROR_FILE_EXISTS:                 return EEXIST;
+       case ERROR_CANNOT_MAKE:                 return EPERM;
+       case ERROR_INVALID_PARAMETER:   return EINVAL;
+       case ERROR_NO_PROC_SLOTS:               return EAGAIN;
+       case ERROR_BROKEN_PIPE:                 return EPIPE;
+       case ERROR_OPEN_FAILED:                 return EIO;
+       case ERROR_NO_MORE_SEARCH_HANDLES:      return ENFILE;
+       case ERROR_CALL_NOT_IMPLEMENTED:        return ENOSYS;
+       case ERROR_INVALID_NAME:                return ENOENT;
+       case ERROR_WAIT_NO_CHILDREN:    return ECHILD;
+       case ERROR_CHILD_NOT_COMPLETE:  return EBUSY;
+       case ERROR_DIR_NOT_EMPTY:               return ENOTEMPTY;
+       case ERROR_SIGNAL_REFUSED:              return EIO;
+       case ERROR_BAD_PATHNAME:                return ENOENT;
+       case ERROR_SIGNAL_PENDING:              return EBUSY;
+       case ERROR_MAX_THRDS_REACHED:   return EAGAIN;
+       case ERROR_BUSY:                                return EBUSY;
+       case ERROR_ALREADY_EXISTS:              return EEXIST;
+       case ERROR_NO_SIGNAL_SENT:              return EIO;
+       case ERROR_FILENAME_EXCED_RANGE:        return EINVAL;
+       case ERROR_META_EXPANSION_TOO_LONG:     return EINVAL;
+       case ERROR_INVALID_SIGNAL_NUMBER:       return EINVAL;
+       case ERROR_THREAD_1_INACTIVE:   return EINVAL;
+       case ERROR_BAD_PIPE:                    return EINVAL;
+       case ERROR_PIPE_BUSY:                   return EBUSY;
+       case ERROR_NO_DATA:                             return EPIPE;
+       case ERROR_MORE_DATA:                   return EAGAIN;
+       case ERROR_DIRECTORY:                   return ENOTDIR;
+       case ERROR_PIPE_CONNECTED:              return EBUSY;
+       case ERROR_NO_TOKEN:                    return EINVAL;
+       case ERROR_PROCESS_ABORTED:             return EFAULT;
+       case ERROR_BAD_DEVICE:                  return ENODEV;
+       case ERROR_BAD_USERNAME:                return EINVAL;
+       case ERROR_OPEN_FILES:                  return EAGAIN;
+       case ERROR_ACTIVE_CONNECTIONS:  return EAGAIN;
+       case ERROR_DEVICE_IN_USE:               return EAGAIN;
+       case ERROR_INVALID_AT_INTERRUPT_TIME:   return EINTR;
+       case ERROR_IO_DEVICE:                   return EIO;
+       case ERROR_NOT_OWNER:                   return EPERM;
+       case ERROR_END_OF_MEDIA:                return ENOSPC;
+       case ERROR_EOM_OVERFLOW:                return ENOSPC;
+       case ERROR_BEGINNING_OF_MEDIA:  return ESPIPE;
+       case ERROR_SETMARK_DETECTED:    return ESPIPE;
+       case ERROR_NO_DATA_DETECTED:    return ENOSPC;
+       case ERROR_POSSIBLE_DEADLOCK:   return EDEADLOCK;
+       case ERROR_CRC:                                 return EIO;
+       case ERROR_NEGATIVE_SEEK:               return EINVAL;
+       case ERROR_DISK_FULL:                   return ENOSPC;
+       case ERROR_NOACCESS:                    return EFAULT;
+       case ERROR_FILE_INVALID:                return ENXIO;
+       }
+
+       return winerr;
+}
 
 int sync_file_range(int fd, off64_t offset, off64_t nbytes,
                           unsigned int flags)
@@ -350,7 +428,7 @@ static int fio_windowsaio_queue(struct thread_data *td, struct io_u *io_u)
        case DDIR_SYNC_FILE_RANGE:
                success = FlushFileBuffers(io_u->file->hFile);
                if (!success)
-                   io_u->error = GetLastError();
+                   io_u->error = win_to_poxix_error(GetLastError());
 
                return FIO_Q_COMPLETED;
                break;
@@ -368,7 +446,7 @@ static int fio_windowsaio_queue(struct thread_data *td, struct io_u *io_u)
        if (success || GetLastError() == ERROR_IO_PENDING)
                rc = FIO_Q_QUEUED;
        else {
-               io_u->error = GetLastError();
+               io_u->error = win_to_poxix_error(GetLastError());
                io_u->resid = io_u->xfer_buflen;
        }
 
@@ -390,7 +468,7 @@ static DWORD WINAPI IoCompletionRoutine(LPVOID lpParameter)
        wd = ctx->wd;
 
        do {
-               if (!GetQueuedCompletionStatus(ctx->iocp, &bytes, &ulKey, &ovl, 250))
+               if (!GetQueuedCompletionStatus(ctx->iocp, &bytes, &ulKey, &ovl, 250) && ovl == NULL)
                        continue;
 
                fov = CONTAINING_RECORD(ovl, struct fio_overlapped, o);
@@ -401,7 +479,7 @@ static DWORD WINAPI IoCompletionRoutine(LPVOID lpParameter)
                        io_u->error = 0;
                } else {
                        io_u->resid = io_u->xfer_buflen;
-                       io_u->error = ovl->Internal;
+                       io_u->error = win_to_poxix_error(GetLastError());
                }
 
                fov->io_complete = TRUE;
diff --git a/file.h b/file.h
index 38e9d0d43003c466ae13defebea219db8057b7c1..3024c5440094f4a711b993e80dc6b81264f42893 100644 (file)
--- a/file.h
+++ b/file.h
@@ -6,6 +6,8 @@
 #include "io_ddir.h"
 #include "flist.h"
 #include "lib/zipf.h"
+#include "lib/axmap.h"
+#include "lib/lfsr.h"
 
 /*
  * The type of object we are working on
@@ -108,10 +110,9 @@ struct fio_file {
        /*
         * block map for random io
         */
-       unsigned long *file_map;
-       unsigned long num_maps;
-       unsigned long last_free_lookup;
-       unsigned failed_rands;
+       struct axmap *io_axmap;
+
+       struct fio_lfsr lfsr;
 
        /*
         * Used for zipf random distribution
@@ -177,13 +178,11 @@ extern void free_release_files(struct thread_data *);
 
 static inline void fio_file_reset(struct fio_file *f)
 {
-       f->last_free_lookup = 0;
-       f->failed_rands = 0;
        f->last_pos = f->file_offset;
        f->last_start = -1ULL;
        f->file_pos = -1ULL;
-       if (f->file_map)
-               memset(f->file_map, 0, f->num_maps * sizeof(unsigned long));
+       if (f->io_axmap)
+               axmap_reset(f->io_axmap);
 }
 
 #endif
index 4a2383f1718ab390b9fc7ab4d3a05cb747d0ee7d..ee58a7b63333728a8a3e392b21e7f202ddecb6f5 100644 (file)
@@ -13,6 +13,7 @@
 #include "filehash.h"
 #include "os/os.h"
 #include "hash.h"
+#include "lib/axmap.h"
 
 #ifdef FIO_HAVE_LINUX_FALLOCATE
 #include <linux/falloc.h>
@@ -873,6 +874,9 @@ static int __init_rand_distribution(struct thread_data *td, struct fio_file *f)
        nranges = (f->real_file_size + range_size - 1) / range_size;
 
        seed = jhash(f->file_name, strlen(f->file_name), 0) * td->thread_number;
+       if (!td->o.rand_repeatable)
+               seed = td->rand_seeds[4];
+
        if (td->o.random_distribution == FIO_RAND_DIST_ZIPF)
                zipf_init(&f->zipf, nranges, td->o.zipf_theta.u.f, seed);
        else
@@ -901,28 +905,27 @@ static int init_rand_distribution(struct thread_data *td)
 
 int init_random_map(struct thread_data *td)
 {
-       unsigned long long blocks, num_maps;
+       unsigned long long blocks;
        struct fio_file *f;
        unsigned int i;
 
        if (init_rand_distribution(td))
                return 0;
-       if (td->o.norandommap || !td_random(td))
+       if (!td_random(td))
                return 0;
 
        for_each_file(td, f, i) {
                blocks = (f->real_file_size + td->o.rw_min_bs - 1) /
                                (unsigned long long) td->o.rw_min_bs;
-               num_maps = (blocks + BLOCKS_PER_MAP - 1) /
-                               (unsigned long long) BLOCKS_PER_MAP;
-               if (num_maps == (unsigned long) num_maps) {
-                       f->file_map = smalloc(num_maps * sizeof(unsigned long));
-                       if (f->file_map) {
-                               f->num_maps = num_maps;
+               if (td->o.random_generator == FIO_RAND_GEN_LFSR) {
+                       if (!lfsr_init(&f->lfsr, blocks))
                                continue;
-                       }
-               } else
-                       f->file_map = NULL;
+               } else if (!td->o.norandommap) {
+                       f->io_axmap = axmap_new(blocks);
+                       if (f->io_axmap)
+                               continue;
+               } else if (td->o.norandommap)
+                       continue;
 
                if (!td->o.softrandommap) {
                        log_err("fio: failed allocating random map. If running"
@@ -934,7 +937,6 @@ int init_random_map(struct thread_data *td)
 
                log_info("fio: file %s failed allocating random map. Running "
                         "job without.\n", f->file_name);
-               f->num_maps = 0;
        }
 
        return 0;
@@ -971,8 +973,8 @@ void close_and_free_files(struct thread_data *td)
 
                sfree(f->file_name);
                f->file_name = NULL;
-               sfree(f->file_map);
-               f->file_map = NULL;
+               axmap_free(f->io_axmap);
+               f->io_axmap = NULL;
                sfree(f);
        }
 
diff --git a/fio.1 b/fio.1
index 8d3fedf79a8fe034d4fb23cedd2730209498a949..02eafaec48d28178a6676d335bf0d8b37e195df6 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -580,6 +580,32 @@ overrides the first. This may interfere with a given rate setting, if fio is
 asked to limit reads or writes to a certain rate. If that is the case, then
 the distribution may be skewed. Default: 50.
 .TP
+.BI random_distribution \fR=\fPstr:float
+By default, fio will use a completely uniform random distribution when asked
+to perform random IO. Sometimes it is useful to skew the distribution in
+specific ways, ensuring that some parts of the data is more hot than others.
+Fio includes the following distribution models:
+.RS
+.TP
+.B random
+Uniform random distribution
+.TP
+.B zipf
+Zipf distribution
+.TP
+.B pareto
+Pareto distribution
+.TP
+.RE
+.P
+When using a zipf or pareto distribution, an input value is also needed to
+define the access pattern. For zipf, this is the zipf theta. For pareto,
+it's the pareto power. Fio includes a test program, genzipf, that can be
+used visualize what the given input values will yield in terms of hit rates.
+If you wanted to use zipf with a theta of 1.2, you would use
+random_distribution=zipf:1.2 as the option. If a non-uniform model is used,
+fio will disable use of the random map.
+.TP
 .B norandommap
 Normally \fBfio\fR will cover every block of the file when doing random I/O. If
 this parameter is given, a new offset will be chosen without looking at past
diff --git a/fio.h b/fio.h
index 5022cdfd300b2cf48b26309ec20fca04d152206d..43ad765821ce8d3a100902b40c62482b7a7aa92c 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -68,11 +68,23 @@ enum {
        RW_SEQ_IDENT,
 };
 
+
+enum {
+       TD_F_VER_BACKLOG        = 1,
+       TD_F_TRIM_BACKLOG       = 2,
+       TD_F_READ_IOLOG         = 4,
+       TD_F_REFILL_BUFFERS     = 8,
+       TD_F_SCRAMBLE_BUFFERS   = 16,
+       TD_F_VER_NONE           = 32,
+       TD_F_PROFILE_OPS        = 64,
+};
+
 /*
  * This describes a single thread/process executing a fio job.
  */
 struct thread_data {
        struct thread_options o;
+       unsigned long flags;
        void *eo;
        char verror[FIO_VERROR_SIZE];
        pthread_t thread;
@@ -348,11 +360,6 @@ static inline void fio_ro_check(struct thread_data *td, struct io_u *io_u)
        assert(!(io_u->ddir == DDIR_WRITE && !td_write(td)));
 }
 
-#define BLOCKS_PER_MAP         (8 * sizeof(unsigned long))
-#define TO_MAP_BLOCK(f, b)     (b)
-#define RAND_MAP_IDX(f, b)     (TO_MAP_BLOCK(f, b) / BLOCKS_PER_MAP)
-#define RAND_MAP_BIT(f, b)     (TO_MAP_BLOCK(f, b) & (BLOCKS_PER_MAP - 1))
-
 #define REAL_MAX_JOBS          2048
 
 static inline enum error_type_bit td_error_type(enum fio_ddir ddir, int err)
@@ -452,8 +459,8 @@ enum {
        TD_NOT_CREATED = 0,
        TD_CREATED,
        TD_INITIALIZED,
-       TD_SETTING_UP,
        TD_RAMP,
+       TD_SETTING_UP,
        TD_RUNNING,
        TD_PRE_READING,
        TD_VERIFYING,
@@ -596,4 +603,9 @@ enum {
        FIO_RAND_DIST_PARETO,
 };
 
+enum {
+       FIO_RAND_GEN_TAUSWORTHE = 0,
+       FIO_RAND_GEN_LFSR,
+};
+
 #endif
index 5be45ccf5f3954b3c87494132d7f0cdf94825814..1b4e1d0a2c9ccabe9c3e6483223f2abae54b5c7d 100644 (file)
--- a/helpers.c
+++ b/helpers.c
@@ -50,3 +50,10 @@ int _weak sync_file_range(int fd, off64_t offset, off64_t nbytes,
        return -1;
 }
 #endif
+
+#ifndef FIO_HAVE_FADVISE
+int _weak posix_fadvise(int fd, off_t offset, off_t len, int advice)
+{
+       return 0;
+}
+#endif
index ed2086d147cee112fd4681ef45b8d63681c3247a..191096bde600b07c1ed352b69cd4d72cf193a337 100644 (file)
--- a/helpers.h
+++ b/helpers.h
@@ -15,5 +15,6 @@ extern int _weak inet_aton(const char *cp, struct in_addr *inp);
 extern int _weak clock_gettime(clockid_t clk_id, struct timespec *ts);
 extern int _weak sync_file_range(int fd, off64_t offset, off64_t nbytes,
                                        unsigned int flags);
+extern int _weak posix_fadvise(int fd, off_t offset, off_t len, int advice);
 
 #endif /* FIO_HELPERS_H_ */
diff --git a/init.c b/init.c
index bdee8a21bf8e43cbdba7b106a920b57e1cc6717d..59b472753e50422e6e2883c30ba10eecc41a4a26 100644 (file)
--- a/init.c
+++ b/init.c
@@ -9,7 +9,9 @@
 #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>
 
@@ -603,6 +605,13 @@ static int fixup_options(struct thread_data *td)
                td->o.compress_percentage = 0;
        }
 
+       /*
+        * Using a non-uniform random distribution excludes usage of
+        * a random map
+        */
+       if (td->o.random_distribution != FIO_RAND_DIST_RANDOM)
+               td->o.norandommap = 1;
+
        return ret;
 }
 
@@ -765,6 +774,24 @@ int ioengine_load(struct thread_data *td)
        return 0;
 }
 
+static void init_flags(struct thread_data *td)
+{
+       struct thread_options *o = &td->o;
+
+       if (o->verify_backlog)
+               td->flags |= TD_F_VER_BACKLOG;
+       if (o->trim_backlog)
+               td->flags |= TD_F_TRIM_BACKLOG;
+       if (o->read_iolog_file)
+               td->flags |= TD_F_READ_IOLOG;
+       if (o->refill_buffers)
+               td->flags |= TD_F_REFILL_BUFFERS;
+       if (o->scramble_buffers)
+               td->flags |= TD_F_SCRAMBLE_BUFFERS;
+       if (o->verify != VERIFY_NONE)
+               td->flags |= TD_F_VER_NONE;
+}
+
 /*
  * Adds a job to the list of things todo. Sanitizes the various options
  * to make sure we don't have conflicts, and initializes various
@@ -783,6 +810,8 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
        if (td == &def_thread)
                return 0;
 
+       init_flags(td);
+
        /*
         * if we are just dumping the output command line, don't add the job
         */
index f28f7555ceeadffbe819e54fdd2d2d386cc6b990..8df24b8a97d77e53e836654e4fc5e2ae411bdbf2 100644 (file)
--- a/io_ddir.h
+++ b/io_ddir.h
@@ -30,7 +30,7 @@ enum td_ddir {
 #define td_trim(td)            ((td)->o.td_ddir & TD_DDIR_TRIM)
 #define td_rw(td)              (((td)->o.td_ddir & TD_DDIR_RW) == TD_DDIR_RW)
 #define td_random(td)          ((td)->o.td_ddir & TD_DDIR_RAND)
-#define file_randommap(td, f)  (!(td)->o.norandommap && (f)->file_map)
+#define file_randommap(td, f)  (!(td)->o.norandommap && (f)->io_axmap)
 
 static inline int ddir_sync(enum fio_ddir ddir)
 {
diff --git a/io_u.c b/io_u.c
index dcb56f1a5a854b1cb5e0c924ffa67072cd8adee0..6f1db1842c677337faa705008f3eef42e04ee01f 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -10,6 +10,7 @@
 #include "verify.h"
 #include "trim.h"
 #include "lib/rand.h"
+#include "lib/axmap.h"
 
 struct io_completion_data {
        int nr;                         /* input */
@@ -20,17 +21,12 @@ struct io_completion_data {
 };
 
 /*
- * The ->file_map[] contains a map of blocks we have or have not done io
+ * The ->io_axmap contains a map of blocks we have or have not done io
  * to yet. Used to make sure we cover the entire range in a fair fashion.
  */
 static int random_map_free(struct fio_file *f, const unsigned long long block)
 {
-       unsigned int idx = RAND_MAP_IDX(f, block);
-       unsigned int bit = RAND_MAP_BIT(f, block);
-
-       dprint(FD_RANDOM, "free: b=%llu, idx=%u, bit=%u\n", block, idx, bit);
-
-       return (f->file_map[idx] & (1UL << bit)) == 0;
+       return !axmap_isset(f->io_axmap, block);
 }
 
 /*
@@ -41,61 +37,16 @@ static void mark_random_map(struct thread_data *td, struct io_u *io_u)
        unsigned int min_bs = td->o.rw_min_bs;
        struct fio_file *f = io_u->file;
        unsigned long long block;
-       unsigned int blocks, nr_blocks;
-       int busy_check;
+       unsigned int nr_blocks;
 
        block = (io_u->offset - f->file_offset) / (unsigned long long) min_bs;
        nr_blocks = (io_u->buflen + min_bs - 1) / min_bs;
-       blocks = 0;
-       busy_check = !(io_u->flags & IO_U_F_BUSY_OK);
-
-       while (nr_blocks) {
-               unsigned int idx, bit;
-               unsigned long mask, this_blocks;
-
-               /*
-                * If we have a mixed random workload, we may
-                * encounter blocks we already did IO to.
-                */
-               if (!busy_check) {
-                       blocks = nr_blocks;
-                       break;
-               }
-               if ((td->o.ddir_seq_nr == 1) && !random_map_free(f, block))
-                       break;
-
-               idx = RAND_MAP_IDX(f, block);
-               bit = RAND_MAP_BIT(f, block);
 
-               fio_assert(td, idx < f->num_maps);
-
-               this_blocks = nr_blocks;
-               if (this_blocks + bit > BLOCKS_PER_MAP)
-                       this_blocks = BLOCKS_PER_MAP - bit;
-
-               do {
-                       if (this_blocks == BLOCKS_PER_MAP)
-                               mask = -1UL;
-                       else
-                               mask = ((1UL << this_blocks) - 1) << bit;
-
-                       if (!(f->file_map[idx] & mask))
-                               break;
-
-                       this_blocks--;
-               } while (this_blocks);
-
-               if (!this_blocks)
-                       break;
-
-               f->file_map[idx] |= mask;
-               nr_blocks -= this_blocks;
-               blocks += this_blocks;
-               block += this_blocks;
-       }
+       if (!(io_u->flags & IO_U_F_BUSY_OK))
+               nr_blocks = axmap_set_nr(f->io_axmap, block, nr_blocks);
 
-       if ((blocks * min_bs) < io_u->buflen)
-               io_u->buflen = blocks * min_bs;
+       if ((nr_blocks * min_bs) < io_u->buflen)
+               io_u->buflen = nr_blocks * min_bs;
 }
 
 static unsigned long long last_block(struct thread_data *td, struct fio_file *f,
@@ -123,113 +74,57 @@ static unsigned long long last_block(struct thread_data *td, struct fio_file *f,
        return max_blocks;
 }
 
-/*
- * Return the next free block in the map.
- */
-static int get_next_free_block(struct thread_data *td, struct fio_file *f,
-                              enum fio_ddir ddir, unsigned long long *b)
-{
-       unsigned long long block, min_bs = td->o.rw_min_bs, lastb;
-       int i;
-
-       lastb = last_block(td, f, ddir);
-       if (!lastb)
-               return 1;
-
-       i = f->last_free_lookup;
-       block = i * BLOCKS_PER_MAP;
-       while (block * min_bs < f->real_file_size &&
-               block * min_bs < f->io_size) {
-               if (f->file_map[i] != -1UL) {
-                       block += ffz(f->file_map[i]);
-                       if (block > lastb)
-                               break;
-                       f->last_free_lookup = i;
-                       *b = block;
-                       return 0;
-               }
-
-               block += BLOCKS_PER_MAP;
-               i++;
-       }
-
-       dprint(FD_IO, "failed finding a free block\n");
-       return 1;
-}
-
 static int __get_next_rand_offset(struct thread_data *td, struct fio_file *f,
                                  enum fio_ddir ddir, unsigned long long *b)
 {
-       unsigned long long rmax, r, lastb;
-       int loops = 5;
+       unsigned long long r;
 
-       lastb = last_block(td, f, ddir);
-       if (!lastb)
-               return 1;
+       if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE) {
+               unsigned long long rmax, lastb;
 
-       if (f->failed_rands >= 200)
-               goto ffz;
+               lastb = last_block(td, f, ddir);
+               if (!lastb)
+                       return 1;
 
-       rmax = td->o.use_os_rand ? OS_RAND_MAX : FRAND_MAX;
-       do {
-               if (td->o.use_os_rand)
+               rmax = td->o.use_os_rand ? OS_RAND_MAX : FRAND_MAX;
+
+               if (td->o.use_os_rand) {
+                       rmax = OS_RAND_MAX;
                        r = os_random_long(&td->random_state);
-               else
+               } else {
+                       rmax = FRAND_MAX;
                        r = __rand(&td->__random_state);
-
-               *b = (lastb - 1) * (r / ((unsigned long long) rmax + 1.0));
+               }
 
                dprint(FD_RANDOM, "off rand %llu\n", r);
 
+               *b = (lastb - 1) * (r / ((unsigned long long) rmax + 1.0));
+       } else {
+               uint64_t off = 0;
 
-               /*
-                * if we are not maintaining a random map, we are done.
-                */
-               if (!file_randommap(td, f))
-                       goto ret_good;
-
-               /*
-                * calculate map offset and check if it's free
-                */
-               if (random_map_free(f, *b))
-                       goto ret_good;
-
-               dprint(FD_RANDOM, "get_next_rand_offset: offset %llu busy\n",
-                                                                       *b);
-       } while (--loops);
+               if (lfsr_next(&f->lfsr, &off))
+                       return 1;
 
-       if (!f->failed_rands++)
-               f->last_free_lookup = 0;
+               *b = off;
+       }
 
        /*
-        * we get here, if we didn't suceed in looking up a block. generate
-        * a random start offset into the filemap, and find the first free
-        * block from there.
+        * if we are not maintaining a random map, we are done.
         */
-       loops = 10;
-       do {
-               f->last_free_lookup = (f->num_maps - 1) *
-                                       (r / ((unsigned long long) rmax + 1.0));
-               if (!get_next_free_block(td, f, ddir, b))
-                       goto ret;
-
-               if (td->o.use_os_rand)
-                       r = os_random_long(&td->random_state);
-               else
-                       r = __rand(&td->__random_state);
-       } while (--loops);
+       if (!file_randommap(td, f))
+               goto ret;
 
        /*
-        * that didn't work either, try exhaustive search from the start
+        * calculate map offset and check if it's free
         */
-       f->last_free_lookup = 0;
-ffz:
-       if (!get_next_free_block(td, f, ddir, b))
-               return 0;
-       f->last_free_lookup = 0;
-       return get_next_free_block(td, f, ddir, b);
-ret_good:
-       f->failed_rands = 0;
+       if (random_map_free(f, *b))
+               goto ret;
+
+       dprint(FD_RANDOM, "get_next_rand_offset: offset %llu busy\n", *b);
+
+       *b = axmap_next_free(f->io_axmap, *b);
+       if (*b == (uint64_t) -1ULL)
+               return 1;
 ret:
        return 0;
 }
@@ -347,7 +242,8 @@ static int get_next_block(struct thread_data *td, struct io_u *io_u,
                else if (b != -1ULL)
                        io_u->offset = b * td->o.ba[ddir];
                else {
-                       log_err("fio: bug in offset generation\n");
+                       log_err("fio: bug in offset generation: offset=%llu, b=%llu\n",
+                                                               offset, b);
                        ret = 1;
                }
        }
@@ -394,10 +290,12 @@ static int __get_next_offset(struct thread_data *td, struct io_u *io_u)
 
 static int get_next_offset(struct thread_data *td, struct io_u *io_u)
 {
-       struct prof_io_ops *ops = &td->prof_io_ops;
+       if (td->flags & TD_F_PROFILE_OPS) {
+               struct prof_io_ops *ops = &td->prof_io_ops;
 
-       if (ops->fill_io_u_off)
-               return ops->fill_io_u_off(td, io_u);
+               if (ops->fill_io_u_off)
+                       return ops->fill_io_u_off(td, io_u);
+       }
 
        return __get_next_offset(td, io_u);
 }
@@ -472,10 +370,12 @@ static unsigned int __get_next_buflen(struct thread_data *td, struct io_u *io_u)
 
 static unsigned int get_next_buflen(struct thread_data *td, struct io_u *io_u)
 {
-       struct prof_io_ops *ops = &td->prof_io_ops;
+       if (td->flags & TD_F_PROFILE_OPS) {
+               struct prof_io_ops *ops = &td->prof_io_ops;
 
-       if (ops->fill_io_u_size)
-               return ops->fill_io_u_size(td, io_u);
+               if (ops->fill_io_u_size)
+                       return ops->fill_io_u_size(td, io_u);
+       }
 
        return __get_next_buflen(td, io_u);
 }
@@ -1064,10 +964,12 @@ out:
 
 static struct fio_file *get_next_file(struct thread_data *td)
 {
-       struct prof_io_ops *ops = &td->prof_io_ops;
+       if (!(td->flags & TD_F_PROFILE_OPS)) {
+               struct prof_io_ops *ops = &td->prof_io_ops;
 
-       if (ops->get_next_file)
-               return ops->get_next_file(td);
+               if (ops->get_next_file)
+                       return ops->get_next_file(td);
+       }
 
        return __get_next_file(td);
 }
@@ -1144,7 +1046,10 @@ again:
 
 static int check_get_trim(struct thread_data *td, struct io_u *io_u)
 {
-       if (td->o.trim_backlog && td->trim_entries) {
+       if (!(td->flags & TD_F_TRIM_BACKLOG))
+               return 0;
+
+       if (td->trim_entries) {
                int get_trim = 0;
 
                if (td->trim_batch) {
@@ -1167,7 +1072,10 @@ static int check_get_trim(struct thread_data *td, struct io_u *io_u)
 
 static int check_get_verify(struct thread_data *td, struct io_u *io_u)
 {
-       if (td->o.verify_backlog && td->io_hist_len) {
+       if (!(td->flags & TD_F_VER_BACKLOG))
+               return 0;
+
+       if (td->io_hist_len) {
                int get_verify = 0;
 
                if (td->verify_batch)
@@ -1258,7 +1166,7 @@ struct io_u *get_io_u(struct thread_data *td)
        /*
         * If using an iolog, grab next piece if any available.
         */
-       if (td->o.read_iolog_file) {
+       if (td->flags & TD_F_READ_IOLOG) {
                if (read_iolog_get(td, io_u))
                        goto err_put;
        } else if (set_io_u_file(td, io_u)) {
@@ -1279,12 +1187,12 @@ struct io_u *get_io_u(struct thread_data *td)
                f->last_pos = io_u->offset + io_u->buflen;
 
                if (io_u->ddir == DDIR_WRITE) {
-                       if (td->o.refill_buffers) {
+                       if (td->flags & TD_F_REFILL_BUFFERS) {
                                io_u_fill_buffer(td, io_u,
                                        io_u->xfer_buflen, io_u->xfer_buflen);
-                       } else if (td->o.scramble_buffers)
+                       } else if (td->flags & TD_F_SCRAMBLE_BUFFERS)
                                do_scramble = 1;
-                       if (td->o.verify != VERIFY_NONE) {
+                       if (td->flags & TD_F_VER_NONE) {
                                populate_verify_io_u(td, io_u);
                                do_scramble = 0;
                        }
index b4bc22b8968b00039989734ebc720567ff72f340..1cd08af8c25516a83c47ae33673067e09b361928 100644 (file)
@@ -6,7 +6,7 @@
 #include "debug.h"
 #include "file.h"
 
-#define FIO_IOOPS_VERSION      13
+#define FIO_IOOPS_VERSION      14
 
 enum {
        IO_U_F_FREE             = 1 << 0,
@@ -52,12 +52,16 @@ struct io_u {
        struct timeval start_time;
        struct timeval issue_time;
 
+       struct fio_file *file;
+       unsigned int flags;
+       enum fio_ddir ddir;
+
        /*
         * Allocated/set buffer and length
         */
-       void *buf;
        unsigned long buflen;
        unsigned long long offset;
+       void *buf;
 
        /*
         * Initial seed for generating the buffer contents
@@ -80,8 +84,6 @@ struct io_u {
        unsigned int resid;
        unsigned int error;
 
-       enum fio_ddir ddir;
-
        /*
         * io engine private data
         */
@@ -91,10 +93,6 @@ struct io_u {
                void *engine_data;
        };
 
-       unsigned int flags;
-
-       struct fio_file *file;
-
        struct flist_head list;
 
        /*
@@ -129,6 +127,7 @@ struct ioengine_ops {
        int (*open_file)(struct thread_data *, struct fio_file *);
        int (*close_file)(struct thread_data *, struct fio_file *);
        int (*get_file_size)(struct thread_data *, struct fio_file *);
+       void (*terminate)(struct thread_data *);
        int option_struct_size;
        struct fio_option *options;
        void *data;
@@ -143,10 +142,9 @@ enum fio_ioengine_flags {
        FIO_NODISKUTIL  = 1 << 4,       /* diskutil can't handle filename */
        FIO_UNIDIR      = 1 << 5,       /* engine is uni-directional */
        FIO_NOIO        = 1 << 6,       /* thread does only pseudo IO */
-       FIO_SIGTERM     = 1 << 7,       /* needs SIGTERM to exit */
-       FIO_PIPEIO      = 1 << 8,       /* input/output no seekable */
-       FIO_BARRIER     = 1 << 9,       /* engine supports barriers */
-       FIO_MEMALIGN    = 1 << 10,      /* engine wants aligned memory */
+       FIO_PIPEIO      = 1 << 7,       /* input/output no seekable */
+       FIO_BARRIER     = 1 << 8,       /* engine supports barriers */
+       FIO_MEMALIGN    = 1 << 9,       /* engine wants aligned memory */
 };
 
 /*
diff --git a/lib/axmap.c b/lib/axmap.c
new file mode 100644 (file)
index 0000000..a44e0ec
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * Bitmap of bitmaps, where each layer is number-of-bits-per-word smaller than
+ * the previous. Hence an 'axmap', since we axe each previous layer into a
+ * much smaller piece. I swear, that is why it's named like that. It has
+ * nothing to do with anything remotely narcissistic.
+ *
+ * A set bit at layer N indicates a full word at layer N-1, and so forth. As
+ * the bitmap becomes progressively more full, checking for existance
+ * becomes cheaper (since fewer layers are walked, making it a lot more
+ * cache friendly) and locating the next free space likewise.
+ *
+ * Axmaps get pretty close to optimal (1 bit per block) space usage, since
+ * layers quickly diminish in size. Doing the size math is straight forward,
+ * since we have log64(blocks) layers of maps. For 20000 blocks, overhead
+ * is roughly 1.9%, or 1.019 bits per block. The number quickly converges
+ * towards 1.0158, or 1.58% of overhead.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "../arch/arch.h"
+#include "axmap.h"
+#include "../smalloc.h"
+#include "../minmax.h"
+
+#if BITS_PER_LONG == 64
+#define UNIT_SHIFT             6
+#elif BITS_PER_LONG == 32
+#define UNIT_SHIFT             5
+#else
+#error "Number of arch bits unknown"
+#endif
+
+#define BLOCKS_PER_UNIT                (1UL << UNIT_SHIFT)
+#define BLOCKS_PER_UNIT_MASK   (BLOCKS_PER_UNIT - 1)
+
+#define firstfree_valid(b)     ((b)->first_free != (uint64_t) -1)
+
+struct axmap_level {
+       int level;
+       unsigned long map_size;
+       unsigned long *map;
+};
+
+struct axmap {
+       unsigned int nr_levels;
+       struct axmap_level *levels;
+       uint64_t first_free;
+};
+
+static unsigned long ulog64(unsigned long val, unsigned int log)
+{
+       while (log-- && val)
+               val >>= UNIT_SHIFT;
+
+       return val;
+}
+
+void axmap_reset(struct axmap *axmap)
+{
+       int i;
+
+       for (i = 0; i < axmap->nr_levels; i++) {
+               struct axmap_level *al = &axmap->levels[i];
+
+               memset(al->map, 0, al->map_size * sizeof(unsigned long));
+       }
+}
+
+void axmap_free(struct axmap *axmap)
+{
+       unsigned int i;
+
+       if (!axmap)
+               return;
+
+       for (i = 0; i < axmap->nr_levels; i++)
+               sfree(axmap->levels[i].map);
+
+       sfree(axmap->levels);
+       sfree(axmap);
+}
+
+struct axmap *axmap_new(unsigned long nr_bits)
+{
+       struct axmap *axmap;
+       unsigned int i, levels;
+
+       axmap = smalloc(sizeof(*axmap));
+       if (!axmap)
+               return NULL;
+
+       levels = 1;
+       i = (nr_bits + BLOCKS_PER_UNIT - 1) >> UNIT_SHIFT;
+       while (i > 1) {
+               i = (i + BLOCKS_PER_UNIT - 1) >> UNIT_SHIFT;
+               levels++;
+       }
+
+       axmap->nr_levels = levels;
+       axmap->levels = smalloc(axmap->nr_levels * sizeof(struct axmap_level));
+       axmap->first_free = 0;
+
+       for (i = 0; i < axmap->nr_levels; i++) {
+               struct axmap_level *al = &axmap->levels[i];
+
+               al->level = i;
+               al->map_size = (nr_bits + BLOCKS_PER_UNIT - 1) >> UNIT_SHIFT;
+               al->map = smalloc(al->map_size * sizeof(unsigned long));
+               if (!al->map)
+                       goto err;
+
+               nr_bits = (nr_bits + BLOCKS_PER_UNIT - 1) >> UNIT_SHIFT;
+       }
+
+       axmap_reset(axmap);
+       return axmap;
+err:
+       for (i = 0; i < axmap->nr_levels; i++)
+               if (axmap->levels[i].map)
+                       sfree(axmap->levels[i].map);
+
+       sfree(axmap->levels);
+       return NULL;
+}
+
+static int axmap_handler(struct axmap *axmap, uint64_t bit_nr,
+                         int (*func)(struct axmap_level *, unsigned long, unsigned int,
+                         void *), void *data)
+{
+       struct axmap_level *al;
+       int i;
+
+       for (i = 0; i < axmap->nr_levels; i++) {
+               unsigned long index = ulog64(bit_nr, i);
+               unsigned long offset = index >> UNIT_SHIFT;
+               unsigned int bit = index & BLOCKS_PER_UNIT_MASK;
+
+               al = &axmap->levels[i];
+
+               if (func(al, offset, bit, data))
+                       return 1;
+       }
+
+       return 0;
+}
+
+static int axmap_handler_topdown(struct axmap *axmap, uint64_t bit_nr,
+       int (*func)(struct axmap_level *, unsigned long, unsigned int, void *),
+       void *data)
+{
+       struct axmap_level *al;
+       int i, level = axmap->nr_levels;
+
+       for (i = axmap->nr_levels - 1; i >= 0; i--) {
+               unsigned long index = ulog64(bit_nr, --level);
+               unsigned long offset = index >> UNIT_SHIFT;
+               unsigned int bit = index & BLOCKS_PER_UNIT_MASK;
+
+               al = &axmap->levels[i];
+
+               if (func(al, offset, bit, data))
+                       return 1;
+       }
+
+       return 0;
+}
+
+static int axmap_clear_fn(struct axmap_level *al, unsigned long offset,
+                          unsigned int bit, void *unused)
+{
+       if (!(al->map[offset] & (1UL << bit)))
+               return 1;
+
+       al->map[offset] &= ~(1UL << bit);
+       return 0;
+}
+
+void axmap_clear(struct axmap *axmap, uint64_t bit_nr)
+{
+       axmap_handler(axmap, bit_nr, axmap_clear_fn, NULL);
+}
+
+struct axmap_set_data {
+       unsigned int nr_bits;
+       unsigned int set_bits;
+       unsigned int fail_ok;
+};
+
+static unsigned long bit_masks[] = {
+       0x0000000000000000, 0x0000000000000001, 0x0000000000000003, 0x0000000000000007,
+       0x000000000000000f, 0x000000000000001f, 0x000000000000003f, 0x000000000000007f,
+       0x00000000000000ff, 0x00000000000001ff, 0x00000000000003ff, 0x00000000000007ff,
+       0x0000000000000fff, 0x0000000000001fff, 0x0000000000003fff, 0x0000000000007fff,
+       0x000000000000ffff, 0x000000000001ffff, 0x000000000003ffff, 0x000000000007ffff,
+       0x00000000000fffff, 0x00000000001fffff, 0x00000000003fffff, 0x00000000007fffff,
+       0x0000000000ffffff, 0x0000000001ffffff, 0x0000000003ffffff, 0x0000000007ffffff,
+       0x000000000fffffff, 0x000000001fffffff, 0x000000003fffffff, 0x000000007fffffff,
+       0x00000000ffffffff,
+#if BITS_PER_LONG == 64
+       0x00000001ffffffff, 0x00000003ffffffff, 0x00000007ffffffff, 0x0000000fffffffff,
+       0x0000001fffffffff, 0x0000003fffffffff, 0x0000007fffffffff, 0x000000ffffffffff,
+       0x000001ffffffffff, 0x000003ffffffffff, 0x000007ffffffffff, 0x00000fffffffffff,
+       0x00001fffffffffff, 0x00003fffffffffff, 0x00007fffffffffff, 0x0000ffffffffffff,
+       0x0001ffffffffffff, 0x0003ffffffffffff, 0x0007ffffffffffff, 0x000fffffffffffff,
+       0x001fffffffffffff, 0x003fffffffffffff, 0x007fffffffffffff, 0x00ffffffffffffff,
+       0x01ffffffffffffff, 0x03ffffffffffffff, 0x07ffffffffffffff, 0x0fffffffffffffff,
+       0x1fffffffffffffff, 0x3fffffffffffffff, 0x7fffffffffffffff, 0xffffffffffffffff
+#endif
+};
+
+static int axmap_set_fn(struct axmap_level *al, unsigned long offset,
+                        unsigned int bit, void *__data)
+{
+       struct axmap_set_data *data = __data;
+       unsigned long mask, overlap;
+       unsigned int nr_bits;
+
+       nr_bits = min(data->nr_bits, BLOCKS_PER_UNIT - bit);
+
+       mask = bit_masks[nr_bits] << bit;
+
+       /*
+        * Mask off any potential overlap, only sets contig regions
+        */
+       overlap = al->map[offset] & mask;
+       if (overlap == mask) {
+               assert(data->fail_ok);
+               return 1;
+       }
+
+       while (overlap) {
+               unsigned long clear_mask = ~(1UL << ffz(~overlap));
+
+               mask &= clear_mask;
+               overlap &= clear_mask;
+               nr_bits--;
+       }
+
+       assert(mask);
+       assert(!(al->map[offset] & mask));
+               
+       al->map[offset] |= mask;
+
+       if (!al->level)
+               data->set_bits = nr_bits;
+
+       data->nr_bits = 1;
+       return al->map[offset] != -1UL;
+}
+
+static void __axmap_set(struct axmap *axmap, uint64_t bit_nr,
+                        struct axmap_set_data *data)
+{
+       unsigned int set_bits, nr_bits = data->nr_bits;
+
+       if (axmap->first_free >= bit_nr &&
+           axmap->first_free < bit_nr + data->nr_bits)
+               axmap->first_free = -1ULL;
+
+       set_bits = 0;
+       while (nr_bits) {
+               axmap_handler(axmap, bit_nr, axmap_set_fn, data);
+               set_bits += data->set_bits;
+
+               if (data->set_bits != (BLOCKS_PER_UNIT - nr_bits))
+                       break;
+
+               nr_bits -= data->set_bits;
+               bit_nr += data->set_bits;
+
+               data->nr_bits = nr_bits;
+               data->fail_ok = 1;
+       }
+
+       data->set_bits = set_bits;
+}
+
+void axmap_set(struct axmap *axmap, uint64_t bit_nr)
+{
+       struct axmap_set_data data = { .nr_bits = 1, };
+
+       __axmap_set(axmap, bit_nr, &data);
+}
+
+unsigned int axmap_set_nr(struct axmap *axmap, uint64_t bit_nr, unsigned int nr_bits)
+{
+       struct axmap_set_data data = { .nr_bits = nr_bits, };
+
+       __axmap_set(axmap, bit_nr, &data);
+       return data.set_bits;
+}
+
+static int axmap_isset_fn(struct axmap_level *al, unsigned long offset,
+                           unsigned int bit, void *unused)
+{
+       return (al->map[offset] & (1UL << bit)) != 0;
+}
+
+int axmap_isset(struct axmap *axmap, uint64_t bit_nr)
+{
+       return axmap_handler_topdown(axmap, bit_nr, axmap_isset_fn, NULL);
+}
+
+static uint64_t axmap_find_first_free(struct axmap *axmap, unsigned int level,
+                                      uint64_t index)
+{
+       unsigned long j;
+       int i;
+
+       /*
+        * Start at the bottom, then converge towards first free bit at the top
+        */
+       for (i = level; i >= 0; i--) {
+               struct axmap_level *al = &axmap->levels[i];
+
+               if (index >= al->map_size) {
+                       index = -1ULL;
+                       break;
+               }
+
+               for (j = index; j < al->map_size; j++) {
+                       if (al->map[j] == -1UL)
+                               continue;
+
+                       /*
+                        * First free bit here is our index into the first
+                        * free bit at the next higher level
+                        */
+                       index = (j << UNIT_SHIFT) + ffz(al->map[j]);
+                       break;
+               }
+       }
+
+       return index;
+}
+
+uint64_t axmap_first_free(struct axmap *axmap)
+{
+       if (firstfree_valid(axmap))
+               return axmap->first_free;
+
+       axmap->first_free = axmap_find_first_free(axmap, axmap->nr_levels - 1, 0);
+       return axmap->first_free;
+}
+
+struct axmap_next_free_data {
+       unsigned int level;
+       unsigned long offset;
+       uint64_t bit;
+};
+
+static int axmap_next_free_fn(struct axmap_level *al, unsigned long offset,
+                              unsigned int bit, void *__data)
+{
+       struct axmap_next_free_data *data = __data;
+       uint64_t mask = ~((1UL << ((data->bit & BLOCKS_PER_UNIT_MASK) + 1)) - 1);
+
+       if (!(mask & al->map[offset]))
+               return 0;
+
+       if (al->map[offset] != -1UL) {
+               data->level = al->level;
+               data->offset = offset;
+               return 1;
+       }
+
+       data->bit = (data->bit + BLOCKS_PER_UNIT - 1) / BLOCKS_PER_UNIT;
+       return 0;
+}
+
+/*
+ * 'bit_nr' is already set. Find the next free bit after this one.
+ */
+uint64_t axmap_next_free(struct axmap *axmap, uint64_t bit_nr)
+{
+       struct axmap_next_free_data data = { .level = -1U, .bit = bit_nr, };
+
+       if (firstfree_valid(axmap) && bit_nr < axmap->first_free)
+               return axmap->first_free;
+
+       if (!axmap_handler(axmap, bit_nr, axmap_next_free_fn, &data))
+               return axmap_first_free(axmap);
+
+       assert(data.level != -1U);
+
+       return axmap_find_first_free(axmap, data.level, data.offset);
+}
diff --git a/lib/axmap.h b/lib/axmap.h
new file mode 100644 (file)
index 0000000..edfeba8
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef FIO_BITMAP_H
+#define FIO_BITMAP_H
+
+#include <inttypes.h>
+
+struct axmap;
+struct axmap *axmap_new(unsigned long nr_bits);
+void axmap_free(struct axmap *bm);
+
+void axmap_clear(struct axmap *axmap, uint64_t bit_nr);
+void axmap_set(struct axmap *axmap, uint64_t bit_nr);
+unsigned int axmap_set_nr(struct axmap *axmap, uint64_t bit_nr, unsigned int nr_bits);
+int axmap_isset(struct axmap *axmap, uint64_t bit_nr);
+uint64_t axmap_first_free(struct axmap *axmap);
+uint64_t axmap_next_free(struct axmap *axmap, uint64_t bit_nr);
+void axmap_reset(struct axmap *axmap);
+
+#endif
diff --git a/lib/lfsr.c b/lib/lfsr.c
new file mode 100644 (file)
index 0000000..01c97cb
--- /dev/null
@@ -0,0 +1,269 @@
+#include <stdio.h>
+
+#include "lfsr.h"
+
+/*
+ * From table 3 of
+ *
+ * http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
+ */
+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, },
+       },
+};
+
+#define FIO_LFSR_CRANKS                128
+
+static uint64_t __lfsr_next(uint64_t v, struct lfsr_taps *lt)
+{
+       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);
+}
+
+int lfsr_next(struct fio_lfsr *fl, uint64_t *off)
+{
+       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)
+                       break;
+       } while (1);
+
+       *off = fl->last_val - 1;
+       fl->num_vals++;
+       return 0;
+}
+
+static struct lfsr_taps *find_lfsr(uint64_t size)
+{
+       int i;
+
+       for (i = 0; lfsr_taps[i].length; i++)
+               if (((1UL << lfsr_taps[i].length) + FIO_LFSR_CRANKS) >= size)
+                       return &lfsr_taps[i];
+
+       return NULL;
+}
+
+int lfsr_init(struct fio_lfsr *fl, uint64_t size)
+{
+       struct lfsr_taps *tap;
+       int i;
+
+       tap = find_lfsr(size);
+       if (!tap)
+               return 1;
+
+       fl->last_val = 1;
+       fl->max_val = size - 1;
+       fl->num_vals = 0;
+       fl->taps.length = tap->length;
+       for (i = 0; i < FIO_MAX_TAPS; i++) {
+               fl->taps.taps[i] = tap->taps[i];
+               if (!fl->taps.taps[i])
+                       break;
+       }
+
+       for (i = 0; i < FIO_LFSR_CRANKS; i++)
+               fl->last_val = __lfsr_next(fl->last_val, &fl->taps);
+
+       return 0;
+}
diff --git a/lib/lfsr.h b/lib/lfsr.h
new file mode 100644 (file)
index 0000000..0de9ea8
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef FIO_LFSR_H
+#define FIO_LFSR_H
+
+#include <inttypes.h>
+
+#define FIO_MAX_TAPS   8
+
+struct lfsr_taps {
+       unsigned int length;
+       unsigned int taps[FIO_MAX_TAPS];
+};
+
+
+struct fio_lfsr {
+       uint64_t last_val;
+       uint64_t max_val;
+       uint64_t num_vals;
+       struct lfsr_taps taps;
+};
+
+int lfsr_next(struct fio_lfsr *fl, uint64_t *off);
+int lfsr_init(struct fio_lfsr *fl, uint64_t size);
+
+#endif
index b48d7c27c07d1dbcc325d619c7549d09a16baae6..5395dd2d690f45deda57a0b2124fb61eb1b58ea9 100644 (file)
--- a/libfio.c
+++ b/libfio.c
@@ -168,6 +168,7 @@ void td_set_runstate(struct thread_data *td, int runstate)
 void fio_terminate_threads(int group_id)
 {
        struct thread_data *td;
+       pid_t pid = getpid();
        int i;
 
        dprint(FD_PROCESS, "terminate group_id=%d\n", group_id);
@@ -182,15 +183,15 @@ void fio_terminate_threads(int group_id)
                        /*
                         * if the thread is running, just let it exit
                         */
-                       if (!td->pid)
+                       if (!td->pid || pid == td->pid)
                                continue;
                        else if (td->runstate < TD_RAMP)
                                kill(td->pid, SIGTERM);
                        else {
                                struct ioengine_ops *ops = td->io_ops;
 
-                               if (ops && (ops->flags & FIO_SIGTERM))
-                                       kill(td->pid, SIGTERM);
+                               if (ops && ops->terminate)
+                                       ops->terminate(td);
                        }
                }
        }
index f97749bc72c657f7b0d9f3739853dd7039797280..5293af96b226240117d312f24875f0406ceff5fd 100644 (file)
--- a/memory.c
+++ b/memory.c
@@ -5,7 +5,9 @@
 #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"
@@ -119,6 +121,13 @@ static int alloc_mem_mmap(struct thread_data *td, size_t total_mem)
 
        td->mmapfd = 1;
 
+       if (td->o.mem_type == MEM_MMAPHUGE) {
+               unsigned long mask = td->o.hugepage_size - 1;
+
+               flags |= MAP_HUGETLB;
+               total_mem = (total_mem + mask) & ~mask;
+       }
+
        if (td->o.mmapfile) {
                td->mmapfd = open(td->o.mmapfile, O_RDWR|O_CREAT, 0644);
 
index 9ee606037402a0d855093d88a51f017acc8f75fb..db02194ee1a2fd7836a4de0acf458837073ea45a 100644 (file)
--- a/options.c
+++ b/options.c
@@ -1614,6 +1614,23 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_RANDOM,
        },
+       {
+               .name   = "random_generator",
+               .type   = FIO_OPT_STR,
+               .off1   = td_var_offset(random_generator),
+               .help   = "Type of random number generator to use",
+               .def    = "tausworthe",
+               .posval = {
+                         { .ival = "tausworthe",
+                           .oval = FIO_RAND_GEN_TAUSWORTHE,
+                           .help = "Strong Tausworthe generator",
+                         },
+                         { .ival = "lfsr",
+                           .oval = FIO_RAND_GEN_LFSR,
+                           .help = "Variable length LFSR",
+                         },
+               },
+       },
        {
                .name   = "random_distribution",
                .type   = FIO_OPT_STR,
diff --git a/os/os-android.h b/os/os-android.h
new file mode 100644 (file)
index 0000000..3da3953
--- /dev/null
@@ -0,0 +1,234 @@
+#ifndef FIO_OS_ANDROID_H
+#define FIO_OS_ANDROID_H
+
+#define        FIO_OS  os_android
+
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <sys/syscall.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sched.h>
+#include <linux/unistd.h>
+#include <linux/major.h>
+#include <endian.h>
+
+#include "indirect.h"
+#include "binject.h"
+#include "../file.h"
+
+#define FIO_HAVE_DISK_UTIL
+#define FIO_HAVE_SPLICE
+#define FIO_HAVE_IOSCHED_SWITCH
+#define FIO_HAVE_ODIRECT
+#define FIO_HAVE_HUGETLB
+#define FIO_HAVE_BLKTRACE
+#define FIO_HAVE_STRSEP
+#define FIO_HAVE_POSIXAIO_FSYNC
+#define FIO_HAVE_PSHARED_MUTEX
+#define FIO_HAVE_CL_SIZE
+#define FIO_HAVE_FDATASYNC
+#define FIO_HAVE_FS_STAT
+#define FIO_HAVE_TRIM
+#define FIO_HAVE_CLOCK_MONOTONIC
+#define FIO_HAVE_GETTID
+#define FIO_USE_GENERIC_INIT_RANDOM_STATE
+#define FIO_HAVE_E4_ENG
+#define FIO_HAVE_BYTEORDER_FUNCS
+
+#define OS_MAP_ANON            MAP_ANONYMOUS
+
+#define posix_madvise   madvise
+#define POSIX_MADV_DONTNEED MADV_DONTNEED
+#define POSIX_MADV_SEQUENTIAL  MADV_SEQUENTIAL
+#define POSIX_MADV_RANDOM      MADV_RANDOM
+#ifdef MADV_REMOVE
+#define FIO_MADV_FREE  MADV_REMOVE
+#endif
+
+
+/*
+ * The Android NDK doesn't currently export <sys/shm.h>, so define the
+ * necessary stuff here.
+ */
+
+#include <linux/shm.h>
+#define SHM_HUGETLB    04000
+
+static inline int shmctl (int __shmid, int __cmd, struct shmid_ds *__buf)
+{
+       return syscall(__NR_shmctl, __shmid, __cmd, __buf);
+}
+
+static inline int shmget (key_t __key, size_t __size, int __shmflg)
+{
+       return syscall(__NR_shmget, __key, __size, __shmflg);
+}
+
+static inline void *shmat (int __shmid, const void *__shmaddr, int __shmflg)
+{
+       return (void *)syscall(__NR_shmat, __shmid, __shmaddr, __shmflg);
+}
+
+static inline int shmdt (const void *__shmaddr)
+{
+       return syscall(__NR_shmctl, __shmaddr);
+}
+
+
+/*
+ * Just check for SPLICE_F_MOVE, if that isn't there, assume the others
+ * aren't either.
+ */
+#ifndef SPLICE_F_MOVE
+#define SPLICE_F_MOVE  (0x01)  /* move pages instead of copying */
+#define SPLICE_F_NONBLOCK (0x02) /* don't block on the pipe splicing (but */
+                                /* we may still block on the fd we splice */
+                                /* from/to, of course */
+#define SPLICE_F_MORE  (0x04)  /* expect more data */
+#define SPLICE_F_GIFT   (0x08)  /* pages passed in are a gift */
+
+static inline int splice(int fdin, loff_t *off_in, int fdout, loff_t *off_out,
+                        size_t len, unsigned int flags)
+{
+       return syscall(__NR_sys_splice, fdin, off_in, fdout, off_out, len, flags);
+}
+
+static inline int tee(int fdin, int fdout, size_t len, unsigned int flags)
+{
+       return syscall(__NR_sys_tee, fdin, fdout, len, flags);
+}
+
+static inline int vmsplice(int fd, const struct iovec *iov,
+                          unsigned long nr_segs, unsigned int flags)
+{
+       return syscall(__NR_sys_vmsplice, fd, iov, nr_segs, flags);
+}
+#endif
+
+#define SPLICE_DEF_SIZE        (64*1024)
+
+#ifndef BLKGETSIZE64
+#define BLKGETSIZE64   _IOR(0x12,114,size_t)
+#endif
+
+#ifndef BLKFLSBUF
+#define BLKFLSBUF      _IO(0x12,97)
+#endif
+
+#ifndef BLKDISCARD
+#define BLKDISCARD     _IO(0x12,119)
+#endif
+
+static inline int blockdev_invalidate_cache(struct fio_file *f)
+{
+       return ioctl(f->fd, BLKFLSBUF);
+}
+
+static inline int blockdev_size(struct fio_file *f, unsigned long long *bytes)
+{
+       if (!ioctl(f->fd, BLKGETSIZE64, bytes))
+               return 0;
+
+       return errno;
+}
+
+static inline unsigned long long os_phys_mem(void)
+{
+       long pagesize, pages;
+
+       pagesize = sysconf(_SC_PAGESIZE);
+       pages = sysconf(_SC_PHYS_PAGES);
+       if (pages == -1 || pagesize == -1)
+               return 0;
+
+       return (unsigned long long) pages * (unsigned long long) pagesize;
+}
+
+typedef struct { unsigned short r[3]; } os_random_state_t;
+
+static inline void os_random_seed(unsigned long seed, os_random_state_t *rs)
+{
+       rs->r[0] = seed & 0xffff;
+       seed >>= 16;
+       rs->r[1] = seed & 0xffff;
+       seed >>= 16;
+       rs->r[2] = seed & 0xffff;
+       seed48(rs->r);
+}
+
+static inline long os_random_long(os_random_state_t *rs)
+{
+       return nrand48(rs->r);
+}
+
+#ifdef O_NOATIME
+#define FIO_O_NOATIME  O_NOATIME
+#else
+#define FIO_O_NOATIME  0
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define FIO_LITTLE_ENDIAN
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define FIO_BIG_ENDIAN
+#else
+#error "Unknown endianness"
+#endif
+
+#define fio_swap16(x)  __bswap_16(x)
+#define fio_swap32(x)  __bswap_32(x)
+#define fio_swap64(x)  __bswap_64(x)
+
+#define CACHE_LINE_FILE        \
+       "/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size"
+
+static inline int arch_cache_line_size(void)
+{
+       char size[32];
+       int fd, ret;
+
+       fd = open(CACHE_LINE_FILE, O_RDONLY);
+       if (fd < 0)
+               return -1;
+
+       ret = read(fd, size, sizeof(size));
+
+       close(fd);
+
+       if (ret <= 0)
+               return -1;
+       else
+               return atoi(size);
+}
+
+static inline unsigned long long get_fs_size(const char *path)
+{
+       unsigned long long ret;
+       struct statfs s;
+
+       if (statfs(path, &s) < 0)
+               return -1ULL;
+
+       ret = s.f_bsize;
+       ret *= (unsigned long long) s.f_bfree;
+       return ret;
+}
+
+static inline int os_trim(int fd, unsigned long long start,
+                         unsigned long long len)
+{
+       uint64_t range[2];
+
+       range[0] = start;
+       range[1] = len;
+
+       if (!ioctl(fd, BLKDISCARD, range))
+               return 0;
+
+       return errno;
+}
+
+#endif
index 081f5d6c632b57ae322ff93e8d39d5c985b14e9e..0d9829885b3be853f99de85e9431622c7c8a809a 100644 (file)
@@ -7,6 +7,7 @@
 #include <sys/uio.h>
 #include <sys/syscall.h>
 #include <sys/vfs.h>
+#include <sys/mman.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
 #define FIO_USE_GENERIC_INIT_RANDOM_STATE
 #define FIO_HAVE_E4_ENG
 
+#ifdef MAP_HUGETLB
+#define FIO_HAVE_MMAP_HUGE
+#endif
+
 /*
  * Can only enable this for newer glibcs, or the header and defines are
  * missing
index e7a544e1a0bc37c4766a2dc303da9701a1421efa..5efd7ac1e96481ec4ed0645c2c2bb88a66cbdf6d 100644 (file)
@@ -24,6 +24,7 @@
 #define FIO_USE_GENERIC_BDEV_SIZE
 #define FIO_USE_GENERIC_INIT_RANDOM_STATE
 #define FIO_HAVE_GETTID
+#define FIO_HAVE_FADVISE
 
 #define OS_MAP_ANON            MAP_ANON
 #define OS_RAND_MAX            2147483648UL
diff --git a/os/os.h b/os/os.h
index e2c188f1235cc5c0e85d280582ba0ed0a4b18483..8ca507a68cbbede9c2f5367e49174f9ec7a2a2b6 100644 (file)
--- a/os/os.h
+++ b/os/os.h
@@ -17,11 +17,14 @@ enum {
        os_netbsd,
        os_solaris,
        os_windows,
+       os_android,
 
        os_nr,
 };
 
-#if defined(__linux__)
+#if defined(__ANDROID__)
+#include "os-android.h"
+#elif defined(__linux__)
 #include "os-linux.h"
 #elif defined(__FreeBSD__)
 #include "os-freebsd.h"
@@ -65,15 +68,11 @@ typedef struct aiocb os_aiocb_t;
 #define OS_MSG_DONTWAIT        MSG_DONTWAIT
 #endif
 
-#ifndef FIO_HAVE_FADVISE
-#define posix_fadvise(fd, off, len, advice)    (0)
-
 #ifndef POSIX_FADV_DONTNEED
 #define POSIX_FADV_DONTNEED    (0)
 #define POSIX_FADV_SEQUENTIAL  (0)
 #define POSIX_FADV_RANDOM      (0)
 #endif
-#endif /* FIO_HAVE_FADVISE */
 
 #ifndef FIO_HAVE_CPU_AFFINITY
 #define fio_setaffinity(pid, mask)     (0)
@@ -95,6 +94,7 @@ typedef unsigned long os_cpu_mask_t;
 
 #ifndef FIO_HAVE_HUGETLB
 #define SHM_HUGETLB                    0
+#define MAP_HUGETLB                    0
 #ifndef FIO_HUGE_PAGE
 #define FIO_HUGE_PAGE                  0
 #endif
@@ -104,6 +104,10 @@ typedef unsigned long os_cpu_mask_t;
 #endif
 #endif
 
+#ifndef FIO_HAVE_MMAP_HUGE
+#define MAP_HUGETLB                    0
+#endif
+
 #ifndef FIO_O_NOATIME
 #define FIO_O_NOATIME                  0
 #endif
@@ -170,6 +174,7 @@ static inline uint64_t fio_swap64(uint64_t val)
 }
 #endif
 
+#ifndef FIO_HAVE_BYTEORDER_FUNCS
 #ifdef FIO_LITTLE_ENDIAN
 #define __le16_to_cpu(x)               (x)
 #define __le32_to_cpu(x)               (x)
@@ -185,6 +190,7 @@ static inline uint64_t fio_swap64(uint64_t val)
 #define __cpu_to_le32(x)               fio_swap32(x)
 #define __cpu_to_le64(x)               fio_swap64(x)
 #endif
+#endif /* FIO_HAVE_BYTEORDER_FUNCS */
 
 #define le16_to_cpu(val) ({                    \
        uint16_t *__val = &(val);               \
index f3d6bc3f2f89ca58bbfecb56f3d092fa6c32565d..84f2a8624f726f3b171f943f09d61533cae3663b 100755 (executable)
@@ -14,7 +14,7 @@
                 <Component>\r
                     <File Source="..\..\examples\fsx" />\r
                 </Component>\r
-                <Component >\r
+                <Component>\r
                     <File Source="..\..\examples\iometer-file-access-server" />\r
                 </Component>\r
                 <Component>\r
                 <Component>\r
                   <File Source="..\..\examples\flow" />\r
                 </Component>\r
+                <Component>\r
+                  <File Source="..\..\examples\cpuio" />\r
+                </Component>\r
+                <Component>\r
+                  <File Source="..\..\examples\falloc" />\r
+                </Component>\r
+                <Component>\r
+                  <File Source="..\..\examples\fusion-aw-sync.ini" />\r
+                </Component>\r
+                <Component>\r
+                  <File Source="..\..\examples\ssd-steadystate.fio" />\r
+                </Component>\r
+                <Component>\r
+                  <File Source="..\..\examples\zipf" />\r
+                </Component>\r
         </DirectoryRef>\r
     </Fragment>\r
     <Fragment>\r
             <ComponentRef Id="tiobench_example" />\r
             <ComponentRef Id="null" />\r
             <ComponentRef Id="flow" />\r
+            <ComponentRef Id="cpuio" />\r
+            <ComponentRef Id="falloc" />\r
+            <ComponentRef Id="fusion_aw_sync.ini" />\r
+            <ComponentRef Id="ssd_steadystate.fio" />\r
+            <ComponentRef Id="zipf" />\r
         </ComponentGroup>\r
     </Fragment>\r
-</Wix>
\ No newline at end of file
+</Wix>\r
index e02347e4b4c0c50da9671c0c3bc00fe659100102..86098b0c8d14db213a558f24d87aa5e884328905 100755 (executable)
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="utf-8"?>\r
 <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">\r
-       \r
+\r
        <?if $(env.FIO_ARCH) = x86 ?>\r
                <?define ProgramDirectory = ProgramFilesFolder ?>\r
        <?else?>\r
                <?define ProgramDirectory = ProgramFiles64Folder ?>\r
        <?endif?>\r
 \r
-       <Product Id="2BA394F9-0D9E-4597-BB9D-6B18097D64BB"\r
+    <Product Id="C3DC8A4F-1191-412F-8287-ACB6BA798F6A"\r
          Codepage="1252" Language="1033"\r
          Manufacturer="fio" Name="fio"\r
-         UpgradeCode="2338A332-5511-43cf-b9BD-5C60496CCFCC" Version="2.0.10">\r
-               <Package \r
+         UpgradeCode="2338A332-5511-43cf-b9BD-5C60496CCFCC" Version="2.0.11">\r
+               <Package\r
                  Comments="Contact: Your local administrator"\r
                  Description="Flexible IO Tester"\r
                  InstallerVersion="200" Keywords="Installer,MSI,Database"\r
@@ -57,7 +57,7 @@
                <ComponentRef Id="COPYING"/>\r
                <ComponentGroupRef Id="examples"/>\r
        </Feature>\r
-               \r
+\r
        <Property Id="ARPURLINFOABOUT" Value="http://git.kernel.dk/?p=fio.git" />\r
        <Property Id='ARPCONTACT'>fio@vger.kernel.org</Property>\r
        <Property Id='ARPHELPLINK'>http://www.spinics.net/lists/fio/</Property>\r
diff --git a/parse.c b/parse.c
index ffe2dc0feb28aef5dc6560a2f894a5915b202f9f..92adbe58c135370725cf2172ffbf37f6be8250b6 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -360,7 +360,7 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data,
        long long ull, *ullp;
        long ul1, ul2;
        double uf;
-       char **cp;
+       char **cp = NULL;
        int ret = 0, is_time = 0;
        const struct value_pair *vp;
        struct value_pair posval[PARSE_MAX_VP];
@@ -535,8 +535,6 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data,
                                cp = td_var(data, o->off1);
 
                        *cp = strdup(ptr);
-               } else {
-                       cp = NULL;
                }
 
                if (fn)
index 74f14facd6c6d0115bea1af3dc0c328fda1fdfd7..6a80dec2c7b7479cff92d24c47d2a0d9ac8fa691 100644 (file)
--- a/profile.c
+++ b/profile.c
@@ -93,8 +93,10 @@ void profile_add_hooks(struct thread_data *td)
        if (!ops)
                return;
 
-       if (ops->io_ops)
+       if (ops->io_ops) {
                td->prof_io_ops = *ops->io_ops;
+               td->flags |= TD_F_PROFILE_OPS;
+       }
 }
 
 int profile_td_init(struct thread_data *td)
diff --git a/t/axmap.c b/t/axmap.c
new file mode 100644 (file)
index 0000000..1f8c3e9
--- /dev/null
+++ b/t/axmap.c
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "../lib/lfsr.h"
+
+struct axmap;
+void axmap_set(struct axmap *, uint64_t);
+struct axmap *axmap_new(uint64_t size);
+
+void *smalloc(size_t size)
+{
+       return malloc(size);
+}
+
+void sfree(void *ptr)
+{
+       free(ptr);
+}
+
+int main(int argc, char *argv[])
+{
+       struct fio_lfsr lfsr;
+       size_t size = (1UL << 28) - 200;
+       struct axmap *map;
+
+       if (argc > 1)
+               size = strtoul(argv[1], NULL, 10);
+
+       printf("Using %llu entries\n", (unsigned long long) size);
+
+       lfsr_init(&lfsr, size);
+       map = axmap_new(size);
+
+       while (size--) {
+               uint64_t val;
+
+               lfsr_next(&lfsr, &val);
+               axmap_set(map, val);
+       }
+
+       return 0;
+}
index 3cc93e6d7f080624a3749df162f7aaefc50908ef..c5f098c4c606eceb26072048fa398cfb31bfedda 100644 (file)
@@ -78,13 +78,29 @@ static struct node *hash_insert(struct node *n, unsigned long long val)
        return n;
 }
 
+static void usage(void)
+{
+       printf("genzipf: test zipf/pareto values for fio input\n");
+       printf("\t-h\tThis help screen\n");
+       printf("\t-p\tGenerate size of data set that are hit by this percentage\n");
+       printf("\t-t\tDistribution type (zipf or pareto)\n");
+       printf("\t-i\tDistribution algorithm input (zipf theta or pareto power)\n");
+       printf("\t-b\tBlock size of a given range (in bytes)\n");
+       printf("\t-g\tSize of data set (in gigabytes)\n");
+       printf("\t-o\tNumber of output columns\n");
+       printf("\t-c\tOutput ranges in CSV format\n");
+}
+
 static int parse_options(int argc, char *argv[])
 {
-       const char *optstring = "t:g:i:o:b:p:c";
+       const char *optstring = "t:g:i:o:b:p:ch";
        int c, dist_val_set = 0;
 
        while ((c = getopt(argc, argv, optstring)) != -1) {
                switch (c) {
+               case 'h':
+                       usage();
+                       return 1;
                case 'p':
                        percentage = atof(optarg);
                        break;
index 9975af17d4f24b078f78bfea23c81475c5ba5cf6..5354473bce9c9cb2cdabe517f85f1e256429e781 100644 (file)
@@ -123,6 +123,8 @@ struct thread_options {
        fio_fp64_t zipf_theta;
        fio_fp64_t pareto_h;
 
+       unsigned int random_generator;
+
        unsigned int hugepage_size;
        unsigned int rw_min_bs;
        unsigned int thinktime;
@@ -326,6 +328,8 @@ struct thread_options_pack {
        fio_fp64_t zipf_theta;
        fio_fp64_t pareto_h;
 
+       uint32_t random_generator;
+
        uint32_t hugepage_size;
        uint32_t rw_min_bs;
        uint32_t thinktime;
index 01b56fde0b3c48529d70750be5c32616a393b82c..85fc448f8877f8f4cffe2c158cbeda24418b98ce 100644 (file)
--- a/verify.c
+++ b/verify.c
@@ -690,6 +690,7 @@ int verify_io_u(struct thread_data *td, struct io_u *io_u)
                        .hdr_num        = hdr_num,
                        .td             = td,
                };
+               unsigned int verify_type;
 
                if (ret && td->o.verify_fatal)
                        break;
@@ -708,7 +709,12 @@ int verify_io_u(struct thread_data *td, struct io_u *io_u)
                        return EILSEQ;
                }
 
-               switch (hdr->verify_type) {
+               if (td->o.verify != VERIFY_NONE)
+                       verify_type = td->o.verify;
+               else
+                       verify_type = hdr->verify_type;
+
+               switch (verify_type) {
                case VERIFY_MD5:
                        ret = verify_io_u_md5(hdr, &vc);
                        break;
@@ -747,6 +753,10 @@ int verify_io_u(struct thread_data *td, struct io_u *io_u)
                        log_err("Bad verify type %u\n", hdr->verify_type);
                        ret = EINVAL;
                }
+
+               if (ret && verify_type != hdr->verify_type)
+                       log_err("fio: verify type mismatch (%u media, %u given)\n",
+                                       hdr->verify_type, verify_type);
        }
 
 done: