From 397c58c41e1fd86c57e18d11023e2ffb8da70416 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Tue, 17 May 2016 23:34:47 +0200 Subject: [PATCH] Add new IO window advise modes --- HISTORY | 11 ++-- Makefile.am | 4 +- cmdline/snapraid.c | 35 +++++------ cmdline/support.c | 142 +++++++++++++++++++++++---------------------- cmdline/support.h | 19 +++--- 5 files changed, 104 insertions(+), 107 deletions(-) diff --git a/HISTORY b/HISTORY index 61b9521f..2e7d906b 100644 --- a/HISTORY +++ b/HISTORY @@ -15,13 +15,12 @@ SnapRAID HISTORY '\'. * Added test options for selecting the file advise mode to use: --test-io-advise-none for standard mode - --test-io-advise-sequential advise sequential operations (Linux/Windows) - --test-io-advise-flush flush data after every operation (Linux) + --test-io-advise-sequential advise sequential access (Linux/Windows) + --test-io-advise-flush flush cache after every operation (Linux) + --test-io-advise-flush-window flush cache every 8 MB (Linux) --test-io-advise-discard discard cache after every operation (Linux) - --test-io-advise-discard-2 discard cache every 2 MB (Linux) - --test-io-advise-discard-8 discard cache every 8 MB (Linux) - --test-io-advise-discard-32 discard cache every 32 MB (Linux) - --test-io-advise-direct use direct mode (Linux/Windows) + --test-io-advise-discard-window discard cache every 8 MB (Linux) + --test-io-advise-direct use direct/unbuffered mode (Linux/Windows) * Fixed running in Windows platforms that miss the RtlGenRandom function. * Added a new 'hashsize' configuration option. It could be useful in diff --git a/Makefile.am b/Makefile.am index 706d8bef..c0bd988a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -439,8 +439,8 @@ endif $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) status $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-io-advise-none -c $(PAR1) sync -F $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-io-advise-sequential -c $(PAR1) sync -F - $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-io-advise-flush -c $(PAR1) sync -F - $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-io-advise-discard -c $(PAR1) sync -F + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-io-advise-flush-window -c $(PAR1) sync -F + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-io-advise-discard-window -c $(PAR1) sync -F #### CHANGE LINKS #### # Use a different size ("22" instead of "1") to ensure to recognize the file different # even if it gets the same timestamp in case subsecond timestamp is no available diff --git a/cmdline/snapraid.c b/cmdline/snapraid.c index 0597231b..d7435900 100644 --- a/cmdline/snapraid.c +++ b/cmdline/snapraid.c @@ -285,11 +285,10 @@ void config(char* conf, size_t conf_size, const char* argv0) #define OPT_TEST_IO_ADVISE_NONE 293 #define OPT_TEST_IO_ADVISE_SEQUENTIAL 294 #define OPT_TEST_IO_ADVISE_FLUSH 295 -#define OPT_TEST_IO_ADVISE_DISCARD 296 -#define OPT_TEST_IO_ADVISE_DISCARD_2 297 -#define OPT_TEST_IO_ADVISE_DISCARD_8 298 -#define OPT_TEST_IO_ADVISE_DISCARD_32 299 -#define OPT_TEST_IO_ADVISE_DIRECT 300 +#define OPT_TEST_IO_ADVISE_FLUSH_WINDOW 296 +#define OPT_TEST_IO_ADVISE_DISCARD 297 +#define OPT_TEST_IO_ADVISE_DISCARD_WINDOW 298 +#define OPT_TEST_IO_ADVISE_DIRECT 299 #define OPT_TEST_PARITY_LIMIT 301 #define OPT_TEST_SKIP_CONTENT_WRITE 302 @@ -434,17 +433,14 @@ struct option long_options[] = { /* Set the io advise to flush */ { "test-io-advise-flush", 0, 0, OPT_TEST_IO_ADVISE_FLUSH }, + /* Set the io advise to flush window */ + { "test-io-advise-flush-window", 0, 0, OPT_TEST_IO_ADVISE_FLUSH_WINDOW }, + /* Set the io advise to discard */ { "test-io-advise-discard", 0, 0, OPT_TEST_IO_ADVISE_DISCARD }, - /* Set the io advise to discard */ - { "test-io-advise-discard-2", 0, 0, OPT_TEST_IO_ADVISE_DISCARD_2 }, - - /* Set the io advise to discard */ - { "test-io-advise-discard-8", 0, 0, OPT_TEST_IO_ADVISE_DISCARD_8 }, - - /* Set the io advise to discard */ - { "test-io-advise-discard-32", 0, 0, OPT_TEST_IO_ADVISE_DISCARD_32 }, + /* Set the io advise to discard window */ + { "test-io-advise-discard-window", 0, 0, OPT_TEST_IO_ADVISE_DISCARD_WINDOW }, /* Set the io advise to direct */ { "test-io-advise-direct", 0, 0, OPT_TEST_IO_ADVISE_DIRECT }, @@ -860,17 +856,14 @@ int main(int argc, char* argv[]) case OPT_TEST_IO_ADVISE_FLUSH : opt.file_mode = ADVISE_FLUSH; break; + case OPT_TEST_IO_ADVISE_FLUSH_WINDOW : + opt.file_mode = ADVISE_FLUSH_WINDOW; + break; case OPT_TEST_IO_ADVISE_DISCARD : opt.file_mode = ADVISE_DISCARD; break; - case OPT_TEST_IO_ADVISE_DISCARD_2 : - opt.file_mode = ADVISE_DISCARD_2; - break; - case OPT_TEST_IO_ADVISE_DISCARD_8 : - opt.file_mode = ADVISE_DISCARD_8; - break; - case OPT_TEST_IO_ADVISE_DISCARD_32 : - opt.file_mode = ADVISE_DISCARD_32; + case OPT_TEST_IO_ADVISE_DISCARD_WINDOW : + opt.file_mode = ADVISE_DISCARD_WINDOW; break; case OPT_TEST_IO_ADVISE_DIRECT : opt.file_mode = ADVISE_DIRECT; diff --git a/cmdline/support.c b/cmdline/support.c index 7a4b68db..0d2552a5 100644 --- a/cmdline/support.c +++ b/cmdline/support.c @@ -895,10 +895,9 @@ int advise_flags(struct advise_struct* advise) if (advise->mode == ADVISE_SEQUENTIAL || advise->mode == ADVISE_FLUSH + || advise->mode == ADVISE_FLUSH_WINDOW || advise->mode == ADVISE_DISCARD - || advise->mode == ADVISE_DISCARD_2 - || advise->mode == ADVISE_DISCARD_8 - || advise->mode == ADVISE_DISCARD_32 + || advise->mode == ADVISE_DISCARD_WINDOW ) flags |= O_SEQUENTIAL; @@ -918,10 +917,9 @@ int advise_open(struct advise_struct* advise, int f) #if HAVE_POSIX_FADVISE if (advise->mode == ADVISE_SEQUENTIAL || advise->mode == ADVISE_FLUSH + || advise->mode == ADVISE_FLUSH_WINDOW || advise->mode == ADVISE_DISCARD - || advise->mode == ADVISE_DISCARD_2 - || advise->mode == ADVISE_DISCARD_8 - || advise->mode == ADVISE_DISCARD_32 + || advise->mode == ADVISE_DISCARD_WINDOW ) { int ret; @@ -939,26 +937,15 @@ int advise_open(struct advise_struct* advise, int f) return 0; } -int advise_write(struct advise_struct* advise, int f, size_t offset, size_t size) +int advise_write(struct advise_struct* advise, int f, uint64_t offset, uint64_t size) { - (void)advise; + uint64_t handle_offset; + uint64_t handle_size; + (void)f; - (void)offset; - (void)size; -#if HAVE_SYNC_FILE_RANGE - if (advise->mode == ADVISE_FLUSH) { - int ret; - - /* start writing immediately */ - ret = sync_file_range(f, offset, size, SYNC_FILE_RANGE_WRITE); - if (ret != 0) { - /* LCOV_EXCL_START */ - return -1; - /* LCOV_EXCL_STOP */ - } - } -#endif + handle_offset = 0; + handle_size = 0; /* * Follow Linus recommendations about fast writes. @@ -1013,54 +1000,74 @@ int advise_write(struct advise_struct* advise, int f, size_t offset, size_t size * --- */ -#if HAVE_SYNC_FILE_RANGE && HAVE_POSIX_FADVISE - if (advise->mode == ADVISE_DISCARD - || advise->mode == ADVISE_DISCARD_2 - || advise->mode == ADVISE_DISCARD_8 - || advise->mode == ADVISE_DISCARD_32 - ) { - size_t dirty_offset = advise->dirty_begin; - size_t dirty_size = advise->dirty_end - advise->dirty_begin; - size_t limit; + if (advise->mode == ADVISE_FLUSH || advise->mode == ADVISE_DISCARD) { + handle_offset = offset; + handle_size = size; + } - switch (advise->mode) { - default: - case ADVISE_DISCARD : limit = 1; break; - case ADVISE_DISCARD_2 : limit = 2 * 1024 * 1024; break; - case ADVISE_DISCARD_8 : limit = 8 * 1024 * 1024; break; - case ADVISE_DISCARD_32 : limit = 32 * 1024 * 1024; break; - } + if (advise->mode == ADVISE_FLUSH_WINDOW || advise->mode == ADVISE_DISCARD_WINDOW) { + /* if the dirty range can be extended */ + if (advise->dirty_end == offset) { + /* extent the dirty range */ + advise->dirty_end += size; - /* if we have to discard */ - if (dirty_size >= limit) { - int ret; + /* if we reached the double window size */ + if (advise->dirty_end - advise->dirty_begin >= 2 * ADVISE_WINDOW_SIZE) { + /* handle the first window */ + handle_offset = advise->dirty_begin; + handle_size = ADVISE_WINDOW_SIZE; - /* send the data to the disk and wait until it's written */ - ret = sync_file_range(f, dirty_offset, dirty_size, SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE | SYNC_FILE_RANGE_WAIT_AFTER); - if (ret != 0) { - /* LCOV_EXCL_START */ - return -1; - /* LCOV_EXCL_STOP */ + /* remove it from the dirty range */ + advise->dirty_begin += ADVISE_WINDOW_SIZE; } + } else { + /* otherwise flush the existing dirty */ + handle_offset = advise->dirty_begin; + handle_size = advise->dirty_end - advise->dirty_begin; - /* flush the data from the cache */ - ret = posix_fadvise(f, dirty_offset, dirty_size, POSIX_FADV_DONTNEED); - if (ret != 0) { - /* LCOV_EXCL_START */ - errno = ret; /* posix_fadvise return the error code */ - return -1; - /* LCOV_EXCL_STOP */ - } - - /* set the new dirty range */ + /* and set the new range as dirty */ advise->dirty_begin = offset; advise->dirty_end = offset + size; - } else { - /* extend the dirty range */ - if (advise->dirty_begin > offset) - advise->dirty_begin = offset; - if (advise->dirty_end < offset + size) - advise->dirty_end = offset + size; + } + } + +#if HAVE_SYNC_FILE_RANGE + if ((advise->mode == ADVISE_FLUSH || advise->mode == ADVISE_FLUSH_WINDOW) + && handle_size != 0 + ) { + int ret; + + /* start writing immediately */ + ret = sync_file_range(f, handle_offset, handle_size, SYNC_FILE_RANGE_WRITE); + if (ret != 0) { + /* LCOV_EXCL_START */ + return -1; + /* LCOV_EXCL_STOP */ + } + } +#endif + +#if HAVE_SYNC_FILE_RANGE && HAVE_POSIX_FADVISE + if ((advise->mode == ADVISE_DISCARD || advise->mode == ADVISE_DISCARD_WINDOW) + && handle_size != 0 + ) { + int ret; + + /* send the data to the disk and wait until it's written */ + ret = sync_file_range(f, handle_offset, handle_size, SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE | SYNC_FILE_RANGE_WAIT_AFTER); + if (ret != 0) { + /* LCOV_EXCL_START */ + return -1; + /* LCOV_EXCL_STOP */ + } + + /* flush the data from the cache */ + ret = posix_fadvise(f, handle_offset, handle_size, POSIX_FADV_DONTNEED); + if (ret != 0) { + /* LCOV_EXCL_START */ + errno = ret; /* posix_fadvise return the error code */ + return -1; + /* LCOV_EXCL_STOP */ } } #endif @@ -1068,7 +1075,7 @@ int advise_write(struct advise_struct* advise, int f, size_t offset, size_t size return 0; } -int advise_read(struct advise_struct* advise, int f, size_t offset, size_t size) +int advise_read(struct advise_struct* advise, int f, uint64_t offset, uint64_t size) { (void)advise; (void)f; @@ -1077,9 +1084,7 @@ int advise_read(struct advise_struct* advise, int f, size_t offset, size_t size) #if HAVE_POSIX_FADVISE if (advise->mode == ADVISE_DISCARD - || advise->mode == ADVISE_DISCARD_2 - || advise->mode == ADVISE_DISCARD_8 - || advise->mode == ADVISE_DISCARD_32 + || advise->mode == ADVISE_DISCARD_WINDOW ) { int ret; @@ -1143,7 +1148,6 @@ int advise_read(struct advise_struct* advise, int f, size_t offset, size_t size) */ static size_t mcounter; - size_t malloc_counter_get(void) { size_t ret; diff --git a/cmdline/support.h b/cmdline/support.h index eafd7a20..f3b543d0 100644 --- a/cmdline/support.h +++ b/cmdline/support.h @@ -332,23 +332,24 @@ int fmtime(int f, int64_t mtime_sec, int mtime_nsec); #define ADVISE_NONE 1 /**< Bare read/write mode. */ #define ADVISE_SEQUENTIAL 2 /**< Sequential mode. */ #define ADVISE_FLUSH 3 /**< Flush mode. */ -#define ADVISE_DISCARD 4 /**< Discard the cache after every operation. */ -#define ADVISE_DISCARD_2 5 /**< Discard the cache every 2MB. */ -#define ADVISE_DISCARD_8 6 /**< Discard the cache every 8MB. */ -#define ADVISE_DISCARD_32 7 /**< Discard the cache every 32MB. */ -#define ADVISE_DIRECT 8 /**< Direct mode. */ +#define ADVISE_FLUSH_WINDOW 4 /**< Flush mode with a window of 8MB. */ +#define ADVISE_DISCARD 5 /**< Discard the cache after every operation. */ +#define ADVISE_DISCARD_WINDOW 6 /**< Discard the cache with a window of 8MB. */ +#define ADVISE_DIRECT 7 /**< Direct mode. */ + +#define ADVISE_WINDOW_SIZE (8 * 1024 * 1024) /**< Window size. */ struct advise_struct { int mode; - size_t dirty_begin; - size_t dirty_end; + uint64_t dirty_begin; + uint64_t dirty_end; }; void advise_init(struct advise_struct* advise, int mode); int advise_flags(struct advise_struct* advise); int advise_open(struct advise_struct* advise, int f); -int advise_write(struct advise_struct* advise, int f, size_t offset, size_t size); -int advise_read(struct advise_struct* advise, int f, size_t offset, size_t size); +int advise_write(struct advise_struct* advise, int f, uint64_t offset, uint64_t size); +int advise_read(struct advise_struct* advise, int f, uint64_t offset, uint64_t size); /****************************************************************************/ /* memory */