diff --git a/f3read.c b/f3read.c index aea2f9e..4d31f82 100644 --- a/f3read.c +++ b/f3read.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -28,6 +27,17 @@ static uint64_t offset_from_filename(const char *filename) return number * GIGABYTES; } +static inline void update_dt(struct timeval *dt, const struct timeval *t1, + const struct timeval *t2) +{ + dt->tv_sec += t2->tv_sec - t1->tv_sec; + dt->tv_usec += t2->tv_usec - t1->tv_usec; + if (dt->tv_usec >= 1000000) { + dt->tv_sec++; + dt->tv_usec -= 1000000; + } +} + #define TOLERANCE 2 #define PRINT_STATUS(s) printf("%s%7" PRIu64 "/%9" PRIu64 "/%7" PRIu64 "/%7" \ @@ -57,8 +67,7 @@ static void validate_file(const char *path, const char *filename, /* Progress time. */ struct timeval pt1 = { .tv_sec = -1000, .tv_usec = 0 }; - *ptr_ok = *ptr_corrupted = *ptr_changed = *ptr_overwritten = - *ptr_size = 0; + *ptr_ok = *ptr_corrupted = *ptr_changed = *ptr_overwritten = 0; printf("Validating file %s ... %s", filename, progress ? BLANK : ""); fflush(stdout); @@ -130,7 +139,8 @@ static void validate_file(const char *path, const char *filename, *read_all = feof(f); assert(*read_all || errno == EIO); - *ptr_size += ftell(f); + *ptr_size = ftell(f); + assert(*ptr_size >= 0); fclose(f); tail_msg = read_all ? "" : " - NOT fully read"; @@ -145,6 +155,13 @@ static void report(const char *prefix, uint64_t i) printf("%s %.2f %s (%" PRIu64 " sectors)\n", prefix, f, unit, i); } +static inline double dt_to_s(struct timeval *dt) +{ + double ret = (double)dt->tv_sec + ((double)dt->tv_usec / 1000000.); + assert(ret >= 0); + return ret > 0 ? ret : 1; +} + static int iterate_path(const char *path, int progress) { DIR *ptr_dir; diff --git a/f3write.c b/f3write.c index 05d2283..2a8faae 100644 --- a/f3write.c +++ b/f3write.c @@ -22,7 +22,7 @@ static uint64_t fill_buffer(void *buf, size_t size, uint64_t offset) uint8_t *p, *ptr_next_sector, *ptr_end; struct drand48_data state; - /* Assumed that size is not zero and a sector-size multiple. */ + assert(size > 0); assert(size % SECTOR_SIZE == 0); p = buf; @@ -33,7 +33,7 @@ static uint64_t fill_buffer(void *buf, size_t size, uint64_t offset) ptr_next_sector = p + SECTOR_SIZE; p += sizeof(offset); for (; p < ptr_next_sector; p += sizeof(long int)) - lrand48_r(&state, (long int *) p); + lrand48_r(&state, (long int *)p); assert(p == ptr_next_sector); offset += SECTOR_SIZE; } @@ -48,7 +48,7 @@ struct flow { uint64_t total_written; /* If true, show progress. */ int progress; - /* Writing rate. */ + /* Writing rate in bytes. */ int block_size; /* Blocks to write before measurement. */ int blocks_per_delay; @@ -87,6 +87,7 @@ static inline void init_flow(struct flow *fw, uint64_t total_size, int progress) fw->measured_blocks = 0; fw->state = FW_START; fw->erase = 0; + assert(fw->block_size > 0); assert(fw->block_size % SECTOR_SIZE == 0); } @@ -113,6 +114,7 @@ static void erase(int count) repeat_ch('\b', count); } +/* Average writing speed in byte/s. */ static inline double get_avg_speed(struct flow *fw) { return (double)(fw->measured_blocks * fw->block_size * 1000) / @@ -178,7 +180,15 @@ static void measure(int fd, struct flow *fw) fw->bpd1 = fw->blocks_per_delay / 2; fw->bpd2 = fw->blocks_per_delay; fw->blocks_per_delay = (fw->bpd1 + fw->bpd2) / 2; - assert(fw->bpd1 > 0); + assert(fw->bpd1 >= 0); + /* The following should be true only when the kernel + * is already too busy with the device. + */ + if (fw->bpd1 == 0) { + fw->bpd1++; + fw->bpd2++; + fw->blocks_per_delay++; + } fw->state = FW_SEARCH; } else if (delay < fw->delay_ms) { fw->blocks_per_delay *= 2; @@ -318,7 +328,7 @@ static int create_and_fill_file(const char *path, int number, size_t size, static inline uint64_t get_freespace(const char *path) { struct statvfs fs; - assert(statvfs(path, &fs) == 0); + assert(!statvfs(path, &fs)); return (uint64_t)fs.f_frsize * (uint64_t)fs.f_bfree; } @@ -342,6 +352,15 @@ static int fill_fs(const char *path, int progress) return 1; } + /* This sync is just to minimize the chance we'll misestimate + * the writting speed, especially at beginning that can slow down + * the whole process. + * This issue was spotted on a large pen drive in which all fff files + * were removed by function unlink_old_files, but the metadata + * wasn't properly flushed before reaching here. + */ + sync(); + init_flow(&fw, free_space, progress); i = 0; fine = 1; diff --git a/utils.c b/utils.c index 1a6ab18..ff2f8d7 100644 --- a/utils.c +++ b/utils.c @@ -2,11 +2,11 @@ const char *adjust_unit(double *ptr_bytes) { - char *units[] = { "Byte", "KB", "MB", "GB", "TB" }; + const char *units[] = { "Byte", "KB", "MB", "GB", "TB", "PB", "EB" }; int i = 0; double final = *ptr_bytes; - while (i < 5 && final >= 1024) { + while (i < 7 && final >= 1024) { final /= 1024; i++; } @@ -14,7 +14,7 @@ const char *adjust_unit(double *ptr_bytes) return units[i]; } -#ifndef APPLE_MAC +#ifdef APPLE_MAC #include #include diff --git a/utils.h b/utils.h index eae9e43..3e0b658 100644 --- a/utils.h +++ b/utils.h @@ -27,24 +27,6 @@ static inline void get_full_fn(char *full_fn, int len, assert(snprintf(full_fn, len, "%s/%s", path, filename) < len); } -static inline void update_dt(struct timeval *dt, const struct timeval *t1, - const struct timeval *t2) -{ - dt->tv_sec += t2->tv_sec - t1->tv_sec; - dt->tv_usec += t2->tv_usec - t1->tv_usec; - if (dt->tv_usec >= 1000000) { - dt->tv_sec++; - dt->tv_usec -= 1000000; - } -} - -static inline double dt_to_s(struct timeval *dt) -{ - double ret = (double)dt->tv_sec + ((double)dt->tv_usec / 1000000.); - assert(ret >= 0.); - return ret > 0. ? ret : 1.; -} - static inline long delay_ms(const struct timeval *t1, const struct timeval *t2) { return (t2->tv_sec - t1->tv_sec) * 1000 +