':' colon. So if you wanted a job to open /dev/sda and /dev/sdb
as the two working files, you would use
filename=/dev/sda:/dev/sdb. On Windows, disk devices are accessed
- as /dev/sda for the first device (i.e. \Device\HardDisk0\Partition0,
- /dev/sda1 for the first partition on the first disk 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".
+ 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
two depends on the read/write direction set.
tool (http://www.opencsw.org/get-it/pkgutil/) and then install fio via
'pkgutil -i fio'.
+Windows:
+Bruce Cran <bruce@cran.org.uk> has fio packages for Windows at
+http://www.bluestop.org/fio .
+
Mailing list
------------
Building
--------
-Just type 'make' and 'make install'. If on FreeBSD, for now you have to
-specify the FreeBSD Makefile with -f and use gmake (not make), eg:
+Just type 'make' and 'make install'. If on BSD, for now you have to
+specify the BSD Makefile with -f and use gmake (not make), eg:
-$ gmake -f Makefile.Freebsd && gmake -f Makefile.FreeBSD install
+$ gmake -f Makefile.FreeBSD && gmake -f Makefile.FreeBSD install
Same goes for AIX:
each job file will be regarded as a separate group and fio will stonewall
its execution.
-The --readonly switch is an extra safety guard to prevent accidentically
+The --readonly switch is an extra safety guard to prevent accidentally
turning on a write setting when that is not desired. Fio will only write
if rw=write/randwrite/rw/randrw is given, but this extra safety net can
be used as an extra precaution. It will also enable a write check in the
Platforms
---------
-Fio works on (at least) Linux, Solaris, AIX, OSX, NetBSD, and FreeBSD. Some
-features and/or options may only be available on some of the platforms,
+Fio works on (at least) Linux, Solaris, AIX, OSX, NetBSD, Windows and FreeBSD.
+Some features and/or options may only be available on some of the platforms,
typically because those features only apply to that platform (like the
solarisaio engine, or the splice engine on Linux).
--- /dev/null
+/*
+ * Native Windows async IO engine
+ * Copyright (C) 2010 Bruce Cran <bruce@cran.org.uk>
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <windows.h>
+
+#include "../fio.h"
+
+BOOL windowsaio_debug = FALSE;
+
+struct windowsaio_data {
+ struct io_u **aio_events;
+ unsigned int ioFinished;
+ BOOL running;
+ BOOL stopped;
+ HANDLE hThread;
+};
+
+typedef struct {
+ OVERLAPPED o;
+ struct io_u *io_u;
+} FIO_OVERLAPPED;
+
+struct thread_ctx {
+ HANDLE ioCP;
+ struct windowsaio_data *wd;
+};
+
+static void PrintError(LPCSTR lpszFunction);
+static int fio_windowsaio_cancel(struct thread_data *td,
+ struct io_u *io_u);
+static DWORD GetEndCount(DWORD startCount, struct timespec *t);
+static BOOL TimedOut(DWORD startCount, DWORD endCount);
+static int fio_windowsaio_getevents(struct thread_data *td, unsigned int min,
+ 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);
+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 void PrintError(LPCSTR lpszFunction)
+{
+ // Retrieve the system error message for the last-error code
+
+ LPSTR lpMsgBuf;
+ DWORD dw = GetLastError();
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ dw,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR)&lpMsgBuf,
+ 0, NULL );
+
+ log_err("%s - %s", lpszFunction, lpMsgBuf);
+ LocalFree(lpMsgBuf);
+}
+
+static int fio_windowsaio_cancel(struct thread_data *td,
+ struct io_u *io_u)
+{
+ BOOL bSuccess;
+ int rc = 0;
+
+ bSuccess = CancelIo(io_u->file->hFile);
+
+ if (!bSuccess)
+ rc = 1;
+
+ return rc;
+}
+
+static DWORD GetEndCount(DWORD startCount, struct timespec *t)
+{
+ DWORD endCount = startCount;
+
+ if (t == NULL)
+ return 0;
+
+ endCount += (t->tv_sec * 1000) + (t->tv_nsec / 1000000);
+ return endCount;
+}
+
+static BOOL TimedOut(DWORD startCount, DWORD endCount)
+{
+ BOOL expired = FALSE;
+ DWORD currentTime;
+
+ if (startCount == 0 || endCount == 0)
+ return FALSE;
+
+ currentTime = GetTickCount();
+
+ if ((endCount > startCount) && currentTime >= endCount)
+ expired = TRUE;
+ else if (currentTime < startCount && currentTime > endCount)
+ expired = TRUE;
+
+ if (windowsaio_debug)
+ printf("windowsaio: timedout = %d\n", expired);
+
+ return expired;
+}
+
+static int fio_windowsaio_getevents(struct thread_data *td, unsigned int min,
+ unsigned int max, struct timespec *t)
+{
+ struct windowsaio_data *wd = td->io_ops->data;
+ struct flist_head *entry;
+ unsigned int dequeued = 0;
+ struct io_u *io_u;
+ DWORD startCount = 0, endCount = 0;
+ BOOL timedout = FALSE;
+ unsigned int r = 0;
+
+ if (windowsaio_debug)
+ printf("getevents (min %d, max %d)\n", min, max);
+
+ if (t != NULL) {
+ startCount = GetTickCount();
+ endCount = GetEndCount(startCount, t);
+ }
+
+ while (dequeued < min && !timedout) {
+
+ flist_for_each(entry, &td->io_u_busylist) {
+ io_u = flist_entry(entry, struct io_u, list);
+
+ if (io_u->seen == 0)
+ continue;
+
+ dequeued++;
+
+ wd->ioFinished--;
+ wd->aio_events[r] = io_u;
+ r++;
+
+ if (windowsaio_debug)
+ printf("dequeued %d\n", dequeued);
+
+ if (dequeued == max)
+ break;
+ }
+
+ if (TimedOut(startCount, endCount))
+ timedout = TRUE;
+
+ if (dequeued < min && !timedout)
+ Sleep(250);
+ }
+
+ if (windowsaio_debug)
+ printf("leave getevents (%d)\n", dequeued);
+
+ return dequeued;
+}
+
+static struct io_u *fio_windowsaio_event(struct thread_data *td, int event)
+{
+ struct windowsaio_data *wd = td->io_ops->data;
+ return wd->aio_events[event];
+}
+
+static int fio_windowsaio_queue(struct thread_data *td,
+ struct io_u *io_u)
+{
+ FIO_OVERLAPPED *fov;
+ DWORD ioBytes;
+ BOOL bSuccess = TRUE;
+ int rc;
+
+ fio_ro_check(td, io_u);
+
+ if (windowsaio_debug)
+ printf("enqueue enter\n");
+
+ fov = malloc(sizeof(FIO_OVERLAPPED));
+ ZeroMemory(fov, sizeof(FIO_OVERLAPPED));
+
+ io_u->seen = 0;
+
+ fov->o.Offset = io_u->offset & 0xFFFFFFFF;
+ fov->o.OffsetHigh = io_u->offset >> 32;
+ fov->o.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ fov->io_u = io_u;
+
+ if (fov->o.hEvent == NULL) {
+ PrintError(__func__);
+ return 1;
+ }
+
+ if (io_u->ddir == DDIR_WRITE)
+ bSuccess = WriteFile(io_u->file->hFile, io_u->xfer_buf, io_u->xfer_buflen, &ioBytes, &fov->o);
+ else if (io_u->ddir == DDIR_READ)
+ bSuccess = ReadFile(io_u->file->hFile, io_u->xfer_buf, io_u->xfer_buflen, &ioBytes, &fov->o);
+ else if (io_u->ddir == DDIR_SYNC ||
+ io_u->ddir == DDIR_DATASYNC ||
+ io_u->ddir == DDIR_SYNC_FILE_RANGE)
+ {
+ FlushFileBuffers(io_u->file->hFile);
+ return FIO_Q_COMPLETED;
+ } else if (io_u->ddir == DDIR_TRIM) {
+ log_info("explicit TRIM isn't supported on Windows");
+ return FIO_Q_COMPLETED;
+ }
+
+ if (bSuccess) {
+ io_u->seen = 1;
+ io_u->resid = io_u->xfer_buflen - fov->o.InternalHigh;
+ io_u->error = 0;
+ rc = FIO_Q_COMPLETED;
+ } else if (!bSuccess && GetLastError() == ERROR_IO_PENDING) {
+ rc = FIO_Q_QUEUED;
+ } else {
+ PrintError(__func__);
+ io_u->error = GetLastError();
+ io_u->resid = io_u->xfer_buflen;
+ rc = FIO_Q_COMPLETED;
+ }
+
+ if (windowsaio_debug)
+ printf("enqueue - leave (offset %llu)\n", io_u->offset);
+
+ return rc;
+}
+
+static void fio_windowsaio_cleanup(struct thread_data *td)
+{
+ struct windowsaio_data *wd;
+
+ if (windowsaio_debug)
+ printf("windowsaio: cleanup - enter\n");
+
+ wd = td->io_ops->data;
+ wd->running = FALSE;
+
+ while (wd->stopped == FALSE)
+ Sleep(5);
+
+ if (wd != NULL) {
+ CloseHandle(wd->hThread);
+ free(wd->aio_events);
+ wd->aio_events = NULL;
+ free(wd);
+ td->io_ops->data = NULL;
+ }
+
+ if (windowsaio_debug)
+ printf("windowsaio: cleanup - leave\n");
+}
+
+static DWORD WINAPI IoCompletionRoutine(LPVOID lpParameter)
+{
+ OVERLAPPED *ovl;
+ FIO_OVERLAPPED *fov;
+ struct io_u *io_u;
+ struct windowsaio_data *wd;
+
+ struct thread_ctx *ctx;
+ ULONG_PTR ulKey = 0;
+ BOOL bSuccess;
+ DWORD bytes;
+
+
+ ctx = (struct thread_ctx*)lpParameter;
+ wd = ctx->wd;
+ bSuccess = TRUE;
+
+ if (windowsaio_debug)
+ printf("windowsaio: IoCompletionRoutine - enter\n");
+
+ while (ctx->wd->running) {
+ bSuccess = GetQueuedCompletionStatus(ctx->ioCP, &bytes, &ulKey, &ovl, 500);
+
+ if (windowsaio_debug)
+ printf("GetQueuedCompletionStatus returned %d\n", bSuccess);
+
+ if (!bSuccess) {
+ if (GetLastError() == WAIT_TIMEOUT) {
+ continue;
+ } else {
+ PrintError(__func__);
+ continue;
+ }
+ }
+
+ fov = CONTAINING_RECORD(ovl, FIO_OVERLAPPED, o);
+ io_u = fov->io_u;
+
+ if (windowsaio_debug) {
+ if (io_u->seen == 1)
+ printf("IoCompletionRoutine - got already completed IO\n");
+ else
+ printf("IoCompletionRoutine - completed %d IO\n", ctx->wd->ioFinished);
+ }
+
+ if (io_u->seen == 1)
+ continue;
+
+ ctx->wd->ioFinished++;
+
+ if (ovl->Internal == ERROR_SUCCESS) {
+ io_u->resid = io_u->xfer_buflen - ovl->InternalHigh;
+ io_u->error = 0;
+ } else {
+ io_u->resid = io_u->xfer_buflen;
+ io_u->error = 1;
+ }
+
+ io_u->seen = 1;
+ CloseHandle(ovl->hEvent);
+ free(ovl);
+ }
+
+ bSuccess = CloseHandle(ctx->ioCP);
+ if (!bSuccess)
+ PrintError(__func__);
+
+ if (windowsaio_debug)
+ printf("windowsaio: IoCompletionRoutine - leave\n");
+
+ ctx->wd->stopped = TRUE;
+ free(ctx);
+ return 0;
+}
+
+static int fio_windowsaio_init(struct thread_data *td)
+{
+ int rc = 0;
+ struct windowsaio_data *wd;
+
+ if (windowsaio_debug)
+ printf("windowsaio: init\n");
+
+ wd = malloc(sizeof(struct windowsaio_data));
+
+ ZeroMemory(wd, sizeof(*wd));
+ wd->aio_events = malloc((td->o.iodepth + 1) * sizeof(struct io_u *));
+ ZeroMemory(wd->aio_events, (td->o.iodepth + 1) * sizeof(struct io_u *));
+
+ td->io_ops->data = wd;
+ return rc;
+}
+
+static int fio_windowsaio_open_file(struct thread_data *td, struct fio_file *f)
+{
+ int rc = 0;
+ HANDLE hFile;
+ DWORD flags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_OVERLAPPED;
+ DWORD sharemode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ DWORD openmode = OPEN_ALWAYS;
+ DWORD access;
+
+ dprint(FD_FILE, "fd open %s\n", f->file_name);
+
+ if (windowsaio_debug)
+ printf("windowsaio: open file %s - enter\n", f->file_name);
+
+ if (f->filetype == FIO_TYPE_PIPE) {
+ log_err("fio: windowsaio doesn't support pipes\n");
+ return 1;
+ }
+
+ if (!strcmp(f->file_name, "-")) {
+ log_err("fio: can't read/write to stdin/out\n");
+ return 1;
+ }
+
+ if (td->o.odirect)
+ flags |= FILE_FLAG_NO_BUFFERING;
+ if (td->o.sync_io)
+ flags |= FILE_FLAG_WRITE_THROUGH;
+
+
+ if (td->o.td_ddir == TD_DDIR_READ ||
+ td->o.td_ddir == TD_DDIR_WRITE ||
+ td->o.td_ddir == TD_DDIR_RANDRW)
+ {
+ flags |= FILE_FLAG_SEQUENTIAL_SCAN;
+ }
+ else
+ {
+ flags |= FILE_FLAG_RANDOM_ACCESS;
+ }
+
+ if (td_read(td) || read_only)
+ access = GENERIC_READ;
+ else
+ access = (GENERIC_READ | GENERIC_WRITE);
+
+ if (td->o.create_on_open > 0)
+ openmode = OPEN_ALWAYS;
+ else
+ openmode = OPEN_EXISTING;
+
+ f->hFile = CreateFile(f->file_name, access, sharemode,
+ NULL, openmode, flags, NULL);
+
+ if (f->hFile == INVALID_HANDLE_VALUE) {
+ log_err("Failed to open %s\n", f->file_name);
+ PrintError(__func__);
+ rc = 1;
+ }
+
+ /* Only set up the competion port and thread if we're not just
+ * querying the device size */
+ if (!rc && td->io_ops->data != NULL) {
+ struct windowsaio_data *wd;
+ struct thread_ctx *ctx;
+ hFile = CreateIoCompletionPort(f->hFile, NULL, 0, 0);
+
+ wd = td->io_ops->data;
+ wd->running = TRUE;
+ wd->stopped = FALSE;
+
+ ctx = malloc(sizeof(struct thread_ctx));
+ ctx->ioCP = hFile;
+ ctx->wd = wd;
+
+ wd->hThread = CreateThread(NULL, 0, IoCompletionRoutine, ctx, 0, NULL);
+
+ if (wd->hThread == NULL) {
+ PrintError(__func__);
+ rc = 1;
+ }
+ }
+
+ if (windowsaio_debug)
+ printf("windowsaio: open file - leave (%d)\n", rc);
+
+ return rc;
+}
+
+static int fio_windowsaio_close_file(struct thread_data fio_unused *td, struct fio_file *f)
+{
+ BOOL bSuccess;
+
+ if (windowsaio_debug)
+ printf("windowsaio: close file\n");
+
+ if (f->hFile != INVALID_HANDLE_VALUE) {
+ bSuccess = CloseHandle(f->hFile);
+ if (!bSuccess)
+ PrintError(__func__);
+ }
+
+ f->hFile = INVALID_HANDLE_VALUE;
+ return 0;
+}
+
+static struct ioengine_ops ioengine = {
+ .name = "windowsaio",
+ .version = FIO_IOOPS_VERSION,
+ .init = fio_windowsaio_init,
+ .queue = fio_windowsaio_queue,
+ .cancel = fio_windowsaio_cancel,
+ .getevents = fio_windowsaio_getevents,
+ .event = fio_windowsaio_event,
+ .cleanup = fio_windowsaio_cleanup,
+ .open_file = fio_windowsaio_open_file,
+ .close_file = fio_windowsaio_close_file,
+ .get_file_size = generic_get_file_size
+};
+
+static void fio_init fio_posixaio_register(void)
+{
+ register_ioengine(&ioengine);
+}
+
+static void fio_exit fio_posixaio_unregister(void)
+{
+ unregister_ioengine(&ioengine);
+}
#ifndef FIO_FILE_H
#define FIO_FILE_H
+#include "compiler/compiler.h"
#include "io_ddir.h"
+#include "flist.h"
/*
* The type of object we are working on
#include "fio.h"
#include "smalloc.h"
#include "filehash.h"
+#include "os/os.h"
static int root_warn;
return 1;
}
- r = blockdev_size(f->fd, &bytes);
+ r = blockdev_size(f, &bytes);
if (r) {
td_verror(td, r, "blockdev_size");
printf("fd is %d\n", f->fd);
return 1;
}
- r = chardev_size(f->fd, &bytes);
+ r = chardev_size(f, &bytes);
if (r) {
td_verror(td, r, "chardev_size");
goto err;
(void) posix_madvise(f->mmap_ptr, f->mmap_sz, FIO_MADV_FREE);
#endif
} else if (f->filetype == FIO_TYPE_FILE) {
- ret = fadvise(f->fd, off, len, POSIX_FADV_DONTNEED);
+ ret = posix_fadvise(f->fd, off, len, POSIX_FADV_DONTNEED);
} else if (f->filetype == FIO_TYPE_BD) {
- ret = blockdev_invalidate_cache(f->fd);
+ ret = blockdev_invalidate_cache(f);
if (ret < 0 && errno == EACCES && geteuid()) {
if (!root_warn) {
log_err("fio: only root may flush block "
f->filetype = FIO_TYPE_FILE;
if (!stat(f->file_name, &sb)) {
- if (S_ISBLK(sb.st_mode))
+ /* \\.\ is the device namespace in Windows, where every file is
+ * a block device */
+ if (S_ISBLK(sb.st_mode) || strncmp(f->file_name, "\\\\.\\", 4) == 0)
f->filetype = FIO_TYPE_BD;
else if (S_ISCHR(sb.st_mode))
f->filetype = FIO_TYPE_CHAR;
evt.sigev_notify = SIGEV_THREAD;
evt.sigev_notify_function = ival_fn;
-#ifndef __CYGWIN__
- if (timer_create(CLOCK_MONOTONIC, &evt, &ival_timer) < 0)
+ if (timer_create(FIO_TIMER_CLOCK, &evt, &ival_timer) < 0)
perror("timer_create");
-#else /* Windows (and thus Cygwin) doesn't have a monotonic clock */
- if (timer_create(CLOCK_REALTIME, &evt, &ival_timer) < 0)
- perror("timer_create");
-#endif
}
#include <inttypes.h>
#include <assert.h>
+struct thread_data;
+
#include "compiler/compiler.h"
#include "flist.h"
#include "fifo.h"
if (lstat(filename, &sb) == -1)
return 0;
- if (S_ISREG(sb.st_mode))
+ /* \\.\ is the device namespace in Windows, where every file
+ * is a device node */
+ if (S_ISREG(sb.st_mode) && strncmp(filename, "\\\\.\\", 4) != 0)
return 0;
return 1;
#include <unistd.h>
#include <string.h>
#include <dlfcn.h>
+#include <fcntl.h>
#include <assert.h>
#include "fio.h"
else
flags = POSIX_FADV_SEQUENTIAL;
- if (fadvise(f->fd, f->file_offset, f->io_size, flags) < 0) {
+ if (posix_fadvise(f->fd, f->file_offset, f->io_size, flags) < 0) {
td_verror(td, errno, "fadvise");
goto err;
}
#define FIO_HAVE_POSIXAIO
#define FIO_HAVE_ODIRECT
#define FIO_USE_GENERIC_RAND
+#define FIO_HAVE_CLOCK_MONOTONIC
/*
* This is broken on AIX if _LARGE_FILES is defined...
#define OS_MAP_ANON MAP_ANON
#define OS_MSG_DONTWAIT 0
-static inline int blockdev_invalidate_cache(int fd)
+static inline int blockdev_invalidate_cache(struct fio_file fio_unused *f)
{
return EINVAL;
}
-static inline int blockdev_size(int fd, unsigned long long *bytes)
+static inline int blockdev_size(struct fio_file *f, unsigned long long *bytes)
{
struct devinfo info;
- if (!ioctl(fd, IOCINFO, &info)) {
+ if (!ioctl(f->fd, IOCINFO, &info)) {
*bytes = (unsigned long long)info.un.scdk.numblks *
info.un.scdk.blksize;
return 0;
#define FIO_HAVE_POSIXAIO
#define FIO_HAVE_ODIRECT
+#define FIO_HAVE_IOPRIO
+#define FIO_HAVE_STRSEP
#define FIO_USE_GENERIC_RAND
#define FIO_HAVE_CHARDEV_SIZE
+#define FIO_HAVE_CLOCK_MONOTONIC
#define OS_MAP_ANON MAP_ANON
typedef off_t off64_t;
-static inline int blockdev_size(int fd, unsigned long long *bytes)
+static inline int blockdev_size(struct fio_file *f, unsigned long long *bytes)
{
off_t size;
- if (!ioctl(fd, DIOCGMEDIASIZE, &size)) {
+ if (!ioctl(f->fd, DIOCGMEDIASIZE, &size)) {
*bytes = size;
return 0;
}
return errno;
}
-static inline int chardev_size(int fd, unsigned long long *bytes)
+static inline int chardev_size(struct fio_file *f, unsigned long long *bytes)
{
- return blockdev_size(fd, bytes);
+ return blockdev_size(f->fd, bytes);
}
-static inline int blockdev_invalidate_cache(int fd)
+static inline int blockdev_invalidate_cache(struct fio_file *f)
{
return EINVAL;
}
#define FIO_HAVE_FS_STAT
#define FIO_HAVE_TRIM
#define FIO_HAVE_BINJECT
+#define FIO_HAVE_CLOCK_MONOTONIC
#ifdef SYNC_FILE_RANGE_WAIT_BEFORE
#define FIO_HAVE_SYNC_FILE_RANGE
#define BLKDISCARD _IO(0x12,119)
#endif
-static inline int blockdev_invalidate_cache(int fd)
+static inline int blockdev_invalidate_cache(struct fio_file *fd)
{
- return ioctl(fd, BLKFLSBUF);
+ return ioctl(f->fd, BLKFLSBUF);
}
-static inline int blockdev_size(int fd, unsigned long long *bytes)
+static inline int blockdev_size(struct fio_file *f, unsigned long long *bytes)
{
- if (!ioctl(fd, BLKGETSIZE64, bytes))
+ if (!ioctl(f->fd, BLKGETSIZE64, bytes))
return 0;
return errno;
#endif
#define FIO_HAVE_POSIXAIO
+#define FIO_HAVE_CLOCK_MONOTONIC
#define FIO_USE_GENERIC_BDEV_SIZE
#define FIO_USE_GENERIC_RAND
typedef unsigned int clockid_t;
typedef off_t off64_t;
-static inline int blockdev_invalidate_cache(int fd)
+static inline int blockdev_invalidate_cache(struct fio_file fio_unused *f)
{
return EINVAL;
}
#define FIO_HAVE_POSIXAIO
#define FIO_HAVE_FADVISE
-#define fadvise posix_fadvise /* XXX NetBSD doesn't have fadvise */
#define FIO_HAVE_ODIRECT
#define FIO_HAVE_STRSEP
#define FIO_HAVE_FDATASYNC
+#define FIO_HAVE_CLOCK_MONOTONIC
#define FIO_USE_GENERIC_BDEV_SIZE
#define FIO_USE_GENERIC_RAND
typedef off_t off64_t;
-static inline int blockdev_invalidate_cache(int fd)
+static inline int blockdev_invalidate_cache(struct fio_file fio_unused *f)
{
return EINVAL;
}
#define FIO_HAVE_PSHARED_MUTEX
#define FIO_USE_GENERIC_BDEV_SIZE
#define FIO_HAVE_FDATASYNC
+#define FIO_HAVE_CLOCK_MONOTONIC
#define OS_MAP_ANON MAP_ANON
#define OS_RAND_MAX 2147483648UL
typedef psetid_t os_cpu_mask_t;
typedef struct solaris_rand_seed os_random_state_t;
-static inline int blockdev_invalidate_cache(int fd)
+static inline int blockdev_invalidate_cache(struct fio_file fio_unused *f)
{
return EINVAL;
}
\r
#include <sys/types.h>\r
#include <errno.h>\r
+#include <windows.h>\r
\r
+#include "../smalloc.h"\r
+#include "../file.h"\r
+#include "../log.h"\r
\r
#define FIO_HAVE_ODIRECT\r
#define FIO_USE_GENERIC_RAND\r
#define FIO_HAVE_FDATASYNC\r
#define FIO_HAVE_WINDOWSAIO\r
\r
-/* TODO add support for FIO_HAVE_CPU_AFFINITY */\r
-\r
#define OS_MAP_ANON MAP_ANON\r
\r
-typedef off_t off64_t;\r
-\r
-\r
-#define FIO_NOTUNIX\r
-\r
-#include <windows.h>\r
-#include <io.h>\r
+#define OS_CLOCK CLOCK_REALTIME\r
\r
-typedef void* HANDLE;\r
-\r
-BOOL WINAPI GetFileSizeEx(\r
- HANDLE hFile,\r
- PLARGE_INTEGER lpFileSize\r
-);\r
-\r
-long _get_osfhandle(\r
- int fd\r
-);\r
+typedef off_t off64_t;\r
\r
typedef struct {\r
LARGE_INTEGER Length;\r
\r
#define IOCTL_DISK_GET_LENGTH_INFO 0x7405C\r
\r
-\r
-static inline int blockdev_size(int fd, unsigned long long *bytes)\r
+static inline int blockdev_size(struct fio_file *f, unsigned long long *bytes)\r
{\r
int rc = 0;\r
- HANDLE hFile = (HANDLE)_get_osfhandle(fd);\r
- if (hFile != INVALID_HANDLE_VALUE)\r
- {\r
- GET_LENGTH_INFORMATION info;\r
- DWORD outBytes;\r
- LARGE_INTEGER size;\r
- size.QuadPart = 0;\r
- if (DeviceIoControl(hFile, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &info, sizeof(info), &outBytes, NULL))\r
- *bytes = info.Length.QuadPart;\r
- else\r
- rc = EIO;\r
+ HANDLE hFile;\r
+\r
+ if (f->hFile == NULL) {\r
+ hFile = CreateFile(f->file_name, (GENERIC_READ | GENERIC_WRITE),\r
+ (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, 0, NULL);\r
+ } else {\r
+ hFile = f->hFile;\r
}\r
\r
- return 0;\r
+ GET_LENGTH_INFORMATION info;\r
+ DWORD outBytes;\r
+ LARGE_INTEGER size;\r
+ size.QuadPart = 0;\r
+ if (DeviceIoControl(hFile, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &info, sizeof(info), &outBytes, NULL))\r
+ *bytes = info.Length.QuadPart;\r
+ else\r
+ rc = EIO;\r
+ }\r
+\r
+ /* If we were passed a POSIX fd,\r
+ * close the HANDLE we created via CreateFile */\r
+ if (hFile != INVALID_HANDLE_VALUE && f->hFile == NULL)\r
+ CloseHandle(hFile);\r
+\r
+ return rc;\r
}\r
\r
-static inline int chardev_size(int fd, unsigned long long *bytes)\r
+static inline int chardev_size(struct fio_file *f, unsigned long long *bytes)\r
{\r
- return blockdev_size(fd, bytes);\r
+ return blockdev_size(f, bytes);\r
}\r
\r
-static inline int blockdev_invalidate_cache(int fd)\r
{\r
- int rc = 0;\r
- HANDLE hFile = (HANDLE)_get_osfhandle(fd);\r
\r
- if (hFile != INVALID_HANDLE_VALUE)\r
- FlushFileBuffers(hFile);\r
- else\r
- rc = EIO;\r
+static inline int blockdev_invalidate_cache(struct fio_file *f)\r
+{\r
+ BOOL bSuccess = FlushFileBuffers(f->hFile);\r
+ if (!bSuccess)\r
+ log_info("blockdev_invalidate_cache - FlushFileBuffers failed\n");\r
\r
- return rc;\r
+ return 0;\r
}\r
\r
static inline unsigned long long os_phys_mem(void)\r
#include <sys/types.h>
#include <pthread.h>
#include <unistd.h>
+#include <stdlib.h>
#if defined(__linux__)
#include "os-linux.h"
#endif
#ifndef FIO_HAVE_FADVISE
-#define fadvise(fd, off, len, advice) (0)
+#define posix_fadvise(fd, off, len, advice) (0)
#ifndef POSIX_FADV_DONTNEED
#define POSIX_FADV_DONTNEED (0)
#define OS_RAND_MAX RAND_MAX
#endif
+#ifdef FIO_HAVE_CLOCK_MONOTONIC
+#define FIO_TIMER_CLOCK CLOCK_MONOTONIC
+#else
+#define FIO_TIMER_CLOCK CLOCK_REALTIME
+#endif
+
#ifndef FIO_HAVE_RAWBIND
#define fio_lookup_raw(dev, majdev, mindev) 1
#endif
}
#ifdef FIO_USE_GENERIC_BDEV_SIZE
-static inline int blockdev_size(int fd, unsigned long long *bytes)
+static inline int blockdev_size(struct fio_file *f, unsigned long long *bytes)
{
off_t end;
*bytes = 0;
- end = lseek(fd, 0, SEEK_END);
+ end = lseek(f->fd, 0, SEEK_END);
if (end < 0)
return errno;
--- /dev/null
+#define FIO_VERSION_MAJOR 1\r
+#define FIO_VERSION_MINOR 44\r
+#define FIO_VERSION_BUILD 3\r
+#define FIO_VERSION_STRING "1.44.3"\r
-#include "../../version.h"\r
+#include "version.h"\r
1 VERSIONINFO\r
-FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,0\r
-PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,0\r
+FILEVERSION FIO_VERSION_MAJOR,FIO_VERSION_MINOR,FIO_VERSION_BUILD,0\r
+PRODUCTVERSION FIO_VERSION_MAJOR,FIO_VERSION_MINOR,FIO_VERSION_BUILD,0\r
BEGIN\r
BLOCK "StringFileInfo"\r
BEGIN\r
BEGIN\r
VALUE "CompanyName", ""\r
VALUE "FileDescription", "Flexible IO Tester"\r
- VALUE "FileVersion", "1.44.3"\r
+ VALUE "FileVersion", FIO_VERSION_STRING\r
VALUE "InternalName", "fio"\r
VALUE "LegalCopyright", "Copyright (C) 2010"\r
VALUE "OriginalFilename", "fio.exe"\r
VALUE "ProductName", "FIO"\r
- VALUE "ProductVersion", VERSION_STR\r
+ VALUE "ProductVersion", FIO_VERSION_STRING\r
END\r
END\r
BLOCK "VarFileInfo"\r