independent fio invocations. Unfortuantely this also breaks
the strict time ordering between multiple device accesses.
+replay_align=int Force alignment of IO offsets and lengths in a trace
+ to this power of 2 value.
+
+replay_scale=int Scale sector offsets down by this factor when
+ replaying traces.
+
write_bw_log=str If given, write a bandwidth log of the jobs in this job
file. Can be used to store data of the bandwidth of the
jobs in their lifetime. The included fio_generate_plots
return last_fileno;
}
+static void t_bytes_align(struct thread_options *o, struct blk_io_trace *t)
+{
+ if (!o->replay_align)
+ return;
+
+ t->bytes = (t->bytes + o->replay_align - 1) & ~(o->replay_align - 1);
+}
+
+static void ipo_bytes_align(struct thread_options *o, struct io_piece *ipo)
+{
+ if (!o->replay_align)
+ return;
+
+ ipo->offset &= ~(o->replay_align - 1);
+}
+
+
/*
* Store blk_io_trace data in an ipo for later retrieval.
*/
init_ipo(ipo);
ipo->offset = offset * bs;
+ if (td->o.replay_scale)
+ ipo->offset = ipo->offset / td->o.replay_scale;
+ ipo_bytes_align(&td->o, ipo);
ipo->len = bytes;
ipo->delay = ttime / 1000;
if (rw)
INIT_FLIST_HEAD(&ipo->list);
ipo->offset = t->sector * bs;
+ if (td->o.replay_scale)
+ ipo->offset = ipo->offset / td->o.replay_scale;
+ ipo_bytes_align(&td->o, ipo);
ipo->len = t->bytes;
ipo->delay = ttime / 1000;
ipo->ddir = DDIR_TRIM;
unsigned long *ios, unsigned int *bs)
{
static unsigned long long last_ttime;
- unsigned long long delay;
+ unsigned long long delay = 0;
if ((t->action & 0xffff) != __BLK_TA_QUEUE)
return;
}
}
+ t_bytes_align(&td->o, t);
+
if (t->action & BLK_TC_ACT(BLK_TC_NOTIFY))
handle_trace_notify(t);
else if (t->action & BLK_TC_ACT(BLK_TC_DISCARD))
o->compress_percentage = le32_to_cpu(top->compress_percentage);
o->compress_chunk = le32_to_cpu(top->compress_chunk);
o->dedupe_percentage = le32_to_cpu(top->dedupe_percentage);
+ o->skip_bad = le32_to_cpu(top->skip_bad);
+ o->block_error_hist = le32_to_cpu(top->block_error_hist);
+ o->replay_align = le32_to_cpu(top->replay_align);
+ o->replay_scale = le32_to_cpu(top->replay_scale);
o->trim_backlog = le64_to_cpu(top->trim_backlog);
top->compress_percentage = cpu_to_le32(o->compress_percentage);
top->compress_chunk = cpu_to_le32(o->compress_chunk);
top->dedupe_percentage = cpu_to_le32(o->dedupe_percentage);
+ top->block_error_hist = cpu_to_le32(o->block_error_hist);
+ top->skip_bad = cpu_to_le32(o->skip_bad);
+ top->replay_align = cpu_to_le32(o->replay_align);
+ top->replay_scale = cpu_to_le32(o->replay_scale);
for (i = 0; i < DDIR_RWDIR_CNT; i++) {
top->bs[i] = cpu_to_le32(o->bs[i]);
#include <libaio.h>
#include "../fio.h"
+#include "../lib/pow2.h"
static int fio_libaio_commit(struct thread_data *td);
}
if (ret) {
- int aio_err = aio_error(aiocb);
+ int aio_err = errno;
/*
* At least OSX has a very low limit on the number of pending
#include <string.h>
#include "fio.h"
+#include "lib/pow2.h"
static char __run_str[REAL_MAX_JOBS + 1];
static char run_str[__THREAD_RUNSTR_SZ(REAL_MAX_JOBS)];
dprint(FD_FILE, "add file %s\n", fname);
if (td->o.directory)
- len = set_name_idx(file_name, td->o.directory, numjob);
+ len = set_name_idx(file_name, PATH_MAX, td->o.directory, numjob);
sprintf(file_name + len, "%s", fname);
from. Setting \fBreplay_redirect\fR causes all IOPS to be replayed onto the
single specified device regardless of the device it was recorded from.
.TP
+.BI replay_align \fR=\fPint
+Force alignment of IO offsets and lengths in a trace to this power of 2 value.
+.TP
+.BI replay_scale \fR=\fPint
+Scale sector offsets down by this factor when replaying traces.
+.TP
.BI write_bw_log \fR=\fPstr
If given, write a bandwidth log of the jobs in this job file. Can be used to
store data of the bandwidth of the jobs in their lifetime. The included
return min(td->o.min_bs[DDIR_TRIM], min_bs);
}
-static inline int is_power_of_2(uint64_t val)
-{
- return (val != 0 && ((val & (val - 1)) == 0));
-}
-
static inline int td_async_processing(struct thread_data *td)
{
return (td->flags & TD_F_NEED_LOCK) != 0;
#include "graph.h"
#include "gclient.h"
#include "printing.h"
+#include "lib/pow2.h"
static void gfio_display_ts(struct fio_client *client, struct thread_stat *ts,
struct group_run_stats *rs);
#include "lib/rand.h"
#include "lib/axmap.h"
#include "err.h"
+#include "lib/pow2.h"
struct io_completion_data {
int nr; /* input */
--- /dev/null
+#ifndef FIO_POW2_H
+#define FIO_POW2_H
+
+#include <inttypes.h>
+
+static inline int is_power_of_2(uint64_t val)
+{
+ return (val != 0 && ((val & (val - 1)) == 0));
+}
+
+#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <netinet/in.h>
#include "fio.h"
#include "verify.h"
#include "crc/crc32c.h"
+char client_sockaddr_str[INET6_ADDRSTRLEN] = { 0 };
+
/*
* Check if mmap/mmaphuge has a :/foo/bar/file at the end. If so, return that.
*/
* Returns the directory at the index, indexes > entires will be
* assigned via modulo division of the index
*/
-int set_name_idx(char *target, char *input, int index)
+int set_name_idx(char *target, size_t tlen, char *input, int index)
{
unsigned int cur_idx;
int len;
for (cur_idx = 0; cur_idx <= index; cur_idx++)
fname = get_next_name(&str);
- len = sprintf(target, "%s/", fname);
+ if (client_sockaddr_str[0]) {
+ len = snprintf(target, tlen, "%s/%s.", fname,
+ client_sockaddr_str);
+ } else
+ len = snprintf(target, tlen, "%s/", fname);
+
+ target[tlen - 1] = '\0';
free(p);
return len;
.category = FIO_OPT_C_IO,
.group = FIO_OPT_G_IOLOG,
},
+ {
+ .name = "replay_scale",
+ .lname = "Replace offset scale factor",
+ .type = FIO_OPT_INT,
+ .off1 = td_var_offset(replay_scale),
+ .parent = "read_iolog",
+ .def = "1",
+ .help = "Align offsets to this blocksize",
+ .category = FIO_OPT_C_IO,
+ .group = FIO_OPT_G_IOLOG,
+ },
+ {
+ .name = "replay_align",
+ .lname = "Replace alignment",
+ .type = FIO_OPT_INT,
+ .off1 = td_var_offset(replay_align),
+ .parent = "read_iolog",
+ .help = "Scale offset down by this factor",
+ .category = FIO_OPT_C_IO,
+ .group = FIO_OPT_G_IOLOG,
+ .pow2 = 1,
+ },
{
.name = "exec_prerun",
.lname = "Pre-execute runnable",
struct thread_data;
void fio_options_free(struct thread_data *);
char *get_name_idx(char *, int);
-int set_name_idx(char *, char *, int);
+int set_name_idx(char *, size_t, char *, int);
+
+extern char client_sockaddr_str[]; /* used with --client option */
extern struct fio_option fio_options[FIO_MAX_OPTS];
return dl_error;
}
+/* Copied from http://blogs.msdn.com/b/joshpoley/archive/2007/12/19/date-time-formats-and-conversions.aspx */
+void Time_tToSystemTime(time_t dosTime, SYSTEMTIME *systemTime)
+{
+ LARGE_INTEGER jan1970FT;
+ LARGE_INTEGER utcFT;
+ jan1970FT.QuadPart = 116444736000000000LL; // january 1st 1970
+ utcFT.QuadPart = ((unsigned __int64)dosTime) * 10000000 + jan1970FT.QuadPart;
+
+ FileTimeToSystemTime((FILETIME*)&utcFT, systemTime);
+}
+
+char* ctime_r(const time_t *t, char *buf)
+{
+ SYSTEMTIME systime;
+ const char * const dayOfWeek[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
+ const char * const monthOfYear[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+ Time_tToSystemTime(*t, &systime);
+ /* We don't know how long `buf` is, but assume it's rounded up from the minimum of 25 to 32 */
+ StringCchPrintfA(buf, 32, "%s %s %d %02d:%02d:%02d %04d", dayOfWeek[systime.wDayOfWeek - 1], monthOfYear[systime.wMonth - 1],
+ systime.wDay, systime.wHour, systime.wMinute, systime.wSecond, systime.wYear);
+ return buf;
+}
+
int gettimeofday(struct timeval *restrict tp, void *restrict tzp)
{
FILETIME fileTime;
--- /dev/null
+#ifndef IOCTL_H
+#define IOCTL_H
+
+/* This file is empty since it only needs to exist on Windows
+ but isn't otherwise used */
+
+#endif /* IOCTL_H */
\ No newline at end of file
#include "options.h"
#include "minmax.h"
#include "lib/ieee754.h"
+#include "lib/pow2.h"
#ifdef CONFIG_ARITHMETIC
#include "y.tab.h"
if (ret)
break;
+ if (o->pow2 && !is_power_of_2(ull)) {
+ log_err("%s: must be a power-of-2\n", o->name);
+ return 1;
+ }
if (o->maxval && ull > o->maxval) {
log_err("max value out of range: %llu"
int is_seconds; /* time value with seconds base */
int is_time; /* time based value */
int no_warn_def;
+ int pow2; /* must be a power-of-2 */
};
typedef int (str_cb_fn)(void *, char *);
}
/* exits */
+ strncpy(client_sockaddr_str, from, INET6_ADDRSTRLEN);
handle_connection(sk);
}
};
enum {
- FIO_SERVER_VER = 43,
+ FIO_SERVER_VER = 44,
FIO_SERVER_MAX_FRAGMENT_PDU = 1024,
FIO_SERVER_MAX_CMD_MB = 2048,
#include "json.h"
#include "lib/getrusage.h"
#include "idletime.h"
+#include "lib/pow2.h"
struct fio_mutex *stat_mutex;
unsigned block_error_hist;
unsigned int skip_bad;
+
+ unsigned int replay_align;
+ unsigned int replay_scale;
};
#define FIO_TOP_STR_MAX 256
uint32_t block_error_hist;
uint32_t skip_bad;
+
+ uint32_t replay_align;
+ uint32_t replay_scale;
} __attribute__((packed));
extern void convert_thread_options_to_cpu(struct thread_options *o, struct thread_options_pack *top);