/* * ioping -- simple I/0 latency measuring tool * * Copyright (C) 2011-2015 Konstantin Khlebnikov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef VERSION # define VERSION "1.0" #endif #ifndef EXTRA_VERSION # define EXTRA_VERSION "" #endif #define _GNU_SOURCE #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __linux__ # include # include # include # define HAVE_CLOCK_GETTIME # define HAVE_POSIX_FADVICE # define HAVE_POSIX_MEMALIGN # define HAVE_MKOSTEMP # define HAVE_DIRECT_IO # define HAVE_LINUX_ASYNC_IO # define HAVE_ERR_INCLUDE # define MAX_RW_COUNT 0x7ffff000 /* 2G - 4K */ #endif #ifdef __gnu_hurd__ # include # define HAVE_CLOCK_GETTIME # define HAVE_POSIX_MEMALIGN # define HAVE_MKOSTEMP # define HAVE_ERR_INCLUDE #endif #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) # include # include # include # define HAVE_CLOCK_GETTIME # define HAVE_MKOSTEMP # define HAVE_DIRECT_IO # define HAVE_ERR_INCLUDE #endif #ifdef __DragonFly__ # include # define HAVE_CLOCK_GETTIME # define HAVE_MKOSTEMP # define HAVE_ERR_INCLUDE #endif #ifdef __OpenBSD__ # include # include # include # include # include # define HAVE_CLOCK_GETTIME # define HAVE_POSIX_MEMALIGN # define HAVE_MKOSTEMP # define HAVE_ERR_INCLUDE #endif #ifdef __APPLE__ /* OS X */ # include # include # include # include # define HAVE_NOCACHE_IO # define HAVE_ERR_INCLUDE #endif #ifdef __sun /* Solaris */ # include # include # define HAVE_CLOCK_GETTIME # define HAVE_DIRECT_IO # define O_DIRECT O_DSYNC # define HAVE_ERR_INCLUDE #endif #ifdef __MINGW32__ /* Windows */ # include # include # include # define HAVE_DIRECT_IO # define HAVE_MKOSTEMP /* not required */ #endif #if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 # define HAVE_POSIX_FDATASYNC #endif #ifdef HAVE_ERR_INCLUDE # include #else #define ERR_PREFIX "ioping: " void err(int eval, const char* fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, ERR_PREFIX); vfprintf(stderr, fmt, ap); fprintf(stderr, ": %s\n", strerror(errno)); va_end(ap); exit(eval); } void errx(int eval, const char* fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, ERR_PREFIX); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); exit(eval); } void warnx(const char* fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, ERR_PREFIX); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); } #endif /* HAVE_ERR_INCLUDE */ #define NSEC_PER_SEC 1000000000ll #ifdef HAVE_CLOCK_GETTIME static inline long long now(void) { struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts)) { err(3, "clock_gettime failed"); } return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; } #else static inline long long now(void) { struct timeval tv; if (gettimeofday(&tv, NULL)) { err(3, "gettimeofday failed"); } return tv.tv_sec * NSEC_PER_SEC + tv.tv_usec * 1000ll; } #endif /* HAVE_CLOCK_GETTIME */ #ifndef HAVE_MKOSTEMP int mkostemp(char* template, int flags) { int fd; fd = mkstemp(template); if (!flags || fd < 0) { return fd; } close(fd); return open(template, O_RDWR | flags); } #endif int async = 0; #ifdef __MINGW32__ ssize_t pread(int fd, void* buf, size_t count, off_t offset) { HANDLE h = (HANDLE)_get_osfhandle(fd); DWORD r; OVERLAPPED o; memset(&o, 0, sizeof(o)); o.Offset = offset; o.OffsetHigh = offset >> 32; if (ReadFile(h, buf, count, &r, &o)) { return r; } if (async && GetLastError() == ERROR_IO_PENDING && GetOverlappedResult(h, &o, &r, TRUE)) { return r; } return -1; } ssize_t pwrite(int fd, void* buf, size_t count, off_t offset) { HANDLE h = (HANDLE)_get_osfhandle(fd); DWORD r; OVERLAPPED o; memset(&o, 0, sizeof(o)); o.Offset = offset; o.OffsetHigh = offset >> 32; if (WriteFile(h, buf, count, &r, &o)) { return r; } if (async && GetLastError() == ERROR_IO_PENDING && GetOverlappedResult(h, &o, &r, TRUE)) { return r; } return -1; } int fsync(int fd) { HANDLE h = (HANDLE)_get_osfhandle(fd); return FlushFileBuffers(h) ? 0 : -1; } void srandom(unsigned int seed) { srand(seed); } long int random(void) { return rand() * (RAND_MAX + 1) + rand(); } int nanosleep(const struct timespec* req, struct timespec* rem) { (void)rem; Sleep(req->tv_sec * 1000 + req->tv_nsec / 1000000); return 0; } #endif /* __MINGW32__ */ #ifndef HAVE_POSIX_MEMALIGN /* don't free it */ int posix_memalign(void** memptr, size_t alignment, size_t size) { char* ptr; ptr = malloc(size + alignment); if (!ptr) { return -ENOMEM; } *memptr = ptr + alignment - (size_t)ptr % alignment; return 0; } #endif #ifndef HAVE_POSIX_FDATASYNC int fdatasync(int fd) { return fsync(fd); } #endif void usage(void) { fprintf(stderr, " Usage: ioping [-ABCDRLWYykq] [-c count] [-i interval] [-s size] [-S wsize]\n" " [-o offset] [-w deadline] [-pP period] directory|file|device\n" " ioping -h | -v\n" "\n" " -c stop after requests\n" " -i interval between requests (1s)\n" " -l speed limit in bytes per second\n" " -t