The following changes since commit d5e3f5d8ef7fab70288aa57c8660bc3d2199655f: Add info log on whether tsc is reliable or not for --cpuclock-test (2013-01-18 20:13:45 +0100) are available in the git repository at: git://git.kernel.dk/fio.git master Bruce Cran (1): Fix _SC_NPROCESSORS_ONLN on Windows Jens Axboe (9): gettime: use proper uint64_t types where needed lfsr: add lfsr_reset() axmap: clear map->first_free when we reset it Re-seed random generator when a file is reset verify: add new experimental mode that requires no meta data Add generic hweight helpers Add hweight64() windows: use hweight64(), it's a 64-bit type Use unsigned long long for the uint64_t type Makefile | 2 +- backend.c | 46 +++++++++++++++++++++++++++++++++------------- file.h | 9 +-------- filesetup.c | 14 ++++++++++++-- fio.h | 1 + gettime.c | 16 ++++++++-------- io_u.c | 14 +++++++++++--- ioengines.c | 2 +- lib/axmap.c | 3 ++- lib/hweight.c | 33 +++++++++++++++++++++++++++++++++ lib/hweight.h | 10 ++++++++++ lib/lfsr.c | 18 +++++++++++++----- lib/lfsr.h | 1 + libfio.c | 2 +- options.c | 5 +++++ os/windows/posix.c | 45 +++++++++++++++++++++++++++++++++++++++------ verify.c | 9 +-------- 17 files changed, 173 insertions(+), 57 deletions(-) create mode 100644 lib/hweight.c create mode 100644 lib/hweight.h --- Diff of recent changes: diff --git a/Makefile b/Makefile index 03e46fa..967996d 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ SOURCE := gettime.c fio.c ioengines.c init.c stat.c log.c time.c filesetup.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 + helpers.c lib/flist_sort.c lib/hweight.c ifdef CONFIG_64BIT_LLP64 CFLAGS += -DBITS_PER_LONG=32 diff --git a/backend.c b/backend.c index 7cebf4d..507faa9 100644 --- a/backend.c +++ b/backend.c @@ -393,11 +393,12 @@ static int break_on_this_error(struct thread_data *td, enum fio_ddir ddir, * The main verify engine. Runs over the writes we previously submitted, * reads the blocks back in, and checks the crc/md5 of the data. */ -static void do_verify(struct thread_data *td) +static void do_verify(struct thread_data *td, uint64_t verify_bytes) { struct fio_file *f; struct io_u *io_u; int ret, min_events; + uint64_t io_bytes; unsigned int i; dprint(FD_VERIFY, "starting loop\n"); @@ -421,6 +422,7 @@ static void do_verify(struct thread_data *td) td_set_runstate(td, TD_VERIFYING); io_u = NULL; + io_bytes = 0; while (!td->terminate) { enum fio_ddir ddir; int ret2, full; @@ -438,18 +440,27 @@ static void do_verify(struct thread_data *td) if (flow_threshold_exceeded(td)) continue; - io_u = __get_io_u(td); - if (!io_u) - break; + if (!td->o.experimental_verify) { + io_u = __get_io_u(td); + if (!io_u) + break; - if (get_next_verify(td, io_u)) { - put_io_u(td, io_u); - break; - } + if (get_next_verify(td, io_u)) { + put_io_u(td, io_u); + break; + } - if (td_io_prep(td, io_u)) { - put_io_u(td, io_u); - break; + if (td_io_prep(td, io_u)) { + put_io_u(td, io_u); + break; + } + } else { + io_u = get_io_u(td); + if (!io_u) + break; + + if (io_u->buflen + io_bytes > verify_bytes) + break; } if (td->o.verify_async) @@ -480,6 +491,7 @@ static void do_verify(struct thread_data *td) io_u->xfer_buflen = io_u->resid; io_u->xfer_buf += bytes; io_u->offset += bytes; + io_bytes += bytes; if (ddir_rw(io_u->ddir)) td->ts.short_io_u[io_u->ddir]++; @@ -495,6 +507,7 @@ sync_done: if (ret < 0) break; } + io_bytes += io_u->xfer_buflen; continue; case FIO_Q_QUEUED: break; @@ -529,15 +542,18 @@ sync_done: min_events = 1; do { + unsigned long bytes = 0; + /* * Reap required number of io units, if any, * and do the verification on them through * the callback handler */ - if (io_u_queued_complete(td, min_events, NULL) < 0) { + if (io_u_queued_complete(td, min_events, &bytes) < 0) { ret = -1; break; } + io_bytes += bytes; } while (full && (td->cur_depth > td->o.iodepth_low)); } if (ret < 0) @@ -1174,6 +1190,8 @@ static void *thread_main(void *data) clear_state = 0; while (keep_running(td)) { + uint64_t write_bytes; + fio_gettime(&td->start, NULL); memcpy(&td->bw_sample_time, &td->start, sizeof(td->start)); memcpy(&td->iops_sample_time, &td->start, sizeof(td->start)); @@ -1194,7 +1212,9 @@ static void *thread_main(void *data) prune_io_piece_log(td); + write_bytes = td->io_bytes[DDIR_WRITE]; do_io(td); + write_bytes = td->io_bytes[DDIR_WRITE] - write_bytes; clear_state = 1; @@ -1223,7 +1243,7 @@ static void *thread_main(void *data) fio_gettime(&td->start, NULL); - do_verify(td); + do_verify(td, write_bytes); td->ts.runtime[DDIR_READ] += utime_since_now(&td->start); diff --git a/file.h b/file.h index 5f125c3..95ecefe 100644 --- a/file.h +++ b/file.h @@ -175,13 +175,6 @@ extern int init_random_map(struct thread_data *); extern void dup_files(struct thread_data *, struct thread_data *); extern int get_fileno(struct thread_data *, const char *); extern void free_release_files(struct thread_data *); - -static inline void fio_file_reset(struct fio_file *f) -{ - f->last_pos = f->file_offset; - f->last_start = -1ULL; - if (f->io_axmap) - axmap_reset(f->io_axmap); -} +void fio_file_reset(struct thread_data *, struct fio_file *); #endif diff --git a/filesetup.c b/filesetup.c index 478bda8..d0aef21 100644 --- a/filesetup.c +++ b/filesetup.c @@ -1073,7 +1073,7 @@ int add_file(struct thread_data *td, const char *fname) f->fd = -1; f->shadow_fd = -1; - fio_file_reset(f); + fio_file_reset(td, f); if (td->files_size <= td->files_index) { unsigned int new_size = td->o.nr_files + 1; @@ -1319,7 +1319,7 @@ void dup_files(struct thread_data *td, struct thread_data *org) assert(0); } __f->fd = -1; - fio_file_reset(__f); + fio_file_reset(td, __f); if (f->file_name) { __f->file_name = smalloc_strdup(f->file_name); @@ -1359,3 +1359,13 @@ void free_release_files(struct thread_data *td) td->files_index = 0; td->nr_normal_files = 0; } + +void fio_file_reset(struct thread_data *td, struct fio_file *f) +{ + f->last_pos = f->file_offset; + f->last_start = -1ULL; + if (f->io_axmap) + axmap_reset(f->io_axmap); + if (td->o.random_generator == FIO_RAND_GEN_LFSR) + lfsr_reset(&f->lfsr, td->rand_seeds[FIO_RAND_BLOCK_OFF]); +} diff --git a/fio.h b/fio.h index c5e2bf1..ed793ae 100644 --- a/fio.h +++ b/fio.h @@ -159,6 +159,7 @@ struct thread_options { 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; diff --git a/gettime.c b/gettime.c index f29edcb..cc9dcb7 100644 --- a/gettime.c +++ b/gettime.c @@ -21,8 +21,8 @@ int tsc_reliable = 0; struct tv_valid { struct timeval last_tv; + uint64_t last_cycles; int last_tv_valid; - unsigned long last_cycles; }; #ifdef CONFIG_TLS_THREAD static struct tv_valid __thread static_tv_valid; @@ -168,7 +168,7 @@ static void *__fio_gettime(struct timeval *tp) #endif #ifdef ARCH_HAVE_CPU_CLOCK case CS_CPUCLOCK: { - unsigned long long usecs, t; + uint64_t usecs, t; t = get_cpu_clock(); if (tv && t < tv->last_cycles) { @@ -233,7 +233,7 @@ void fio_gettime(struct timeval *tp, void fio_unused *caller) static unsigned long get_cycles_per_usec(void) { struct timeval s, e; - unsigned long long c_s, c_e; + uint64_t c_s, c_e; enum fio_cs old_cs = fio_clock_source; #ifdef CONFIG_CLOCK_GETTIME @@ -245,7 +245,7 @@ static unsigned long get_cycles_per_usec(void) c_s = get_cpu_clock(); do { - unsigned long long elapsed; + uint64_t elapsed; __fio_gettime(&e); @@ -265,7 +265,7 @@ static unsigned long get_cycles_per_usec(void) static void calibrate_cpu_clock(void) { double delta, mean, S; - unsigned long avg, cycles[NR_TIME_ITERS]; + uint64_t avg, cycles[NR_TIME_ITERS]; int i, samples; cycles[0] = get_cycles_per_usec(); @@ -429,9 +429,9 @@ uint64_t time_since_now(struct timeval *s) #define CLOCK_ENTRIES 100000 struct clock_entry { - unsigned long seq; - unsigned long tsc; - unsigned long cpu; + uint64_t seq; + uint64_t tsc; + uint64_t cpu; }; struct clock_thread { diff --git a/io_u.c b/io_u.c index 3de04ef..f020cac 100644 --- a/io_u.c +++ b/io_u.c @@ -183,7 +183,8 @@ static int get_next_rand_offset(struct thread_data *td, struct fio_file *f, * any stored write metadata, just return a random offset */ if (!td->o.verifysort_nr || !(ddir == DDIR_READ && td->o.do_verify && - td->o.verify != VERIFY_NONE && td_random(td))) + td->o.verify != VERIFY_NONE && td_random(td)) || + td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE) return get_off_from_method(td, f, ddir, b); if (!flist_empty(&td->next_rand_list)) { @@ -223,7 +224,7 @@ static int get_next_rand_block(struct thread_data *td, struct fio_file *f, return 0; if (td->o.time_based) { - fio_file_reset(f); + fio_file_reset(td, f); if (!get_next_rand_offset(td, f, ddir, b)) return 0; } @@ -545,6 +546,12 @@ static enum fio_ddir get_rw_ddir(struct thread_data *td) enum fio_ddir ddir; /* + * If verify phase started, it's always a READ + */ + if (td->runstate == TD_VERIFYING) + return DDIR_READ; + + /* * see if it's time to fsync */ if (td->o.fsync_blocks && @@ -1418,7 +1425,8 @@ static void io_completed(struct thread_data *td, struct io_u *io_u, if (td_write(td) && idx == DDIR_WRITE && td->o.do_verify && - td->o.verify != VERIFY_NONE) + td->o.verify != VERIFY_NONE && + !td->o.experimental_verify) log_io_piece(td, io_u); icd->bytes_done[idx] += bytes; diff --git a/ioengines.c b/ioengines.c index a87175a..f81c46f 100644 --- a/ioengines.c +++ b/ioengines.c @@ -397,7 +397,7 @@ int td_io_open_file(struct thread_data *td, struct fio_file *f) return 1; } - fio_file_reset(f); + fio_file_reset(td, f); fio_file_set_open(f); fio_file_clear_closing(f); disk_util_inc(f->du); diff --git a/lib/axmap.c b/lib/axmap.c index a44e0ec..d9ad30b 100644 --- a/lib/axmap.c +++ b/lib/axmap.c @@ -67,6 +67,8 @@ void axmap_reset(struct axmap *axmap) memset(al->map, 0, al->map_size * sizeof(unsigned long)); } + + axmap->first_free = 0; } void axmap_free(struct axmap *axmap) @@ -101,7 +103,6 @@ struct axmap *axmap_new(unsigned long nr_bits) axmap->nr_levels = levels; axmap->levels = smalloc(axmap->nr_levels * sizeof(struct axmap_level)); - axmap->first_free = 0; for (i = 0; i < axmap->nr_levels; i++) { struct axmap_level *al = &axmap->levels[i]; diff --git a/lib/hweight.c b/lib/hweight.c new file mode 100644 index 0000000..2c819d6 --- /dev/null +++ b/lib/hweight.c @@ -0,0 +1,33 @@ +#include "hweight.h" + +unsigned int hweight8(uint8_t w) +{ + unsigned int res = w - ((w >> 1) & 0x55); + + res = (res & 0x33) + ((res >> 2) & 0x33); + return (res + (res >> 4)) & 0x0F; +} + +unsigned int hweight32(uint32_t w) +{ + unsigned int res = w - ((w >> 1) & 0x55555555); + + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res + (res >> 4)) & 0x0F0F0F0F; + res = res + (res >> 8); + return (res + (res >> 16)) & 0x000000FF; +} + +unsigned int hweight64(uint64_t w) +{ +#if BITS_PER_LONG == 32 + return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w); +#else + uint64_t res = w - ((w >> 1) & 0x5555555555555555ULL); + res = (res & 0x3333333333333333ULL) + ((res >> 2) & 0x3333333333333333ULL); + res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0FULL; + res = res + (res >> 8); + res = res + (res >> 16); + return (res + (res >> 32)) & 0x00000000000000FFULL; +#endif +} diff --git a/lib/hweight.h b/lib/hweight.h new file mode 100644 index 0000000..68861dd --- /dev/null +++ b/lib/hweight.h @@ -0,0 +1,10 @@ +#ifndef FIO_HWEIGHT_H +#define FIO_HWEIGHT_H + +#include <inttypes.h> + +unsigned int hweight8(uint8_t w); +unsigned int hweight32(uint32_t w); +unsigned int hweight64(uint64_t w); + +#endif diff --git a/lib/lfsr.c b/lib/lfsr.c index 975c6a5..61a3aaf 100644 --- a/lib/lfsr.c +++ b/lib/lfsr.c @@ -244,6 +244,17 @@ static struct lfsr_taps *find_lfsr(uint64_t size) return NULL; } +void lfsr_reset(struct fio_lfsr *fl, unsigned long seed) +{ + unsigned int i; + + fl->last_val = seed; + fl->num_vals = 0; + + for (i = 0; i < FIO_LFSR_CRANKS; i++) + fl->last_val = __lfsr_next(fl->last_val, &fl->taps); +} + int lfsr_init(struct fio_lfsr *fl, uint64_t size, unsigned long seed) { struct lfsr_taps *tap; @@ -253,18 +264,15 @@ int lfsr_init(struct fio_lfsr *fl, uint64_t size, unsigned long seed) if (!tap) return 1; - fl->last_val = seed; fl->max_val = size - 1; - fl->num_vals = 0; fl->taps.length = tap->length; + for (i = 0; i < FIO_MAX_TAPS; i++) { fl->taps.taps[i] = tap->taps[i]; if (!fl->taps.taps[i]) break; } - for (i = 0; i < FIO_LFSR_CRANKS; i++) - fl->last_val = __lfsr_next(fl->last_val, &fl->taps); - + lfsr_reset(fl, seed); return 0; } diff --git a/lib/lfsr.h b/lib/lfsr.h index 898646e..45d7028 100644 --- a/lib/lfsr.h +++ b/lib/lfsr.h @@ -20,5 +20,6 @@ struct fio_lfsr { int lfsr_next(struct fio_lfsr *fl, uint64_t *off, uint64_t); int lfsr_init(struct fio_lfsr *fl, uint64_t size, unsigned long seed); +void lfsr_reset(struct fio_lfsr *fl, unsigned long seed); #endif diff --git a/libfio.c b/libfio.c index 96ae814..8255072 100644 --- a/libfio.c +++ b/libfio.c @@ -82,7 +82,7 @@ static void reset_io_counters(struct thread_data *td) /* * reset file done count if we are to start over */ - if (td->o.time_based || td->o.loops) + if (td->o.time_based || td->o.loops || td->o.do_verify) td->nr_done_files = 0; } diff --git a/options.c b/options.c index 8d460be..2b71abd 100644 --- a/options.c +++ b/options.c @@ -1961,6 +1961,11 @@ static struct fio_option options[FIO_MAX_OPTS] = { .parent = "verify_async", }, #endif + { + .name = "experimental_verify", + .off1 = td_var_offset(experimental_verify), + .type = FIO_OPT_BOOL, + }, #ifdef FIO_HAVE_TRIM { .name = "trim_percentage", diff --git a/os/windows/posix.c b/os/windows/posix.c index 8b45147..f5d5300 100755 --- a/os/windows/posix.c +++ b/os/windows/posix.c @@ -20,6 +20,7 @@ #include <sys/poll.h> #include "../os-windows.h" +#include "../../lib/hweight.h" extern unsigned long mtime_since_now(struct timeval *); extern void fio_gettime(struct timeval *, void *); @@ -42,20 +43,52 @@ int vsprintf_s( const char *format, va_list argptr); +int GetNumLogicalProcessors(void) +{ + SYSTEM_LOGICAL_PROCESSOR_INFORMATION *processor_info = NULL; + DWORD len = 0; + DWORD num_processors = 0; + DWORD error = 0; + DWORD i; + + while (!GetLogicalProcessorInformation(processor_info, &len)) { + error = GetLastError(); + if (error == ERROR_INSUFFICIENT_BUFFER) + processor_info = malloc(len); + else { + log_err("Error: GetLogicalProcessorInformation failed: %d\n", error); + return -1; + } + + if (processor_info == NULL) { + log_err("Error: failed to allocate memory for GetLogicalProcessorInformation"); + return -1; + } + } + + for (i = 0; i < len / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); i++) + { + if (processor_info[i].Relationship == RelationProcessorCore) + num_processors += hweight64(processor_info[i].ProcessorMask); + } + + free(processor_info); + return num_processors; +} + long sysconf(int name) { - long long val = -1; - DWORD len; - SYSTEM_LOGICAL_PROCESSOR_INFORMATION processorInfo; + long val = -1; SYSTEM_INFO sysInfo; MEMORYSTATUSEX status; switch (name) { case _SC_NPROCESSORS_ONLN: - len = sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); - GetLogicalProcessorInformation(&processorInfo, &len); - val = len / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); + val = GetNumLogicalProcessors(); + if (val == -1) + log_err("_SC_NPROCESSORS_ONLN failed\n"); + break; case _SC_PAGESIZE: diff --git a/verify.c b/verify.c index c0485d5..cb13b62 100644 --- a/verify.c +++ b/verify.c @@ -13,6 +13,7 @@ #include "smalloc.h" #include "trim.h" #include "lib/rand.h" +#include "lib/hweight.h" #include "crc/md5.h" #include "crc/crc64.h" @@ -308,14 +309,6 @@ static inline void *io_u_verify_off(struct verify_header *hdr, struct vcont *vc) return vc->io_u->buf + vc->hdr_num * hdr->len + hdr_size(hdr); } -static unsigned int hweight8(unsigned int w) -{ - unsigned int res = w - ((w >> 1) & 0x55); - - res = (res & 0x33) + ((res >> 2) & 0x33); - return (res + (res >> 4)) & 0x0F; -} - static int verify_io_u_pattern(struct verify_header *hdr, struct vcont *vc) { struct thread_data *td = vc->td; -- To unsubscribe from this list: send the line "unsubscribe fio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html