Merge branch 'master' into gfio
Conflicts:
Makefile
configure
fio.h
Signed-off-by: Jens Axboe <axboe@kernel.dk>
diff --git a/Makefile b/Makefile
index a14d1f3..aff4fba 100644
--- a/Makefile
+++ b/Makefile
@@ -164,6 +164,7 @@
ifneq ($(findstring $(MAKEFLAGS),s),s)
ifndef V
QUIET_CC = @echo ' ' CC $@;
+ QUIET_LINK = @echo ' ' LINK $@;
QUIET_DEP = @echo ' ' DEP $@;
endif
endif
@@ -189,7 +190,7 @@
override CFLAGS += -DFIO_VERSION='"$(FIO_VERSION)"'
-.c.o: FORCE
+.c.o: FORCE FIO-VERSION-FILE
$(QUIET_CC)$(CC) -o $@ $(CFLAGS) $(CPPFLAGS) -c $<
@$(CC) -MM $(CFLAGS) $(CPPFLAGS) $*.c > $*.d
@mv -f $*.d $*.d.tmp
@@ -198,7 +199,7 @@
sed -e 's/^ *//' -e 's/$$/:/' >> $*.d
@rm -f $*.d.tmp
-init.o: FIO-VERSION-FILE
+init.o: FIO-VERSION-FILE init.c
$(QUIET_CC)$(CC) -o init.o $(CFLAGS) $(CPPFLAGS) -c init.c
gcompat.o: gcompat.c gcompat.h
@@ -229,22 +230,22 @@
$(QUIET_CC)$(CC) $(CFLAGS) $(GTK_CFLAGS) $(CPPFLAGS) -c printing.c
t/stest: $(T_SMALLOC_OBJS)
- $(QUIET_CC)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_SMALLOC_OBJS) $(LIBS) $(LDFLAGS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_SMALLOC_OBJS) $(LIBS) $(LDFLAGS)
t/ieee754: $(T_IEEE_OBJS)
- $(QUIET_CC)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_IEEE_OBJS) $(LIBS) $(LDFLAGS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_IEEE_OBJS) $(LIBS) $(LDFLAGS)
fio: $(FIO_OBJS)
- $(QUIET_CC)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(FIO_OBJS) $(LIBS) $(LDFLAGS)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(FIO_OBJS) $(LIBS) $(LDFLAGS)
gfio: $(GFIO_OBJS)
- $(QUIET_CC)$(CC) $(LIBS) -o gfio $(GFIO_OBJS) $(LIBS) $(GTK_LDFLAGS)
+ $(QUIET_LINK)$(CC) $(LIBS) -o gfio $(GFIO_OBJS) $(LIBS) $(GTK_LDFLAGS)
t/genzipf: $(T_ZIPF_OBJS)
- $(QUIET_CC)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_ZIPF_OBJS) $(LIBS) $(LDFLAGS)
+ $(QUIET_LINK)$(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)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_AXMAP_OBJS) $(LIBS) $(LDFLAGS)
clean: FORCE
-rm -f .depend $(GFIO_OBJS) $(OBJS) $(T_OBJS) $(PROGS) $(T_PROGS) core.* core gfio FIO-VERSION-FILE config-host.mak cscope.out *.d
diff --git a/README b/README
index 4c7b542..4173237 100644
--- a/README
+++ b/README
@@ -125,6 +125,9 @@
5. Run 'make clean'.
6. Run 'make'.
+To build fio on 32-bit Windows, download x86/pthreadGC2.dll instead and do
+'./configure --build-32bit-win=yes' before 'make'.
+
Command line
------------
diff --git a/cconv.c b/cconv.c
index e2548a8..5d575d3 100644
--- a/cconv.c
+++ b/cconv.c
@@ -182,6 +182,7 @@
o->trim_batch = le32_to_cpu(top->trim_batch);
o->trim_zero = le32_to_cpu(top->trim_zero);
o->clat_percentiles = le32_to_cpu(top->clat_percentiles);
+ o->percentile_precision = le32_to_cpu(top->percentile_precision);
o->continue_on_error = le32_to_cpu(top->continue_on_error);
o->cgroup_weight = le32_to_cpu(top->cgroup_weight);
o->cgroup_nodelete = le32_to_cpu(top->cgroup_nodelete);
@@ -327,6 +328,7 @@
top->trim_batch = cpu_to_le32(o->trim_batch);
top->trim_zero = cpu_to_le32(o->trim_zero);
top->clat_percentiles = cpu_to_le32(o->clat_percentiles);
+ top->percentile_precision = cpu_to_le32(o->percentile_precision);
top->continue_on_error = cpu_to_le32(o->continue_on_error);
top->cgroup_weight = cpu_to_le32(o->cgroup_weight);
top->cgroup_nodelete = cpu_to_le32(o->cgroup_nodelete);
diff --git a/configure b/configure
index cab3da8..1c8b2bb 100755
--- a/configure
+++ b/configure
@@ -137,9 +137,11 @@
--extra-cflags=*)
CFLAGS="$CFLAGS $optarg"
;;
+ --build-32bit-win=*) build_32bit_win="$optarg"
+ ;;
--enable-gfio)
- gfio="yes"
- ;;
+ gfio="yes"
+ ;;
--help)
show_help="yes"
;;
@@ -153,6 +155,7 @@
if test "$show_help" = "yes" ; then
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
@@ -191,13 +194,20 @@
CYGWIN*)
echo "Forcing known good options on Windows"
if test -z "$CC" ; then
- CC="x86_64-w64-mingw32-gcc"
+ if test ! -z "$build_32bit_win" && test "$build_32bit_win" = "yes"; then
+ CC="i686-w64-mingw32-gcc"
+ else
+ CC="x86_64-w64-mingw32-gcc"
+ fi
fi
output_sym "CONFIG_LITTLE_ENDIAN"
- output_sym "CONFIG_64BIT_LLP64"
+ if test ! -z "$build_32bit_win" && test "$build_32bit_win" = "yes"; then
+ output_sym "CONFIG_32BIT"
+ else
+ output_sym "CONFIG_64BIT_LLP64"
+ fi
output_sym "CONFIG_FADVISE"
output_sym "CONFIG_SOCKLEN_T"
- output_sym "CONFIG_POSIX_FALLOCATE"
output_sym "CONFIG_FADVISE"
output_sym "CONFIG_SFAA"
output_sym "CONFIG_RUSAGE_THREAD"
diff --git a/engines/windowsaio.c b/engines/windowsaio.c
index 773f027..3a24fa7 100644
--- a/engines/windowsaio.c
+++ b/engines/windowsaio.c
@@ -1,6 +1,7 @@
/*
- * Native Windows async IO engine
- * Copyright (C) 2012 Bruce Cran <bruce@cran.org.uk>
+ * windowsaio engine
+ *
+ * IO engine using Windows IO Completion Ports.
*/
#include <stdio.h>
@@ -37,94 +38,18 @@
};
static int fio_windowsaio_cancel(struct thread_data *td,
- struct io_u *io_u);
+ struct io_u *io_u);
static BOOL timeout_expired(DWORD start_count, DWORD end_count);
static int fio_windowsaio_getevents(struct thread_data *td, unsigned int min,
- unsigned int max, struct timespec *t);
+ unsigned int max, struct timespec *t);
static struct io_u *fio_windowsaio_event(struct thread_data *td, int event);
static int fio_windowsaio_queue(struct thread_data *td,
- struct io_u *io_u);
+ struct io_u *io_u);
static void fio_windowsaio_cleanup(struct thread_data *td);
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_posix_error(DWORD winerr);
-
-static int win_to_posix_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;
-}
static int fio_windowsaio_init(struct thread_data *td)
{
@@ -132,23 +57,27 @@
HANDLE hKernel32Dll;
int rc = 0;
- wd = malloc(sizeof(struct windowsaio_data));
- if (wd != NULL)
- ZeroMemory(wd, sizeof(struct windowsaio_data));
- else
+ wd = calloc(1, sizeof(struct windowsaio_data));
+ if (wd == NULL) {
+ log_err("windowsaio: failed to allocate memory for engine data\n");
rc = 1;
+ }
if (!rc) {
wd->aio_events = malloc(td->o.iodepth * sizeof(struct io_u*));
- if (wd->aio_events == NULL)
+ if (wd->aio_events == NULL) {
+ log_err("windowsaio: failed to allocate memory for aio events list\n");
rc = 1;
+ }
}
if (!rc) {
/* Create an auto-reset event */
wd->iocomplete_event = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (wd->iocomplete_event == NULL)
+ if (wd->iocomplete_event == NULL) {
+ log_err("windowsaio: failed to create io complete event handle\n");
rc = 1;
+ }
}
if (rc) {
@@ -164,15 +93,16 @@
wd->pCancelIoEx = (CANCELIOEX)GetProcAddress(hKernel32Dll, "CancelIoEx");
td->io_ops->data = wd;
-
if (!rc) {
struct thread_ctx *ctx;
struct windowsaio_data *wd;
HANDLE hFile;
hFile = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
- if (hFile == INVALID_HANDLE_VALUE)
+ if (hFile == INVALID_HANDLE_VALUE) {
+ log_err("windowsaio: failed to create io completion port\n");
rc = 1;
+ }
wd = td->io_ops->data;
wd->iothread_running = TRUE;
@@ -183,7 +113,7 @@
if (!rc && ctx == NULL)
{
- log_err("fio: out of memory in windowsaio\n");
+ log_err("windowsaio: failed to allocate memory for thread context structure\n");
CloseHandle(hFile);
rc = 1;
}
@@ -193,6 +123,8 @@
ctx->iocp = hFile;
ctx->wd = wd;
wd->iothread = CreateThread(NULL, 0, IoCompletionRoutine, ctx, 0, NULL);
+ if (wd->iothread == NULL)
+ log_err("windowsaio: failed to create io completion thread\n");
}
if (rc || wd->iothread == NULL)
@@ -234,12 +166,12 @@
dprint(FD_FILE, "fd open %s\n", f->file_name);
if (f->filetype == FIO_TYPE_PIPE) {
- log_err("fio: windowsaio doesn't support pipes\n");
+ log_err("windowsaio: pipes are not supported\n");
return 1;
}
if (!strcmp(f->file_name, "-")) {
- log_err("fio: can't read/write to stdin/out\n");
+ log_err("windowsaio: can't read/write to stdin/out\n");
return 1;
}
@@ -271,8 +203,10 @@
f->hFile = CreateFile(f->file_name, access, sharemode,
NULL, openmode, flags, NULL);
- if (f->hFile == INVALID_HANDLE_VALUE)
+ if (f->hFile == INVALID_HANDLE_VALUE) {
+ log_err("windowsaio: failed to open file \"%s\"\n", f->file_name);
rc = 1;
+ }
/* Only set up the completion port and thread if we're not just
* querying the device size */
@@ -281,8 +215,10 @@
wd = td->io_ops->data;
- if (CreateIoCompletionPort(f->hFile, wd->iocp, 0, 0) == NULL)
+ if (CreateIoCompletionPort(f->hFile, wd->iocp, 0, 0) == NULL) {
+ log_err("windowsaio: failed to create io completion port\n");
rc = 1;
+ }
}
return rc;
@@ -295,8 +231,10 @@
dprint(FD_FILE, "fd close %s\n", f->file_name);
if (f->hFile != INVALID_HANDLE_VALUE) {
- if (!CloseHandle(f->hFile))
+ if (!CloseHandle(f->hFile)) {
+ log_info("windowsaio: failed to close file handle for \"%s\"\n", f->file_name);
rc = 1;
+ }
}
f->hFile = INVALID_HANDLE_VALUE;
@@ -325,7 +263,7 @@
}
static int fio_windowsaio_getevents(struct thread_data *td, unsigned int min,
- unsigned int max, struct timespec *t)
+ unsigned int max, struct timespec *t)
{
struct windowsaio_data *wd = td->io_ops->data;
struct flist_head *entry;
@@ -362,7 +300,7 @@
if (dequeued < min) {
status = WaitForSingleObject(wd->iocomplete_event, mswait);
if (status != WAIT_OBJECT_0 && dequeued >= min)
- break;
+ break;
}
if (dequeued >= min || (t != NULL && timeout_expired(start_count, end_count)))
@@ -398,13 +336,15 @@
case DDIR_DATASYNC:
case DDIR_SYNC_FILE_RANGE:
success = FlushFileBuffers(io_u->file->hFile);
- if (!success)
- io_u->error = win_to_posix_error(GetLastError());
+ if (!success) {
+ log_err("windowsaio: failed to flush file buffers\n");
+ io_u->error = win_to_posix_error(GetLastError());
+ }
return FIO_Q_COMPLETED;
break;
case DDIR_TRIM:
- log_err("manual TRIM isn't supported on Windows");
+ log_err("windowsaio: manual TRIM isn't supported on Windows\n");
io_u->error = 1;
io_u->resid = io_u->xfer_buflen;
return FIO_Q_COMPLETED;
@@ -463,7 +403,7 @@
}
static int fio_windowsaio_cancel(struct thread_data *td,
- struct io_u *io_u)
+ struct io_u *io_u)
{
int rc = 0;
@@ -473,8 +413,10 @@
if (wd->pCancelIoEx != NULL) {
struct fio_overlapped *ovl = io_u->engine_data;
- if (!wd->pCancelIoEx(io_u->file->hFile, &ovl->o))
+ if (!wd->pCancelIoEx(io_u->file->hFile, &ovl->o)) {
+ log_err("windowsaio: failed to cancel io\n");
rc = 1;
+ }
} else
rc = 1;
@@ -500,7 +442,8 @@
o->io_complete = FALSE;
o->io_u = io_u;
o->o.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (!o->o.hEvent) {
+ if (o->o.hEvent == NULL) {
+ log_err("windowsaio: failed to create event handle\n");
free(o);
return 1;
}
@@ -525,12 +468,12 @@
.io_u_free = fio_windowsaio_io_u_free,
};
-static void fio_init fio_posixaio_register(void)
+static void fio_init fio_windowsaio_register(void)
{
register_ioengine(&ioengine);
}
-static void fio_exit fio_posixaio_unregister(void)
+static void fio_exit fio_windowsaio_unregister(void)
{
unregister_ioengine(&ioengine);
}
diff --git a/eta.c b/eta.c
index 6f897a4..a724fe6 100644
--- a/eta.c
+++ b/eta.c
@@ -139,6 +139,15 @@
bytes_total = td->fill_device_size;
}
+ if (td->o.zone_size && td->o.zone_skip && bytes_total) {
+ unsigned int nr_zones;
+ uint64_t zone_bytes;
+
+ zone_bytes = bytes_total + td->o.zone_size + td->o.zone_skip;
+ nr_zones = (zone_bytes - 1) / (td->o.zone_size + td->o.zone_skip);
+ bytes_total -= nr_zones * td->o.zone_skip;
+ }
+
/*
* if writing and verifying afterwards, bytes_total will be twice the
* size. In a mixed workload, verify phase will be the size of the
@@ -156,9 +165,6 @@
bytes_total <<= 1;
}
- if (td->o.zone_size && td->o.zone_skip)
- bytes_total /= (td->o.zone_skip / td->o.zone_size);
-
if (td->runstate == TD_RUNNING || td->runstate == TD_VERIFYING) {
double perc, perc_t;
diff --git a/init.c b/init.c
index 25c8d78..ce699df 100644
--- a/init.c
+++ b/init.c
@@ -415,7 +415,7 @@
/*
* only really works with 1 file
*/
- if (o->zone_size && o->open_files == 1)
+ if (o->zone_size && o->open_files > 1)
o->zone_size = 0;
/*
@@ -869,6 +869,7 @@
td->mutex = fio_mutex_init(FIO_MUTEX_LOCKED);
td->ts.clat_percentiles = td->o.clat_percentiles;
+ td->ts.percentile_precision = td->o.percentile_precision;
memcpy(td->ts.percentile_list, td->o.percentile_list, sizeof(td->o.percentile_list));
for (i = 0; i < DDIR_RWDIR_CNT; i++) {
diff --git a/options.c b/options.c
index 63293e0..fcf4270 100644
--- a/options.c
+++ b/options.c
@@ -2851,6 +2851,7 @@
.lname = "Completion latency percentile list",
.type = FIO_OPT_FLOAT_LIST,
.off1 = td_var_offset(percentile_list),
+ .off2 = td_var_offset(percentile_precision),
.help = "Specify a custom list of percentiles to report",
.def = "1:5:10:20:30:40:50:60:70:80:90:95:99:99.5:99.9:99.95:99.99",
.maxlen = FIO_IO_U_LIST_MAX_LEN,
diff --git a/os/os-windows.h b/os/os-windows.h
index 98f9030..09f9c54 100644
--- a/os/os-windows.h
+++ b/os/os-windows.h
@@ -151,12 +151,14 @@
static inline unsigned long long os_phys_mem(void)
{
- SYSTEM_INFO sysInfo;
- uintptr_t addr;
+ long pagesize, pages;
- GetSystemInfo(&sysInfo);
- addr = (uintptr_t)sysInfo.lpMaximumApplicationAddress;
- return (unsigned long long)addr;
+ 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;
}
static inline void os_get_tmpdir(char *path, int len)
diff --git a/os/windows/eula.rtf b/os/windows/eula.rtf
index be37fad..cc7be7f 100755
--- a/os/windows/eula.rtf
+++ b/os/windows/eula.rtf
Binary files differ
diff --git a/os/windows/install.wxs b/os/windows/install.wxs
index 5845d5f..b43120a 100755
--- a/os/windows/install.wxs
+++ b/os/windows/install.wxs
@@ -7,14 +7,13 @@
<?define ProgramDirectory = ProgramFiles64Folder ?>
<?endif?>
- <Product Id="F9883688-6AB3-4BD1-AB93-91D39F12F003"
+ <Product Id="*"
Codepage="1252" Language="1033"
Manufacturer="fio" Name="fio"
- UpgradeCode="2338A332-5511-43cf-b9BD-5C60496CCFCC" Version="2.0.13">
+ UpgradeCode="2338A332-5511-43CF-B9BD-5C60496CCFCC" Version="2.0.13">
<Package
- Comments="Contact: Your local administrator"
Description="Flexible IO Tester"
- InstallerVersion="200" Keywords="Installer,MSI,Database"
+ InstallerVersion="301" Keywords="Installer,MSI,Database"
Languages="1033" Manufacturer="fio"
InstallScope="perMachine" InstallPrivileges="elevated" Compressed="yes"/>
@@ -67,11 +66,6 @@
<UIRef Id="WixUI_Minimal"/>
- <Condition Message="Per-user installations are not supported">
- Installed OR
- ALLUSERS=1
- </Condition>
-
<MajorUpgrade AllowDowngrades="no" DowngradeErrorMessage="A newer version of the application is already installed."/>
</Product>
</Wix>
diff --git a/os/windows/posix.c b/os/windows/posix.c
index 05fa5a9..6a7841d 100755
--- a/os/windows/posix.c
+++ b/os/windows/posix.c
@@ -43,6 +43,81 @@
const char *format,
va_list argptr);
+int win_to_posix_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 GetNumLogicalProcessors(void)
{
SYSTEM_LOGICAL_PROCESSOR_INFORMATION *processor_info = NULL;
@@ -79,6 +154,7 @@
long sysconf(int name)
{
long val = -1;
+ long val2 = -1;
SYSTEM_INFO sysInfo;
MEMORYSTATUSEX status;
@@ -87,7 +163,7 @@
case _SC_NPROCESSORS_ONLN:
val = GetNumLogicalProcessors();
if (val == -1)
- log_err("_SC_NPROCESSORS_ONLN failed\n");
+ log_err("sysconf(_SC_NPROCESSORS_ONLN) failed\n");
break;
@@ -98,8 +174,11 @@
case _SC_PHYS_PAGES:
status.dwLength = sizeof(status);
- GlobalMemoryStatusEx(&status);
- val = status.ullTotalPhys;
+ val2 = sysconf(_SC_PAGESIZE);
+ if (GlobalMemoryStatusEx(&status) && val2 != -1)
+ val = status.ullTotalPhys / val2;
+ else
+ log_err("sysconf(_SC_PHYS_PAGES) failed\n");
break;
default:
log_err("sysconf(%d) is not implemented\n", name);
@@ -210,6 +289,8 @@
if ((flags & MAP_ANON) | (flags & MAP_ANONYMOUS))
{
allocAddr = VirtualAlloc(addr, len, MEM_COMMIT, vaProt);
+ if (allocAddr == NULL)
+ errno = win_to_posix_error(GetLastError());
}
return allocAddr;
@@ -217,21 +298,26 @@
int munmap(void *addr, size_t len)
{
- return !VirtualFree(addr, 0, MEM_RELEASE);
+ if (!VirtualFree(addr, 0, MEM_RELEASE)) {
+ errno = win_to_posix_error(GetLastError());
+ return -1;
+ }
+
+ return 0;
}
int fork(void)
{
log_err("%s is not implemented\n", __func__);
errno = ENOSYS;
- return (-1);
+ return -1;
}
pid_t setsid(void)
{
log_err("%s is not implemented\n", __func__);
errno = ENOSYS;
- return (-1);
+ return -1;
}
static HANDLE log_file = INVALID_HANDLE_VALUE;
@@ -276,7 +362,7 @@
int kill(pid_t pid, int sig)
{
errno = ESRCH;
- return (-1);
+ return -1;
}
/*
@@ -297,7 +383,7 @@
return 0;
else if (cmd != F_SETFL) {
errno = EINVAL;
- return (-1);
+ return -1;
}
va_start(ap, 1);
@@ -369,12 +455,42 @@
int mlock(const void * addr, size_t len)
{
- return !VirtualLock((LPVOID)addr, len);
+ SIZE_T min, max;
+ BOOL success;
+ HANDLE process = GetCurrentProcess();
+
+ success = GetProcessWorkingSetSize(process, &min, &max);
+ if (!success) {
+ errno = win_to_posix_error(GetLastError());
+ return -1;
+ }
+
+ min += len;
+ max += len;
+ success = SetProcessWorkingSetSize(process, min, max);
+ if (!success) {
+ errno = win_to_posix_error(GetLastError());
+ return -1;
+ }
+
+ success = VirtualLock((LPVOID)addr, len);
+ if (!success) {
+ errno = win_to_posix_error(GetLastError());
+ return -1;
+ }
+
+ return 0;
}
int munlock(const void * addr, size_t len)
{
- return !VirtualUnlock((LPVOID)addr, len);
+ BOOL success = VirtualUnlock((LPVOID)addr, len);
+ if (!success) {
+ errno = win_to_posix_error(GetLastError());
+ return -1;
+ }
+
+ return 0;
}
pid_t waitpid(pid_t pid, int *stat_loc, int options)
@@ -408,68 +524,15 @@
return name;
}
-int posix_fallocate(int fd, off_t offset, off_t len)
-{
- const int BUFFER_SIZE = 256 * 1024;
- int rc = 0;
- char *buf;
- unsigned int write_len;
- unsigned int bytes_written;
- off_t bytes_remaining = len;
-
- if (len == 0 || offset < 0)
- return EINVAL;
-
- buf = malloc(BUFFER_SIZE);
-
- if (buf == NULL)
- return ENOMEM;
-
- memset(buf, 0, BUFFER_SIZE);
-
- int64_t prev_pos = _telli64(fd);
-
- if (_lseeki64(fd, offset, SEEK_SET) == -1)
- return errno;
-
- while (bytes_remaining > 0) {
- if (bytes_remaining < BUFFER_SIZE)
- write_len = (unsigned int)bytes_remaining;
- else
- write_len = BUFFER_SIZE;
-
- bytes_written = _write(fd, buf, write_len);
- if (bytes_written == -1) {
- rc = errno;
- break;
- }
-
- /* Don't allow Windows to cache the write: flush it to disk */
- _commit(fd);
-
- bytes_remaining -= bytes_written;
- }
-
- free(buf);
- _lseeki64(fd, prev_pos, SEEK_SET);
- return rc;
-}
-
-int ftruncate(int fildes, off_t length)
-{
- BOOL bSuccess;
- int64_t prev_pos = _telli64(fildes);
- _lseeki64(fildes, length, SEEK_SET);
- HANDLE hFile = (HANDLE)_get_osfhandle(fildes);
- bSuccess = SetEndOfFile(hFile);
- _lseeki64(fildes, prev_pos, SEEK_SET);
- return !bSuccess;
-}
-
int fsync(int fildes)
{
HANDLE hFile = (HANDLE)_get_osfhandle(fildes);
- return !FlushFileBuffers(hFile);
+ if (!FlushFileBuffers(hFile)) {
+ errno = win_to_posix_error(GetLastError());
+ return -1;
+ }
+
+ return 0;
}
int nFileMappings = 0;
@@ -497,14 +560,33 @@
void* mapAddr;
MEMORY_BASIC_INFORMATION memInfo;
mapAddr = MapViewOfFile(fileMappings[shmid], FILE_MAP_ALL_ACCESS, 0, 0, 0);
- VirtualQuery(mapAddr, &memInfo, sizeof(memInfo));
+ if (mapAddr == NULL) {
+ errno = win_to_posix_error(GetLastError());
+ return (void*)-1;
+ }
+
+ if (VirtualQuery(mapAddr, &memInfo, sizeof(memInfo)) == 0) {
+ errno = win_to_posix_error(GetLastError());
+ return (void*)-1;
+ }
+
mapAddr = VirtualAlloc(mapAddr, memInfo.RegionSize, MEM_COMMIT, PAGE_READWRITE);
+ if (mapAddr == NULL) {
+ errno = win_to_posix_error(GetLastError());
+ return (void*)-1;
+ }
+
return mapAddr;
}
int shmdt(const void *shmaddr)
{
- return !UnmapViewOfFile(shmaddr);
+ if (!UnmapViewOfFile(shmaddr)) {
+ errno = win_to_posix_error(GetLastError());
+ return -1;
+ }
+
+ return 0;
}
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
@@ -515,21 +597,22 @@
} else {
log_err("%s is not implemented\n", __func__);
}
- return (-1);
+ errno = ENOSYS;
+ return -1;
}
int setuid(uid_t uid)
{
log_err("%s is not implemented\n", __func__);
errno = ENOSYS;
- return (-1);
+ return -1;
}
int setgid(gid_t gid)
{
log_err("%s is not implemented\n", __func__);
errno = ENOSYS;
- return (-1);
+ return -1;
}
int nice(int incr)
@@ -622,14 +705,14 @@
{
log_err("%s is not implemented\n", __func__);
errno = ENOSYS;
- return (-1);
+ return -1;
}
ssize_t writev(int fildes, const struct iovec *iov, int iovcnt)
{
log_err("%s is not implemented\n", __func__);
errno = ENOSYS;
- return (-1);
+ return -1;
}
long long strtoll(const char *restrict str, char **restrict endptr,
@@ -725,40 +808,40 @@
DIR *opendir(const char *dirname)
{
- struct dirent_ctx *dc = NULL;
+ struct dirent_ctx *dc = NULL;
- /* See if we can open it. If not, we'll return an error here */
- HANDLE file = CreateFileA(dirname, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- if (file != INVALID_HANDLE_VALUE) {
- CloseHandle(file);
- dc = (struct dirent_ctx*)malloc(sizeof(struct dirent_ctx));
- StringCchCopyA(dc->dirname, MAX_PATH, dirname);
- dc->find_handle = INVALID_HANDLE_VALUE;
- } else {
- DWORD error = GetLastError();
- if (error == ERROR_FILE_NOT_FOUND)
- errno = ENOENT;
+ /* See if we can open it. If not, we'll return an error here */
+ HANDLE file = CreateFileA(dirname, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (file != INVALID_HANDLE_VALUE) {
+ CloseHandle(file);
+ dc = (struct dirent_ctx*)malloc(sizeof(struct dirent_ctx));
+ StringCchCopyA(dc->dirname, MAX_PATH, dirname);
+ dc->find_handle = INVALID_HANDLE_VALUE;
+ } else {
+ DWORD error = GetLastError();
+ if (error == ERROR_FILE_NOT_FOUND)
+ errno = ENOENT;
- else if (error == ERROR_PATH_NOT_FOUND)
- errno = ENOTDIR;
- else if (error == ERROR_TOO_MANY_OPEN_FILES)
- errno = ENFILE;
- else if (error == ERROR_ACCESS_DENIED)
- errno = EACCES;
- else
- errno = error;
- }
+ else if (error == ERROR_PATH_NOT_FOUND)
+ errno = ENOTDIR;
+ else if (error == ERROR_TOO_MANY_OPEN_FILES)
+ errno = ENFILE;
+ else if (error == ERROR_ACCESS_DENIED)
+ errno = EACCES;
+ else
+ errno = error;
+ }
- return dc;
+ return dc;
}
int closedir(DIR *dirp)
{
- if (dirp != NULL && dirp->find_handle != INVALID_HANDLE_VALUE)
- FindClose(dirp->find_handle);
+ if (dirp != NULL && dirp->find_handle != INVALID_HANDLE_VALUE)
+ FindClose(dirp->find_handle);
- free(dirp);
- return 0;
+ free(dirp);
+ return 0;
}
struct dirent *readdir(DIR *dirp)
diff --git a/os/windows/posix.h b/os/windows/posix.h
index cb89cf6..85640a2 100644
--- a/os/windows/posix.h
+++ b/os/windows/posix.h
@@ -6,5 +6,6 @@
extern int clock_gettime(clockid_t clock_id, struct timespec *tp);
extern int inet_aton(const char *, struct in_addr *);
+extern int win_to_posix_error(DWORD winerr);
#endif
diff --git a/parse.c b/parse.c
index 7652a4d..9250133 100644
--- a/parse.c
+++ b/parse.c
@@ -501,6 +501,21 @@
break;
}
case FIO_OPT_FLOAT_LIST: {
+ char *cp2;
+
+ if (first) {
+ /*
+ ** Initialize precision to 0 and zero out list
+ ** in case specified list is shorter than default
+ */
+ ul2 = 0;
+ ilp = td_var(data, o->off2);
+ *ilp = ul2;
+
+ flp = td_var(data, o->off1);
+ for(i = 0; i < o->maxlen; i++)
+ flp[i].u.f = 0.0;
+ }
if (curr >= o->maxlen) {
log_err("the list exceeding max length %d\n",
o->maxlen);
@@ -524,6 +539,23 @@
flp = td_var(data, o->off1);
flp[curr].u.f = uf;
+ /*
+ ** Calculate precision for output by counting
+ ** number of digits after period. Find first
+ ** period in entire remaining list each time
+ */
+ cp2 = strchr(ptr, '.');
+ if (cp2 != NULL) {
+ int len = 0;
+
+ while (*++cp2 != '\0' && *cp2 >= '0' && *cp2 <= '9')
+ len++;
+
+ ilp = td_var(data, o->off2);
+ if (len > *ilp)
+ *ilp = len;
+ }
+
break;
}
case FIO_OPT_STR_STORE: {
diff --git a/stat.c b/stat.c
index b16c55c..8835f7f 100644
--- a/stat.c
+++ b/stat.c
@@ -180,11 +180,12 @@
* Find and display the p-th percentile of clat
*/
static void show_clat_percentiles(unsigned int *io_u_plat, unsigned long nr,
- fio_fp64_t *plist)
+ fio_fp64_t *plist, unsigned int precision)
{
unsigned int len, j = 0, minv, maxv;
unsigned int *ovals;
- int is_last, scale_down;
+ int is_last, per_line, scale_down;
+ char fmt[32];
len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
if (!len)
@@ -202,20 +203,23 @@
log_info(" clat percentiles (usec):\n |");
}
+ snprintf(fmt, sizeof(fmt), "%%1.%uf", precision);
+ per_line = (80 - 7) / (precision + 14);
+
for (j = 0; j < len; j++) {
- char fbuf[8];
+ char fbuf[16], *ptr = fbuf;
/* for formatting */
- if (j != 0 && (j % 4) == 0)
+ if (j != 0 && (j % per_line) == 0)
log_info(" |");
/* end of the list */
is_last = (j == len - 1);
if (plist[j].u.f < 10.0)
- sprintf(fbuf, " %2.2f", plist[j].u.f);
- else
- sprintf(fbuf, "%2.2f", plist[j].u.f);
+ ptr += sprintf(fbuf, " ");
+
+ snprintf(ptr, sizeof(fbuf), fmt, plist[j].u.f);
if (scale_down)
ovals[j] = (ovals[j] + 999) / 1000;
@@ -225,7 +229,7 @@
if (is_last)
break;
- if (j % 4 == 3) /* for formatting */
+ if ((j % per_line) == per_line - 1) /* for formatting */
log_info("\n");
}
@@ -397,7 +401,8 @@
if (ts->clat_percentiles) {
show_clat_percentiles(ts->io_u_plat[ddir],
ts->clat_stat[ddir].samples,
- ts->percentile_list);
+ ts->percentile_list,
+ ts->percentile_precision);
}
if (calc_lat(&ts->bw_stat[ddir], &min, &max, &mean, &dev)) {
double p_of_agg = 100.0;
@@ -614,7 +619,7 @@
log_info(";0%%=0");
continue;
}
- log_info(";%2.2f%%=%u", ts->percentile_list[i].u.f, ovals[i]);
+ log_info(";%f%%=%u", ts->percentile_list[i].u.f, ovals[i]);
}
if (calc_lat(&ts->lat_stat[ddir], &min, &max, &mean, &dev))
@@ -712,7 +717,7 @@
json_object_add_value_int(percentile_object, "0.00", 0);
continue;
}
- snprintf(buf, sizeof(buf), "%2.2f", ts->percentile_list[i].u.f);
+ snprintf(buf, sizeof(buf), "%f", ts->percentile_list[i].u.f);
json_object_add_value_int(percentile_object, (const char *)buf, ovals[i]);
}
@@ -1169,6 +1174,7 @@
ts = &threadstats[j];
ts->clat_percentiles = td->o.clat_percentiles;
+ ts->percentile_precision = td->o.percentile_precision;
memcpy(ts->percentile_list, td->o.percentile_list, sizeof(td->o.percentile_list));
idx++;
diff --git a/stat.h b/stat.h
index ba4c2bf..a3b391c 100644
--- a/stat.h
+++ b/stat.h
@@ -147,6 +147,7 @@
* IO depth and latency stats
*/
uint64_t clat_percentiles;
+ uint64_t percentile_precision;
fio_fp64_t percentile_list[FIO_IO_U_LIST_MAX_LEN];
uint32_t io_u_map[FIO_IO_U_MAP_NR];
diff --git a/t/log.c b/t/log.c
index 76ae68e..1ed3851 100644
--- a/t/log.c
+++ b/t/log.c
@@ -1,5 +1,6 @@
#include <stdio.h>
#include <stdarg.h>
+#include "../minmax.h"
int log_err(const char *format, ...)
{
diff --git a/thread_options.h b/thread_options.h
index 11e7af7..a28ccfe 100644
--- a/thread_options.h
+++ b/thread_options.h
@@ -197,6 +197,7 @@
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;
@@ -396,6 +397,7 @@
uint32_t trim_zero;
uint64_t trim_backlog;
uint32_t clat_percentiles;
+ uint32_t percentile_precision;
fio_fp64_t percentile_list[FIO_IO_U_LIST_MAX_LEN];
uint8_t read_iolog_file[FIO_TOP_STR_MAX];