- DEBUGFLAGS = -D_FORTIFY_SOURCE=2 -DFIO_INC_DEBUG
- CPPFLAGS= -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 $(DEBUGFLAGS)
- OPTFLAGS= -O3 -g -ffast-math $(EXTFLAGS)
- CFLAGS = -std=gnu99 -Wwrite-strings -Wall $(OPTFLAGS)
- LIBS = -lm -lz $(EXTLIBS)
- PROGS = fio
- SCRIPTS = fio_generate_plots
-
ifneq ($(wildcard config-host.mak),)
all:
include config-host.mak
include config-host.mak
endif
- SOURCE := gettime.c ioengines.c init.c stat.c log.c time.c filesetup.c \
+ DEBUGFLAGS = -D_FORTIFY_SOURCE=2 -DFIO_INC_DEBUG
+ CPPFLAGS= -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 $(DEBUGFLAGS)
+ OPTFLAGS= -O3 -g -ffast-math
+ CFLAGS = -std=gnu99 -Wwrite-strings -Wall $(OPTFLAGS) $(EXTFLAGS) $(BUILD_CFLAGS)
+ LIBS += -lm $(EXTLIBS)
+ PROGS = fio
+ SCRIPTS = fio_generate_plots
+
+ifdef CONFIG_GFIO
+ PROGS += gfio
+endif
+
+ SOURCE := gettime.c fio.c ioengines.c init.c stat.c log.c time.c filesetup.c \
eta.c verify.c memory.c io_u.c parse.c mutex.c options.c \
- rbtree.c smalloc.c filehash.c profile.c debug.c lib/rand.c \
+ lib/rbtree.c smalloc.c filehash.c profile.c debug.c lib/rand.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 \
- json.c lib/zipf.c lib/axmap.c lib/lfsr.c gettime-thread.c \
- helpers.c lib/flist_sort.c lib/hweight.c lib/getrusage.c \
- idletime.c
+ cconv.c lib/prio_tree.c json.c lib/zipf.c lib/axmap.c \
+ lib/lfsr.c gettime-thread.c helpers.c lib/flist_sort.c \
+ lib/hweight.c lib/getrusage.c idletime.c
ifdef CONFIG_64BIT_LLP64
CFLAGS += -DBITS_PER_LONG=32
endif
OBJS = $(SOURCE:.c=.o)
+
+FIO_OBJS = $(OBJS) fio.o
+GFIO_OBJS = $(OBJS) gfio.o graph.o tickmarks.o ghelpers.o goptions.o gerror.o \
+ gclient.o gcompat.o cairo_text_helpers.o printing.o
+
-include $(OBJS:.o=.d)
T_SMALLOC_OBJS = t/stest.o
init.o: FIO-VERSION-FILE init.c
$(QUIET_CC)$(CC) -o init.o $(CFLAGS) $(CPPFLAGS) -c init.c
+gcompat.o: gcompat.c gcompat.h
+ $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c gcompat.c
+
+goptions.o: goptions.c goptions.h
+ $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c goptions.c
+
+ghelpers.o: ghelpers.c ghelpers.h
+ $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c ghelpers.c
+
+gerror.o: gerror.c gerror.h
+ $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c gerror.c
+
+gclient.o: gclient.c gclient.h
+ $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c gclient.c
+
+gfio.o: gfio.c ghelpers.c
+ $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c gfio.c
+
+graph.o: graph.c graph.h
+ $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c graph.c
+
+cairo_text_helpers.o: cairo_text_helpers.c cairo_text_helpers.h
+ $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c cairo_text_helpers.c
+
+printing.o: printing.c printing.h
+ $(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c printing.c
+
t/stest: $(T_SMALLOC_OBJS)
$(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_SMALLOC_OBJS) $(LIBS) $(LDFLAGS)
t/ieee754: $(T_IEEE_OBJS)
$(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_IEEE_OBJS) $(LIBS) $(LDFLAGS)
+fio: $(FIO_OBJS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(FIO_OBJS) $(LIBS) $(LDFLAGS)
+
+gfio: $(GFIO_OBJS)
+ $(QUIET_LINK)$(CC) $(LIBS) -o gfio $(GFIO_OBJS) $(LIBS) $(GTK_LDFLAGS)
+
t/genzipf: $(T_ZIPF_OBJS)
$(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_ZIPF_OBJS) $(LIBS) $(LDFLAGS)
t/lfsr-test: $(T_LFSR_TEST_OBJS)
$(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_LFSR_TEST_OBJS) $(LIBS) $(LDFLAGS)
-fio: $(OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(LDFLAGS)
-
clean: FORCE
- -rm -f .depend $(OBJS) $(T_OBJS) $(PROGS) $(T_PROGS) core.* core FIO-VERSION-FILE config-host.mak config-host.h cscope.out *.d
+ -rm -f .depend $(GFIO_OBJS) $(OBJS) $(T_OBJS) $(PROGS) $(T_PROGS) core.* core gfio FIO-VERSION-FILE config-host.mak config-host.h cscope.out *.d
cscope:
@cscope -b -R
static char *cgroup_mnt;
static int exit_value;
static volatile int fio_abort;
+static unsigned int nr_process = 0;
+static unsigned int nr_thread = 0;
struct io_log *agg_io_log[DDIR_RWDIR_CNT];
int groupid = 0;
unsigned int thread_number = 0;
unsigned int stat_number = 0;
-unsigned int nr_process = 0;
-unsigned int nr_thread = 0;
int shm_id = 0;
int temp_stall_ts;
unsigned long done_secs = 0;
return 0;
}
+ static void check_update_rusage(struct thread_data *td)
+ {
+ if (td->update_rusage) {
+ td->update_rusage = 0;
+ update_rusage_stat(td);
+ fio_mutex_up(td->rusage_sem);
+ }
+ }
+
/*
* The main verify engine. Runs over the writes we previously submitted,
* reads the blocks back in, and checks the crc/md5 of the data.
break;
}
+ check_update_rusage(td);
+
if (td->error)
return;
int ret2, full;
update_tv_cache(td);
+ check_update_rusage(td);
if (runtime_exceeded(td, &td->tv_cache)) {
__update_tv_cache(td);
break;
}
+ check_update_rusage(td);
+
if (!td->error) {
min_events = td->cur_depth;
int ret2, full;
enum fio_ddir ddir;
+ check_update_rusage(td);
+
if (td->terminate || td->done)
break;
}
}
+ check_update_rusage(td);
+
if (td->trim_entries)
log_err("fio: %d trim entries leaked?\n", td->trim_entries);
char *p;
max_units = td->o.iodepth;
- max_bs = max(td->o.max_bs[DDIR_READ], td->o.max_bs[DDIR_WRITE]);
- max_bs = max(td->o.max_bs[DDIR_TRIM], max_bs);
+ max_bs = td_max_bs(td);
min_write = td->o.min_bs[DDIR_WRITE];
td->orig_buffer_size = (unsigned long long) max_bs
* (unsigned long long) max_units;
* are done.
*/
diff = td->o.size - ddir_rw_sum(td->io_bytes);
- if (diff < td->o.rw_min_bs)
+ if (diff < td_max_bs(td))
return 0;
return 1;
{
unsigned long long elapsed;
struct thread_data *td = data;
+ struct thread_options *o = &td->o;
pthread_condattr_t attr;
int clear_state;
+ int ret;
- if (!td->o.use_thread) {
+ if (!o->use_thread) {
setsid();
td->pid = getpid();
} else
dprint(FD_PROCESS, "jobs pid=%d started\n", (int) td->pid);
+ if (is_backend)
+ fio_server_send_start(td);
+
INIT_FLIST_HEAD(&td->io_u_freelist);
INIT_FLIST_HEAD(&td->io_u_busylist);
INIT_FLIST_HEAD(&td->io_u_requeues);
* eating a file descriptor
*/
fio_mutex_remove(td->mutex);
+ td->mutex = NULL;
/*
* A new gid requires privilege, so we need to do this before setting
* the uid.
*/
- if (td->o.gid != -1U && setgid(td->o.gid)) {
+ if (o->gid != -1U && setgid(o->gid)) {
td_verror(td, errno, "setgid");
goto err;
}
- if (td->o.uid != -1U && setuid(td->o.uid)) {
+ if (o->uid != -1U && setuid(o->uid)) {
td_verror(td, errno, "setuid");
goto err;
}
* If we have a gettimeofday() thread, make sure we exclude that
* thread from this job
*/
- if (td->o.gtod_cpu)
- fio_cpu_clear(&td->o.cpumask, td->o.gtod_cpu);
+ if (o->gtod_cpu)
+ fio_cpu_clear(&o->cpumask, o->gtod_cpu);
/*
* Set affinity first, in case it has an impact on the memory
* allocations.
*/
- if (td->o.cpumask_set && fio_setaffinity(td->pid, td->o.cpumask) == -1) {
- td_verror(td, errno, "cpu_set_affinity");
- goto err;
+ if (o->cpumask_set) {
+ ret = fio_setaffinity(td->pid, o->cpumask);
+ if (ret == -1) {
+ td_verror(td, errno, "cpu_set_affinity");
+ goto err;
+ }
}
#ifdef CONFIG_LIBNUMA
if (init_io_u(td))
goto err;
- if (td->o.verify_async && verify_async_init(td))
+ if (o->verify_async && verify_async_init(td))
goto err;
- if (td->ioprio_set) {
- if (ioprio_set(IOPRIO_WHO_PROCESS, 0, td->ioprio) == -1) {
+ if (o->ioprio) {
+ ret = ioprio_set(IOPRIO_WHO_PROCESS, 0, o->ioprio_class, o->ioprio);
+ if (ret == -1) {
td_verror(td, errno, "ioprio_set");
goto err;
}
goto err;
errno = 0;
- if (nice(td->o.nice) == -1 && errno != 0) {
+ if (nice(o->nice) == -1 && errno != 0) {
td_verror(td, errno, "nice");
goto err;
}
- if (td->o.ioscheduler && switch_ioscheduler(td))
+ if (o->ioscheduler && switch_ioscheduler(td))
goto err;
- if (!td->o.create_serialize && setup_files(td))
+ if (!o->create_serialize && setup_files(td))
goto err;
if (td_io_init(td))
if (init_random_map(td))
goto err;
- if (td->o.exec_prerun) {
- if (exec_string(td->o.exec_prerun))
- goto err;
- }
+ if (o->exec_prerun && exec_string(o->exec_prerun))
+ goto err;
- if (td->o.pre_read) {
+ if (o->pre_read) {
if (pre_read_files(td) < 0)
goto err;
}
+ fio_verify_init(td);
+
fio_gettime(&td->epoch, NULL);
fio_getrusage(&td->ru_start);
clear_state = 0;
td->ts.io_bytes[DDIR_WRITE] = td->io_bytes[DDIR_WRITE];
td->ts.io_bytes[DDIR_TRIM] = td->io_bytes[DDIR_TRIM];
+ fio_unpin_memory(td);
+
fio_mutex_down(writeout_mutex);
if (td->bw_log) {
if (td->o.bw_log_file) {
close_ioengine(td);
cgroup_shutdown(td, &cgroup_mnt);
- if (td->o.cpumask_set) {
- int ret = fio_cpuset_exit(&td->o.cpumask);
+ if (o->cpumask_set) {
+ int ret = fio_cpuset_exit(&o->cpumask);
td_verror(td, ret, "fio_cpuset_exit");
}
if (td->o.write_iolog_file)
write_iolog_close(td);
+ fio_mutex_remove(td->rusage_sem);
+ td->rusage_sem = NULL;
+
td_set_runstate(td, TD_EXITED);
return (void *) (uintptr_t) td->error;
}
unsigned long spent;
unsigned int i, todo, nr_running, m_rate, t_rate, nr_started;
- if (fio_pin_memory())
- return;
-
if (fio_gtod_offload && fio_start_gtod_thread())
return;
set_sig_handlers();
+ nr_thread = nr_process = 0;
+ for_each_td(td, i) {
+ if (td->o.use_thread)
+ nr_thread++;
+ else
+ nr_process++;
+ }
+
if (output_format == FIO_OUTPUT_NORMAL) {
log_info("Starting ");
if (nr_thread)
init_disk_util(td);
+ td->rusage_sem = fio_mutex_init(FIO_MUTEX_LOCKED);
+ td->update_rusage = 0;
+
/*
* Set state to created. Thread will transition
* to TD_INITIALIZED when it's done setting up.
reap_threads(&nr_running, &t_rate, &m_rate);
- if (todo) {
- if (is_backend)
- fio_server_idle_loop();
- else
- usleep(100000);
- }
+ if (todo)
+ usleep(100000);
}
while (nr_running) {
reap_threads(&nr_running, &t_rate, &m_rate);
-
- if (is_backend)
- fio_server_idle_loop();
- else
- usleep(10000);
+ usleep(10000);
}
fio_idle_prof_stop();
update_io_ticks();
- fio_unpin_memory();
}
void wait_for_disk_thread_exit(void)
return 0;
if (write_bw_log) {
- setup_log(&agg_io_log[DDIR_READ], 0);
- setup_log(&agg_io_log[DDIR_WRITE], 0);
- setup_log(&agg_io_log[DDIR_TRIM], 0);
+ setup_log(&agg_io_log[DDIR_READ], 0, IO_LOG_TYPE_BW);
+ setup_log(&agg_io_log[DDIR_WRITE], 0, IO_LOG_TYPE_BW);
+ setup_log(&agg_io_log[DDIR_TRIM], 0, IO_LOG_TYPE_BW);
}
startup_mutex = fio_mutex_init(FIO_MUTEX_LOCKED);
}
# Default CFLAGS
- CFLAGS="-D_GNU_SOURCE"
- EXTFLAGS="-include config-host.h"
+ CFLAGS="-D_GNU_SOURCE -include config-host.h"
+ BUILD_CFLAGS=""
# Print a helpful header at the top of config.log
echo "# FIO configure log $(date)" >> config.log
cross_prefix=${cross_prefix-${CROSS_COMPILE}}
cc="${CC-${cross_prefix}gcc}"
+# default options
show_help="no"
exit_val=0
+gfio="no"
# parse options
for opt do
;;
--build-32bit-win=*) build_32bit_win="$optarg"
;;
- --help)
- show_help="yes"
+ --enable-gfio)
+ gfio="yes"
;;
+ --help)
+ show_help="yes"
+ ;;
*)
echo "Bad option $opt"
show_help="yes"
echo "--cc= Specify compiler to use"
echo "--extra-cflags= Specify extra CFLAGS to pass to compiler"
echo "--build-32bit-win= Specify yes for a 32-bit build on Windows"
+ echo "--enable-gfio Enable building of gtk gfio"
exit $exit_val
fi
output_sym "CONFIG_SCHED_IDLE"
output_sym "CONFIG_TCP_NODELAY"
echo "CC=$CC" >> $config_host_mak
- echo "EXTFLAGS=$CFLAGS -include config-host.h -D_GNU_SOURCE" >> $config_host_mak
+ echo "BUILD_CFLAGS=$CFLAGS -include config-host.h -D_GNU_SOURCE" >> $config_host_mak
exit 0
;;
esac
fi
echo "libnuma $libnuma"
+ ##########################################
+ # libnuma 2.x version API
+ if test "$libnuma" = "yes" ; then
+ libnuma_v2="no"
+ cat > $TMPC << EOF
+ #include <numa.h>
+ int main(int argc, char **argv)
+ {
+ struct bitmask *mask = numa_parse_nodestring(NULL);
+ return 0;
+ }
+ EOF
+ if compile_prog "" "" "libnuma api"; then
+ libnuma_v2="yes"
+ fi
+ echo "libnuma v2 $libnuma_v2"
+ fi
+
##########################################
# strsep() probe
strsep="no"
echo "__thread $tls_thread"
##########################################
+# Whether or not __thread is supported for TLS
+if test "$gfio" = "yes" ; then
+ cat > $TMPC << EOF
+#include <glib.h>
+#include <cairo.h>
+#include <gtk/gtk.h>
+int main(void)
+{
+ gdk_threads_enter();
+ gdk_threads_leave();
+
+ printf("%d", GTK_CHECK_VERSION(2, 18, 0));
+}
+EOF
+GTK_CFLAGS=$(pkg-config --cflags gtk+-2.0 gthread-2.0)
+if test "$?" != "0" ; then
+ echo "configure: gtk and gthread not found"
+ exit 1
+fi
+GTK_LIBS=$(pkg-config --libs gtk+-2.0 gthread-2.0)
+if test "$?" != "0" ; then
+ echo "configure: gtk and gthread not found"
+ exit 1
+fi
+if compile_prog "$GTK_CFLAGS" "$GTK_LIBS" "gfio" ; then
+ r=$($TMPE)
+ if test "$r" != "0" ; then
+ gfio="yes"
+ LIBS="$LIBS $GTK_LIBS"
+ CFLAGS="$CFLAGS $GTK_CFLAGS"
+ else
+ echo "GTK found, but need version 2.18 or higher"
+ gfio="no"
+ fi
+else
+ echo "Please install gtk and gdk libraries"
+ gfio="no"
+fi
+fi
+
+echo "gfio $gfio"
+
# Check whether we have getrusage(RUSAGE_THREAD)
rusage_thread="no"
cat > $TMPC << EOF
if test "$sfaa" = "yes" ; then
output_sym "CONFIG_SFAA"
fi
- if test "$libverbs" = "yes" -o "rdmacm" = "yes" ; then
+ if test "$libverbs" = "yes" -a "rdmacm" = "yes" ; then
output_sym "CONFIG_RDMA"
fi
if test "$clock_gettime" = "yes" ; then
if test "$fusion_aw" = "yes" ; then
output_sym "CONFIG_FUSION_AW"
fi
- if test "$libnuma" = "yes" ; then
+ if test "$libnuma_v2" = "yes" ; then
output_sym "CONFIG_LIBNUMA"
fi
if test "$solaris_aio" = "yes" ; then
if test "$rusage_thread" = "yes" ; then
output_sym "CONFIG_RUSAGE_THREAD"
fi
+if test "$gfio" = "yes" ; then
+ echo "CONFIG_GFIO=y" >> $config_host_mak
+fi
if test "$sched_idle" = "yes" ; then
output_sym "CONFIG_SCHED_IDLE"
fi
fi
echo "LIBS+=$LIBS" >> $config_host_mak
+echo "CFLAGS+=$CFLAGS" >> $config_host_mak
echo "CC=$cc" >> $config_host_mak
- echo "EXTFLAGS=$EXTFLAGS $CFLAGS" >> $config_host_mak
+ echo "BUILD_CFLAGS=$BUILD_CFLAGS $CFLAGS" >> $config_host_mak
struct thread_data;
#include "compiler/compiler.h"
+#include "thread_options.h"
#include "flist.h"
#include "fifo.h"
-#include "rbtree.h"
+#include "lib/rbtree.h"
#include "arch/arch.h"
#include "os/os.h"
#include "mutex.h"
#include "gettime.h"
#include "lib/getopt.h"
#include "lib/rand.h"
+#include "client.h"
#include "server.h"
#include "stat.h"
#include "flow.h"
#define MPOL_LOCAL MPOL_MAX
#endif
-/*
- * What type of allocation to use for io buffers
- */
-enum fio_memtype {
- MEM_MALLOC = 0, /* ordinary malloc */
- MEM_SHM, /* use shared memory segments */
- MEM_SHMHUGE, /* use shared memory segments with huge pages */
- MEM_MMAP, /* use anonynomous mmap */
- MEM_MMAPHUGE, /* memory mapped huge file */
-};
-
/*
* offset generator types
*/
RW_SEQ_IDENT,
};
-/*
- * What type of errors to continue on when continue_on_error is used
- */
-enum error_type_bit {
- ERROR_TYPE_READ_BIT = 0,
- ERROR_TYPE_WRITE_BIT = 1,
- ERROR_TYPE_VERIFY_BIT = 2,
- ERROR_TYPE_CNT = 3,
-};
-
-enum error_type {
- ERROR_TYPE_NONE = 0,
- ERROR_TYPE_READ = 1 << ERROR_TYPE_READ_BIT,
- ERROR_TYPE_WRITE = 1 << ERROR_TYPE_WRITE_BIT,
- ERROR_TYPE_VERIFY = 1 << ERROR_TYPE_VERIFY_BIT,
- ERROR_TYPE_ANY = 0xffff,
-};
-
-struct bssplit {
- unsigned int bs;
- unsigned char perc;
-};
-
-struct thread_options {
- int pad;
- char *description;
- char *name;
- char *directory;
- char *filename;
- char *opendir;
- char *ioengine;
- enum td_ddir td_ddir;
- unsigned int rw_seq;
- unsigned int kb_base;
- unsigned int ddir_seq_nr;
- long ddir_seq_add;
- unsigned int iodepth;
- unsigned int iodepth_low;
- unsigned int iodepth_batch;
- unsigned int iodepth_batch_complete;
-
- unsigned long long size;
- unsigned int size_percent;
- unsigned int fill_device;
- unsigned long long file_size_low;
- unsigned long long file_size_high;
- unsigned long long start_offset;
-
- unsigned int bs[DDIR_RWDIR_CNT];
- unsigned int ba[DDIR_RWDIR_CNT];
- unsigned int min_bs[DDIR_RWDIR_CNT];
- unsigned int max_bs[DDIR_RWDIR_CNT];
- struct bssplit *bssplit[DDIR_RWDIR_CNT];
- unsigned int bssplit_nr[DDIR_RWDIR_CNT];
-
- int *ignore_error[ERROR_TYPE_CNT];
- unsigned int ignore_error_nr[ERROR_TYPE_CNT];
- unsigned int error_dump;
-
- unsigned int nr_files;
- unsigned int open_files;
- enum file_lock_mode file_lock_mode;
-
- unsigned int odirect;
- unsigned int invalidate_cache;
- unsigned int create_serialize;
- unsigned int create_fsync;
- unsigned int create_on_open;
- unsigned int create_only;
- unsigned int end_fsync;
- unsigned int pre_read;
- unsigned int sync_io;
- unsigned int verify;
- unsigned int do_verify;
- unsigned int verifysort;
- unsigned int verifysort_nr;
- unsigned int verify_interval;
- unsigned int verify_offset;
- char verify_pattern[MAX_PATTERN_SIZE];
- unsigned int verify_pattern_bytes;
- unsigned int verify_fatal;
- unsigned int verify_dump;
- unsigned int verify_async;
- unsigned long long verify_backlog;
- unsigned int verify_batch;
- unsigned int experimental_verify;
- unsigned int use_thread;
- unsigned int unlink;
- unsigned int do_disk_util;
- unsigned int override_sync;
- unsigned int rand_repeatable;
- unsigned int use_os_rand;
- unsigned int write_lat_log;
- unsigned int write_bw_log;
- unsigned int write_iops_log;
- unsigned int log_avg_msec;
- unsigned int norandommap;
- unsigned int softrandommap;
- unsigned int bs_unaligned;
- unsigned int fsync_on_close;
-
- unsigned int random_distribution;
- double zipf_theta;
- double pareto_h;
-
- unsigned int random_generator;
-
- unsigned int hugepage_size;
- unsigned int rw_min_bs;
- unsigned int thinktime;
- unsigned int thinktime_spin;
- unsigned int thinktime_blocks;
- unsigned int fsync_blocks;
- unsigned int fdatasync_blocks;
- unsigned int barrier_blocks;
- unsigned long long start_delay;
- unsigned long long timeout;
- unsigned long long ramp_time;
- unsigned int overwrite;
- unsigned int bw_avg_time;
- unsigned int iops_avg_time;
- unsigned int loops;
- unsigned long long zone_range;
- unsigned long long zone_size;
- unsigned long long zone_skip;
- enum fio_memtype mem_type;
- unsigned int mem_align;
-
- unsigned int max_latency;
-
- unsigned int stonewall;
- unsigned int new_group;
- unsigned int numjobs;
- os_cpu_mask_t cpumask;
- unsigned int cpumask_set;
- os_cpu_mask_t verify_cpumask;
- unsigned int verify_cpumask_set;
-#ifdef CONFIG_LIBNUMA
- struct bitmask *numa_cpunodesmask;
- unsigned int numa_cpumask_set;
- unsigned short numa_mem_mode;
- unsigned int numa_mem_prefer_node;
- struct bitmask *numa_memnodesmask;
- unsigned int numa_memmask_set;
-#endif
- unsigned int iolog;
- unsigned int rwmixcycle;
- unsigned int rwmix[2];
- unsigned int nice;
- unsigned int file_service_type;
- unsigned int group_reporting;
- unsigned int fadvise_hint;
- enum fio_fallocate_mode fallocate_mode;
- unsigned int zero_buffers;
- unsigned int refill_buffers;
- unsigned int scramble_buffers;
- unsigned int compress_percentage;
- unsigned int compress_chunk;
- unsigned int time_based;
- unsigned int disable_lat;
- unsigned int disable_clat;
- unsigned int disable_slat;
- unsigned int disable_bw;
- unsigned int unified_rw_rep;
- unsigned int gtod_reduce;
- unsigned int gtod_cpu;
- unsigned int gtod_offload;
- enum fio_cs clocksource;
- unsigned int no_stall;
- unsigned int trim_percentage;
- unsigned int trim_batch;
- unsigned int trim_zero;
- unsigned long long trim_backlog;
- unsigned int clat_percentiles;
- unsigned int percentile_precision; /* digits after decimal for percentiles */
- fio_fp64_t percentile_list[FIO_IO_U_LIST_MAX_LEN];
-
- char *read_iolog_file;
- char *write_iolog_file;
- char *bw_log_file;
- char *lat_log_file;
- char *iops_log_file;
- char *replay_redirect;
-
- /*
- * Pre-run and post-run shell
- */
- char *exec_prerun;
- char *exec_postrun;
-
- unsigned int rate[DDIR_RWDIR_CNT];
- unsigned int ratemin[DDIR_RWDIR_CNT];
- unsigned int ratecycle;
- unsigned int rate_iops[DDIR_RWDIR_CNT];
- unsigned int rate_iops_min[DDIR_RWDIR_CNT];
-
- char *ioscheduler;
-
- /*
- * CPU "io" cycle burner
- */
- unsigned int cpuload;
- unsigned int cpucycle;
-
- /*
- * I/O Error handling
- */
- enum error_type continue_on_error;
-
- /*
- * Benchmark profile type
- */
- char *profile;
-
- /*
- * blkio cgroup support
- */
- char *cgroup;
- unsigned int cgroup_weight;
- unsigned int cgroup_nodelete;
-
- unsigned int uid;
- unsigned int gid;
-
- int flow_id;
- int flow;
- int flow_watermark;
- unsigned int flow_sleep;
-
- unsigned long long offset_increment;
-
- unsigned int sync_file_range;
-};
-
enum {
TD_F_VER_BACKLOG = 1,
TD_F_TRIM_BACKLOG = 2,
void *eo;
char verror[FIO_VERROR_SIZE];
pthread_t thread;
- int thread_number;
- int groupid;
+ unsigned int thread_number;
+ unsigned int groupid;
struct thread_stat ts;
+ int client_type;
+
struct io_log *slat_log;
struct io_log *clat_log;
struct io_log *lat_log;
uint64_t stat_io_blocks[DDIR_RWDIR_CNT];
struct timeval iops_sample_time;
+ volatile int update_rusage;
+ struct fio_mutex *rusage_sem;
struct rusage ru_start;
struct rusage ru_end;
size_t orig_buffer_size;
volatile int terminate;
volatile int runstate;
- unsigned int ioprio;
- unsigned int ioprio_set;
unsigned int last_was_sync;
enum fio_ddir last_ddir;
- char *mmapfile;
int mmapfd;
void *iolog_buf;
*/
struct prof_io_ops prof_io_ops;
void *prof_data;
+
+ void *pinned_mem;
};
/*
extern int exitall_on_terminate;
extern unsigned int thread_number;
extern unsigned int stat_number;
-extern unsigned int nr_process, nr_thread;
extern int shm_id;
extern int groupid;
extern int output_format;
extern int temp_stall_ts;
-extern unsigned long long mlock_size;
extern uintptr_t page_mask, page_size;
extern int read_only;
extern int eta_print;
/*
* Init/option functions
*/
+extern int __must_check fio_init_options(void);
extern int __must_check parse_options(int, char **);
-extern int parse_jobs_ini(char *, int, int);
-extern int parse_cmd_line(int, char **);
+extern int parse_jobs_ini(char *, int, int, int);
+extern int parse_cmd_line(int, char **, int);
extern int fio_backend(void);
extern void reset_fio_state(void);
extern void clear_io_state(struct thread_data *);
extern void fio_options_mem_dupe(struct thread_data *);
extern void options_mem_dupe(void *data, struct fio_option *options);
extern void td_fill_rand_seeds(struct thread_data *);
-extern void add_job_opts(const char **);
+extern void add_job_opts(const char **, int);
extern char *num2str(unsigned long, int, int, int);
extern int ioengine_load(struct thread_data *);
+extern unsigned long page_mask;
+extern unsigned long page_size;
+extern int initialize_fio(char *envp[]);
+
#define FIO_GETOPT_JOB 0x89000000
#define FIO_GETOPT_IOENGINE 0x98000000
#define FIO_NR_OPTIONS (FIO_MAX_OPTS + 128)
*/
extern void print_thread_status(void);
extern void print_status_init(int);
+extern char *fio_uint_to_kmg(unsigned int val);
/*
* Thread life cycle. Once a thread has a runstate beyond TD_INITIALIZED, it
/*
* Memory helpers
*/
-extern int __must_check fio_pin_memory(void);
-extern void fio_unpin_memory(void);
+extern int __must_check fio_pin_memory(struct thread_data *);
+extern void fio_unpin_memory(struct thread_data *);
extern int __must_check allocate_io_mem(struct thread_data *);
extern void free_io_mem(struct thread_data *);
+extern void free_threads_shm(void);
/*
* Reset stats after ramp time completes
return ret;
}
+ static inline unsigned int td_max_bs(struct thread_data *td)
+ {
+ unsigned int max_bs;
+
+ max_bs = max(td->o.max_bs[DDIR_READ], td->o.max_bs[DDIR_WRITE]);
+ return max(td->o.max_bs[DDIR_TRIM], max_bs);
+ }
+
static inline int is_power_of_2(unsigned int val)
{
return (val != 0 && ((val & (val - 1)) == 0));
extern const char *fio_get_arch_string(int);
extern const char *fio_get_os_string(int);
+#define ARRAY_SIZE(x) (sizeof((x)) / (sizeof((x)[0])))
+
enum {
FIO_OUTPUT_TERSE = 0,
FIO_OUTPUT_JSON,
out:
if (r >= 0) {
/*
- * Reflect that our submitted requests were retrieved with
+ * Reflect that our submitted requests were retrieved with
* whatever OS async calls are in the underlying engine.
*/
td->io_u_in_flight -= r;
if (!td->cur_depth || !td->io_u_queued)
return 0;
- io_u_mark_depth(td, td->io_u_queued);
+ io_u_mark_depth(td, td->io_u_queued);
if (td->io_ops->commit) {
ret = td->io_ops->commit(td);
if (ret)
td_verror(td, -ret, "io commit");
}
-
+
/*
* Reflect that events were submitted as async IO requests.
*/
fio_file_set_closing(f);
disk_util_dec(f->du);
- unlock_file_all(td, f);
+
+ if (td->o.file_lock_mode != FILE_LOCK_NONE)
+ unlock_file_all(td, f);
return put_file(td, f);
}
ret = os_trim(f->fd, io_u->offset, io_u->xfer_buflen);
if (!ret)
- return io_u->xfer_buflen;;
+ return io_u->xfer_buflen;
io_u->error = ret;
return 0;
#include "minmax.h"
#include "lib/ieee754.h"
-static struct fio_option *fio_options;
-extern unsigned int fio_get_kb_base(void *);
+static struct fio_option *__fio_options;
static int vp_cmp(const void *p1, const void *p2)
{
}
}
+ static int is_separator(char c)
+ {
+ switch (c) {
+ case ':':
+ case '-':
+ case ',':
+ case '/':
+ return 1;
+ default:
+ return 0;
+ }
+ }
+
static unsigned long long __get_mult_bytes(const char *p, void *data,
int *percent)
{
c = strdup(p);
- for (i = 0; i < strlen(c); i++)
+ for (i = 0; i < strlen(c); i++) {
c[i] = tolower(c[i]);
+ if (is_separator(c[i])) {
+ c[i] = '\0';
+ break;
+ }
+ }
- if (!strcmp("pib", c)) {
+ if (!strncmp("pib", c, 3)) {
pow = 5;
mult = 1000;
- } else if (!strcmp("tib", c)) {
+ } else if (!strncmp("tib", c, 3)) {
pow = 4;
mult = 1000;
- } else if (!strcmp("gib", c)) {
+ } else if (!strncmp("gib", c, 3)) {
pow = 3;
mult = 1000;
- } else if (!strcmp("mib", c)) {
+ } else if (!strncmp("mib", c, 3)) {
pow = 2;
mult = 1000;
- } else if (!strcmp("kib", c)) {
+ } else if (!strncmp("kib", c, 3)) {
pow = 1;
mult = 1000;
- } else if (!strcmp("p", c) || !strcmp("pb", c))
+ } else if (!strncmp("p", c, 1) || !strncmp("pb", c, 2))
pow = 5;
- else if (!strcmp("t", c) || !strcmp("tb", c))
+ else if (!strncmp("t", c, 1) || !strncmp("tb", c, 2))
pow = 4;
- else if (!strcmp("g", c) || !strcmp("gb", c))
+ else if (!strncmp("g", c, 1) || !strncmp("gb", c, 2))
pow = 3;
- else if (!strcmp("m", c) || !strcmp("mb", c))
+ else if (!strncmp("m", c, 1) || !strncmp("mb", c, 2))
pow = 2;
- else if (!strcmp("k", c) || !strcmp("kb", c))
+ else if (!strncmp("k", c, 1) || !strncmp("kb", c, 2))
pow = 1;
- else if (!strcmp("%", c)) {
+ else if (!strncmp("%", c, 1)) {
*percent = 1;
free(c);
return ret;
return 0;
}
-static int check_str_bytes(const char *p, long long *val, void *data)
+int check_str_bytes(const char *p, long long *val, void *data)
{
return str_to_decimal(p, val, 1, data);
}
if (*(char **)p1) {
s = strdup(*((char **) p1));
- o = get_option(s, fio_options, &foo);
+ o = get_option(s, __fio_options, &foo);
if (o)
prio1 = o->prio;
free(s);
}
if (*(char **)p2) {
s = strdup(*((char **) p2));
- o = get_option(s, fio_options, &foo);
+ o = get_option(s, __fio_options, &foo);
if (o)
prio2 = o->prio;
free(s);
void sort_options(char **opts, struct fio_option *options, int num_opts)
{
- fio_options = options;
+ __fio_options = options;
qsort(opts, num_opts, sizeof(char *), opt_cmp);
- fio_options = NULL;
+ __fio_options = NULL;
}
int parse_cmd_option(const char *opt, const char *val,
return 1;
}
- if (!handle_option(*o, post, data)) {
+ if (!handle_option(*o, post, data))
return 0;
- }
log_err("fio: failed parsing %s\n", input);
return 1;
(o->roff1 || o->roff2 || o->roff3 || o->roff4))) {
log_err("Option %s: both cb and offset given\n", o->name);
}
+ if (!o->category) {
+ log_info("Options %s: no category defined. Setting to misc\n", o->name);
+ o->category = FIO_OPT_C_GENERAL;
+ }
}
/*
dprint(FD_PARSE, "init options\n");
- for (o = &options[0]; o->name; o++)
+ for (o = &options[0]; o->name; o++) {
option_init(o);
+ if (o->inverse)
+ o->inv_opt = find_option(options, o->inverse);
+ }
}
void options_free(struct fio_option *options, void *data)
/*
* Discard the error bits and apply the mask to find the
- * index for the buckets in the group
+ * index for the buckets in the group
*/
offset = (FIO_IO_U_PLAT_VAL - 1) & (val >> error_bits);
/* Make sure the index does not exceed (array size - 1) */
- idx = (base + offset) < (FIO_IO_U_PLAT_NR - 1)?
+ idx = (base + offset) < (FIO_IO_U_PLAT_NR - 1) ?
(base + offset) : (FIO_IO_U_PLAT_NR - 1);
return idx;
/* MSB <= (FIO_IO_U_PLAT_BITS-1), cannot be rounded off. Use
* all bits of the sample as index */
- if (idx < (FIO_IO_U_PLAT_VAL << 1) )
+ if (idx < (FIO_IO_U_PLAT_VAL << 1))
return idx;
/* Find the group and compute the minimum value of that group */
- error_bits = (idx >> FIO_IO_U_PLAT_BITS) -1;
+ error_bits = (idx >> FIO_IO_U_PLAT_BITS) - 1;
base = 1 << (error_bits + FIO_IO_U_PLAT_BITS);
/* Find its bucket number of the group */
return cmp;
}
-static unsigned int calc_clat_percentiles(unsigned int *io_u_plat,
- unsigned long nr, fio_fp64_t *plist,
- unsigned int **output,
- unsigned int *maxv,
- unsigned int *minv)
+unsigned int calc_clat_percentiles(unsigned int *io_u_plat, unsigned long nr,
+ fio_fp64_t *plist, unsigned int **output,
+ unsigned int *maxv, unsigned int *minv)
{
unsigned long sum = 0;
unsigned int len, i, j = 0;
* isn't a worry. Also note that this does not work for NaN values.
*/
if (len > 1)
- qsort((void*)plist, len, sizeof(plist[0]), double_cmp);
+ qsort((void *)plist, len, sizeof(plist[0]), double_cmp);
/*
* Calculate bucket values, note down max and min values
free(ovals);
}
-static int calc_lat(struct io_stat *is, unsigned long *min, unsigned long *max,
- double *mean, double *dev)
+int calc_lat(struct io_stat *is, unsigned long *min, unsigned long *max,
+ double *mean, double *dev)
{
double n = is->samples;
}
}
-#define ts_total_io_u(ts) \
- ((ts)->total_io_u[DDIR_READ] + (ts)->total_io_u[DDIR_WRITE] +\
- (ts)->total_io_u[DDIR_TRIM])
-
-static void stat_calc_dist(unsigned int *map, unsigned long total,
- double *io_u_dist)
+void stat_calc_dist(unsigned int *map, unsigned long total, double *io_u_dist)
{
int i;
static void stat_calc_lat(struct thread_stat *ts, double *dst,
unsigned int *src, int nr)
{
- unsigned long total = ts_total_io_u(ts);
+ unsigned long total = ddir_rw_sum(ts->total_io_u);
int i;
/*
}
}
-static void stat_calc_lat_u(struct thread_stat *ts, double *io_u_lat)
+void stat_calc_lat_u(struct thread_stat *ts, double *io_u_lat)
{
stat_calc_lat(ts, io_u_lat, ts->io_u_lat_u, FIO_IO_U_LAT_U_NR);
}
-static void stat_calc_lat_m(struct thread_stat *ts, double *io_u_lat)
+void stat_calc_lat_m(struct thread_stat *ts, double *io_u_lat)
{
stat_calc_lat(ts, io_u_lat, ts->io_u_lat_m, FIO_IO_U_LAT_M_NR);
}
-static int usec_to_msec(unsigned long *min, unsigned long *max, double *mean,
- double *dev)
+static void display_lat(const char *name, unsigned long min, unsigned long max,
+ double mean, double dev)
{
- if (*min > 1000 && *max > 1000 && *mean > 1000.0 && *dev > 1000.0) {
- *min /= 1000;
- *max /= 1000;
- *mean /= 1000.0;
- *dev /= 1000.0;
- return 0;
- }
+ const char *base = "(usec)";
+ char *minp, *maxp;
- return 1;
+ if (!usec_to_msec(&min, &max, &mean, &dev))
+ base = "(msec)";
+
+ minp = num2str(min, 6, 1, 0);
+ maxp = num2str(max, 6, 1, 0);
+
+ log_info(" %s %s: min=%s, max=%s, avg=%5.02f,"
+ " stdev=%5.02f\n", name, base, minp, maxp, mean, dev);
+
+ free(minp);
+ free(maxp);
}
static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts,
free(bw_p);
free(iops_p);
- if (calc_lat(&ts->slat_stat[ddir], &min, &max, &mean, &dev)) {
- const char *base = "(usec)";
- char *minp, *maxp;
-
- if (!usec_to_msec(&min, &max, &mean, &dev))
- base = "(msec)";
-
- minp = num2str(min, 6, 1, 0);
- maxp = num2str(max, 6, 1, 0);
-
- log_info(" slat %s: min=%s, max=%s, avg=%5.02f,"
- " stdev=%5.02f\n", base, minp, maxp, mean, dev);
-
- free(minp);
- free(maxp);
- }
- if (calc_lat(&ts->clat_stat[ddir], &min, &max, &mean, &dev)) {
- const char *base = "(usec)";
- char *minp, *maxp;
-
- if (!usec_to_msec(&min, &max, &mean, &dev))
- base = "(msec)";
-
- minp = num2str(min, 6, 1, 0);
- maxp = num2str(max, 6, 1, 0);
-
- log_info(" clat %s: min=%s, max=%s, avg=%5.02f,"
- " stdev=%5.02f\n", base, minp, maxp, mean, dev);
-
- free(minp);
- free(maxp);
- }
- if (calc_lat(&ts->lat_stat[ddir], &min, &max, &mean, &dev)) {
- const char *base = "(usec)";
- char *minp, *maxp;
-
- if (!usec_to_msec(&min, &max, &mean, &dev))
- base = "(msec)";
-
- minp = num2str(min, 6, 1, 0);
- maxp = num2str(max, 6, 1, 0);
-
- log_info(" lat %s: min=%s, max=%s, avg=%5.02f,"
- " stdev=%5.02f\n", base, minp, maxp, mean, dev);
+ if (calc_lat(&ts->slat_stat[ddir], &min, &max, &mean, &dev))
+ display_lat("slat", min, max, mean, dev);
+ if (calc_lat(&ts->clat_stat[ddir], &min, &max, &mean, &dev))
+ display_lat("clat", min, max, mean, dev);
+ if (calc_lat(&ts->lat_stat[ddir], &min, &max, &mean, &dev))
+ display_lat(" lat", min, max, mean, dev);
- free(minp);
- free(maxp);
- }
if (ts->clat_percentiles) {
show_clat_percentiles(ts->io_u_plat[ddir],
ts->clat_stat[ddir].samples,
show_lat(io_u_lat_m, FIO_IO_U_LAT_M_NR, ranges, "msec");
}
-static void show_latencies(double *io_u_lat_u, double *io_u_lat_m)
+static void show_latencies(struct thread_stat *ts)
{
+ double io_u_lat_u[FIO_IO_U_LAT_U_NR];
+ double io_u_lat_m[FIO_IO_U_LAT_M_NR];
+
+ stat_calc_lat_u(ts, io_u_lat_u);
+ stat_calc_lat_m(ts, io_u_lat_m);
+
show_lat_u(io_u_lat_u);
show_lat_m(io_u_lat_m);
}
double usr_cpu, sys_cpu;
unsigned long runtime;
double io_u_dist[FIO_IO_U_MAP_NR];
- double io_u_lat_u[FIO_IO_U_LAT_U_NR];
- double io_u_lat_m[FIO_IO_U_LAT_M_NR];
time_t time_p;
char time_buf[64];
if (ts->io_bytes[DDIR_TRIM])
show_ddir_status(rs, ts, DDIR_TRIM);
- stat_calc_lat_u(ts, io_u_lat_u);
- stat_calc_lat_m(ts, io_u_lat_m);
- show_latencies(io_u_lat_u, io_u_lat_m);
+ show_latencies(ts);
runtime = ts->total_run_time;
if (runtime) {
log_info(" cpu : usr=%3.2f%%, sys=%3.2f%%, ctx=%lu, majf=%lu,"
" minf=%lu\n", usr_cpu, sys_cpu, ts->ctx, ts->majf, ts->minf);
- stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
+ stat_calc_dist(ts->io_u_map, ddir_rw_sum(ts->total_io_u), io_u_dist);
log_info(" IO depths : 1=%3.1f%%, 2=%3.1f%%, 4=%3.1f%%, 8=%3.1f%%,"
" 16=%3.1f%%, 32=%3.1f%%, >=64=%3.1f%%\n", io_u_dist[0],
io_u_dist[1], io_u_dist[2],
if (ovals)
free(ovals);
- if (!calc_lat(&ts->bw_stat[ddir], &min, &max, &mean, &dev)) {
+ if (calc_lat(&ts->bw_stat[ddir], &min, &max, &mean, &dev)) {
if (rs->agg[ddir]) {
p_of_agg = mean * 100 / (double) rs->agg[ddir];
if (p_of_agg > 100.0)
}
static void show_thread_status_terse_v2(struct thread_stat *ts,
- struct group_run_stats *rs)
+ struct group_run_stats *rs)
{
double io_u_dist[FIO_IO_U_MAP_NR];
double io_u_lat_u[FIO_IO_U_LAT_U_NR];
ts->minf);
/* Calc % distribution of IO depths, usecond, msecond latency */
- stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
+ stat_calc_dist(ts->io_u_map, ddir_rw_sum(ts->total_io_u), io_u_dist);
stat_calc_lat_u(ts, io_u_lat_u);
stat_calc_lat_m(ts, io_u_lat_m);
ts->minf);
/* Calc % distribution of IO depths, usecond, msecond latency */
- stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
+ stat_calc_dist(ts->io_u_map, ddir_rw_sum(ts->total_io_u), io_u_dist);
stat_calc_lat_u(ts, io_u_lat_u);
stat_calc_lat_m(ts, io_u_lat_m);
/* Calc % distribution of IO depths, usecond, msecond latency */
- stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
+ stat_calc_dist(ts->io_u_map, ddir_rw_sum(ts->total_io_u), io_u_dist);
stat_calc_lat_u(ts, io_u_lat_u);
stat_calc_lat_m(ts, io_u_lat_m);
else
memset(ts->description, 0, FIO_JOBNAME_SIZE);
+ /*
+ * If multiple entries in this group, this is
+ * the first member.
+ */
+ ts->thread_number = td->thread_number;
ts->groupid = td->groupid;
/*
if (td_trim(td) && td->io_bytes[DDIR_TRIM])
td->ts.runtime[DDIR_TRIM] += rt[i];
- update_rusage_stat(td);
+ td->update_rusage = 1;
td->ts.io_bytes[DDIR_READ] = td->io_bytes[DDIR_READ];
td->ts.io_bytes[DDIR_WRITE] = td->io_bytes[DDIR_WRITE];
td->ts.io_bytes[DDIR_TRIM] = td->io_bytes[DDIR_TRIM];
td->ts.total_run_time = mtime_since(&td->epoch, &tv);
}
+ for_each_td(td, i) {
+ if (td->rusage_sem) {
+ td->update_rusage = 1;
+ fio_mutex_down(td->rusage_sem);
+ }
+ td->update_rusage = 0;
+ }
+
show_run_stats();
for_each_td(td, i) {