From e2c4399e2892a13f3bed608431ff3b1cd20bf7e7 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Wed, 20 Jan 2016 21:30:00 +0100 Subject: [PATCH] More precise disk usage time When we wait, we now count the time for all the waiting disks, and not only for the first one that finish. --- cmdline/dry.c | 18 ++++++++++----- cmdline/io.c | 58 ++++++++++++++++++++++++++++++++++++++++++------- cmdline/io.h | 6 ++--- cmdline/scrub.c | 17 ++++++++++----- cmdline/state.c | 53 ++++++++++++++++++++++++++++++++++++++++++++ cmdline/state.h | 50 +++++++----------------------------------- cmdline/sync.c | 20 ++++++++++------- 7 files changed, 149 insertions(+), 73 deletions(-) diff --git a/cmdline/dry.c b/cmdline/dry.c index 44a06a56..1f098e23 100644 --- a/cmdline/dry.c +++ b/cmdline/dry.c @@ -23,6 +23,7 @@ #include "parity.h" #include "handle.h" #include "io.h" +#include "raid/raid.h" /****************************************************************************/ /* dry */ @@ -179,6 +180,8 @@ static int state_dry_process(struct snapraid_state* state, struct snapraid_parit unsigned error; unsigned io_error; unsigned l; + unsigned* waiting_map; + unsigned waiting_mac; handle = handle_mapping(state, &diskmax); @@ -188,6 +191,8 @@ static int state_dry_process(struct snapraid_state* state, struct snapraid_parit /* initialize the io threads */ io_init(&io, state, state->opt.io_cache, buffermax, dry_data_reader, handle, diskmax, dry_parity_reader, 0, parity_handle, state->level); + waiting_map = malloc_nofail((diskmax + RAID_PARITY_MAX) * sizeof(unsigned)); + error = 0; io_error = 0; @@ -222,7 +227,10 @@ static int state_dry_process(struct snapraid_state* state, struct snapraid_parit state_usage_cpu(state); /* get the next task */ - task = io_data_read(&io, &diskcur); + task = io_data_read(&io, &diskcur, waiting_map, &waiting_mac); + + /* until now is disk */ + state_usage_disk(state, handle, waiting_map, waiting_mac); /* get the task results */ disk = task->disk; @@ -233,9 +241,6 @@ static int state_dry_process(struct snapraid_state* state, struct snapraid_parit if (!disk) continue; - /* until now is disk */ - state_usage_disk(state, disk); - /* if the block is not used */ if (!block_has_file(block)) continue; @@ -285,10 +290,10 @@ static int state_dry_process(struct snapraid_state* state, struct snapraid_parit struct snapraid_task* task; unsigned levcur; - task = io_parity_read(&io, &levcur); + task = io_parity_read(&io, &levcur, waiting_map, &waiting_mac); /* until now is parity */ - state_usage_parity(state, levcur); + state_usage_parity(state, waiting_map, waiting_mac); /* handle error conditions */ if (task->state == TASK_STATE_IOERROR) { @@ -370,6 +375,7 @@ bail: log_fatal("DANGER! Unexpected input/output errors!\n"); free(handle); + free(waiting_map); io_done(&io); if (error + io_error != 0) diff --git a/cmdline/io.c b/cmdline/io.c index d697f66a..4b92e8fe 100644 --- a/cmdline/io.c +++ b/cmdline/io.c @@ -485,8 +485,16 @@ void io_write_next(struct snapraid_io* io, unsigned blockcur, int skip, int* wri #endif } -static struct snapraid_task* io_task_read(struct snapraid_io* io, unsigned base, unsigned count, unsigned* pos) +static struct snapraid_task* io_task_read(struct snapraid_io* io, unsigned base, unsigned count, unsigned* pos, unsigned* waiting_map, unsigned* waiting_mac) { + unsigned waiting_cycle; + + /* count the waiting cycle */ + waiting_cycle = 0; + + /* clear the waiting indexes */ + *waiting_mac = 0; + /* the synchronization is protected by the io mutex */ pthread_mutex_lock(&io->mutex); @@ -512,6 +520,12 @@ static struct snapraid_task* io_task_read(struct snapraid_io* io, unsigned base, if (base <= i && i < base + count) { struct snapraid_worker* worker; + /* if it's the first cycle */ + if (waiting_cycle == 0) { + /* store the waiting indexes */ + waiting_map[(*waiting_mac)++] = i - base; + } + worker = &io->reader_map[i]; /* if the worker has finished this index */ @@ -529,6 +543,10 @@ static struct snapraid_task* io_task_read(struct snapraid_io* io, unsigned base, /* return the position */ *pos = i - base; + /* on the first cycle, no one is waiting */ + if (waiting_cycle == 0) + *waiting_mac = 0; + return task; } } @@ -537,23 +555,34 @@ static struct snapraid_task* io_task_read(struct snapraid_io* io, unsigned base, let = &io->reader_list[i + 1]; } - /* if not worker is ready, wait for an event */ + /* if no worker is ready, wait for an event */ pthread_cond_wait(&io->read_done, &io->mutex); + + /* count the cycles */ + ++waiting_cycle; } } -struct snapraid_task* io_data_read(struct snapraid_io* io, unsigned* pos) +struct snapraid_task* io_data_read(struct snapraid_io* io, unsigned* pos, unsigned* waiting_map, unsigned* waiting_mac) { - return io_task_read(io, io->data_base, io->data_count, pos); + return io_task_read(io, io->data_base, io->data_count, pos, waiting_map, waiting_mac); } -struct snapraid_task* io_parity_read(struct snapraid_io* io, unsigned* pos) +struct snapraid_task* io_parity_read(struct snapraid_io* io, unsigned* pos, unsigned* waiting_map, unsigned* waiting_mac) { - return io_task_read(io, io->parity_base, io->parity_count, pos); + return io_task_read(io, io->parity_base, io->parity_count, pos, waiting_map, waiting_mac); } -void io_parity_write(struct snapraid_io* io, unsigned* pos) +void io_parity_write(struct snapraid_io* io, unsigned* pos, unsigned* waiting_map, unsigned* waiting_mac) { + unsigned waiting_cycle; + + /* count the waiting cycle */ + waiting_cycle = 0; + + /* clear the waiting indexes */ + *waiting_mac = 0; + /* the synchronization is protected by the io mutex */ pthread_mutex_lock(&io->mutex); @@ -578,6 +607,12 @@ void io_parity_write(struct snapraid_io* io, unsigned* pos) if (i == io->writer_max) break; + /* if it's the first cycle */ + if (waiting_cycle == 0) { + /* store the waiting indexes */ + waiting_map[(*waiting_mac)++] = i; + } + worker = &io->writer_map[i]; /* the two indexes cannot be equal */ @@ -594,6 +629,10 @@ void io_parity_write(struct snapraid_io* io, unsigned* pos) /* return the position */ *pos = i; + /* on the first cycle, no one is waiting */ + if (waiting_cycle == 0) + *waiting_mac = 0; + return; } @@ -601,8 +640,11 @@ void io_parity_write(struct snapraid_io* io, unsigned* pos) let = &io->writer_list[i + 1]; } - /* if not worker is ready, wait for an event */ + /* if no worker is ready, wait for an event */ pthread_cond_wait(&io->write_done, &io->mutex); + + /* count the cycles */ + ++waiting_cycle; } } diff --git a/cmdline/io.h b/cmdline/io.h index b3a2e956..dd05ece0 100644 --- a/cmdline/io.h +++ b/cmdline/io.h @@ -329,7 +329,7 @@ block_off_t io_read_next(struct snapraid_io* io, void*** buffer); * \param pos The position of the data block in the ::handle_map vector. * \return The completed task. */ -struct snapraid_task* io_data_read(struct snapraid_io* io, unsigned* diskcur); +struct snapraid_task* io_data_read(struct snapraid_io* io, unsigned* diskcur, unsigned* waiting_map, unsigned* waiting_mac); /** * Read a parity block. @@ -340,7 +340,7 @@ struct snapraid_task* io_data_read(struct snapraid_io* io, unsigned* diskcur); * \param pos The position of the parity block in the ::parity_handle_map vector. * \return The completed task. */ -struct snapraid_task* io_parity_read(struct snapraid_io* io, unsigned* levcur); +struct snapraid_task* io_parity_read(struct snapraid_io* io, unsigned* levcur, unsigned* waiting_map, unsigned* waiting_mac); /** * Write of a parity block. @@ -350,7 +350,7 @@ struct snapraid_task* io_parity_read(struct snapraid_io* io, unsigned* levcur); * \param io InputOutput context. * \param pos The position of the parity block in the ::parity_handle_map vector. */ -void io_parity_write(struct snapraid_io* io, unsigned* levcur); +void io_parity_write(struct snapraid_io* io, unsigned* levcur, unsigned* waiting_map, unsigned* waiting_mac); /** * Next write position. diff --git a/cmdline/scrub.c b/cmdline/scrub.c index a5914cf6..c828a7e4 100644 --- a/cmdline/scrub.c +++ b/cmdline/scrub.c @@ -264,6 +264,8 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par unsigned silent_error; unsigned io_error; unsigned l; + unsigned* waiting_map; + unsigned waiting_mac; /* maps the disks to handles */ handle = handle_mapping(state, &diskmax); @@ -277,6 +279,8 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par /* initialize the io threads */ io_init(&io, state, state->opt.io_cache, buffermax, scrub_data_reader, handle, diskmax, scrub_parity_reader, 0, parity_handle, state->level); + waiting_map = malloc_nofail((diskmax + RAID_PARITY_MAX) * sizeof(unsigned)); + error = 0; silent_error = 0; io_error = 0; @@ -362,7 +366,10 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par state_usage_cpu(state); /* get the next task */ - task = io_data_read(&io, &diskcur); + task = io_data_read(&io, &diskcur, waiting_map, &waiting_mac); + + /* until now is disk */ + state_usage_disk(state, handle, waiting_map, waiting_mac); /* get the task results */ disk = task->disk; @@ -378,9 +385,6 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par if (!disk) continue; - /* until now is disk */ - state_usage_disk(state, disk); - /* if the block is unsynced, errors are expected */ if (block_has_invalid_parity(block)) { /* report that the block and the file are not synced */ @@ -485,10 +489,10 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par struct snapraid_task* task; unsigned levcur; - task = io_parity_read(&io, &levcur); + task = io_parity_read(&io, &levcur, waiting_map, &waiting_mac); /* until now is parity */ - state_usage_parity(state, levcur); + state_usage_parity(state, waiting_map, waiting_mac); /* handle error conditions */ if (task->state == TASK_STATE_IOERROR) { @@ -670,6 +674,7 @@ bail: free(handle); free(rehandle_alloc); + free(waiting_map); io_done(&io); if (state->opt.expect_recoverable) { diff --git a/cmdline/state.c b/cmdline/state.c index 395bf10d..1de43e49 100644 --- a/cmdline/state.c +++ b/cmdline/state.c @@ -24,6 +24,7 @@ #include "support.h" #include "parity.h" #include "stream.h" +#include "handle.h" #include "raid/raid.h" #include "raid/cpu.h" @@ -4032,6 +4033,58 @@ int state_progress(struct snapraid_state* state, block_off_t blockpos, block_off return 0; } +void state_usage_waste(struct snapraid_state* state) +{ + uint64_t now = tick(); + + state->tick_last = now; +} + +void state_usage_cpu(struct snapraid_state* state) +{ + uint64_t now = tick(); + uint64_t delta = now - state->tick_last; + + /* increment the time spent in computations */ + state->tick_cpu += delta; + + state->tick_last = now; +} + +void state_usage_disk(struct snapraid_state* state, struct snapraid_handle* handle_map, unsigned* waiting_map, unsigned waiting_mac) +{ + uint64_t now = tick(); + uint64_t delta = now - state->tick_last; + unsigned i; + + /* increment the time spent in the data disks */ + for (i = 0; i < waiting_mac; ++i) { + struct snapraid_disk* disk = handle_map[waiting_map[i]].disk; + + if (!disk) + continue; + + disk->tick += delta; + } + state->tick_io += delta; + + state->tick_last = now; +} + +void state_usage_parity(struct snapraid_state* state, unsigned* waiting_map, unsigned waiting_mac) +{ + uint64_t now = tick(); + uint64_t delta = now - state->tick_last; + unsigned i; + + /* increment the time spent in the parity disk */ + for (i = 0; i < waiting_mac; ++i) + state->parity[waiting_map[i]].tick += delta; + state->tick_io += delta; + + state->tick_last = now; +} + void state_usage_print(struct snapraid_state* state) { uint64_t tick_total; diff --git a/cmdline/state.h b/cmdline/state.h index be97124c..6ef059db 100644 --- a/cmdline/state.h +++ b/cmdline/state.h @@ -20,6 +20,8 @@ #include "elem.h" +struct snapraid_handle; + /****************************************************************************/ /* parity level */ @@ -333,58 +335,22 @@ void state_progress_restart(struct snapraid_state* state); /** * Set the usage time as wasted one not counted. */ -static inline void state_usage_waste(struct snapraid_state* state) -{ - uint64_t now = tick(); - - state->tick_last = now; -} +void state_usage_waste(struct snapraid_state* state); /** * Set the usage time for CPU. */ -static inline void state_usage_cpu(struct snapraid_state* state) -{ - uint64_t now = tick(); - uint64_t delta = now - state->tick_last; - - /* increment the time spent in computations */ - state->tick_cpu += delta; - - state->tick_last = now; -} +void state_usage_cpu(struct snapraid_state* state); /** - * Set the usage time for data disk. + * Set the usage time for a set of data disks. */ -static inline void state_usage_disk(struct snapraid_state* state, struct snapraid_disk* disk) -{ - uint64_t now = tick(); - uint64_t delta = now - state->tick_last; - - /* increment the time spent in the data disk */ - disk->tick += delta; - state->tick_io += delta; - - state->tick_last = now; -} +void state_usage_disk(struct snapraid_state* state, struct snapraid_handle* handle_map, unsigned* waiting_map, unsigned waiting_mac); /** - * Set the usage time for parity disk. + * Set the usage time for a set of parity disk. */ -static inline void state_usage_parity(struct snapraid_state* state, unsigned level) -{ - uint64_t now = tick(); - uint64_t delta = now - state->tick_last; - - assert(level < LEV_MAX); - - /* increment the time spent in the parity disk */ - state->parity[level].tick += delta; - state->tick_io += delta; - - state->tick_last = now; -} +void state_usage_parity(struct snapraid_state* state, unsigned* waiting_map, unsigned waiting_mac); /** * Print the stats of the usage time. diff --git a/cmdline/sync.c b/cmdline/sync.c index 67230a3e..b597b03a 100644 --- a/cmdline/sync.c +++ b/cmdline/sync.c @@ -244,7 +244,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta } /* until now is disk */ - state_usage_disk(state, disk); + state_usage_disk(state, handle, &j, 1); countsize += read_size; @@ -681,6 +681,8 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari struct failed_struct* failed; int* failed_map; unsigned l; + unsigned* waiting_map; + unsigned waiting_mac; /* the sync process assumes that all the hashes are correct */ /* including the ones from CHG and DELETED blocks */ @@ -711,6 +713,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari failed = malloc_nofail(diskmax * sizeof(struct failed_struct)); failed_map = malloc_nofail(diskmax * sizeof(unsigned)); + waiting_map = malloc_nofail((diskmax + RAID_PARITY_MAX) * sizeof(unsigned)); error = 0; silent_error = 0; @@ -814,7 +817,10 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari /* until now is CPU */ state_usage_cpu(state); - task = io_data_read(&io, &diskcur); + task = io_data_read(&io, &diskcur, waiting_map, &waiting_mac); + + /* until now is disk */ + state_usage_disk(state, handle, waiting_map, waiting_mac); /* get the results */ disk = task->disk; @@ -830,9 +836,6 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari if (!disk) continue; - /* until now is disk */ - state_usage_disk(state, disk); - /* get the state of the block */ block_state = block_state_get(block); @@ -1065,7 +1068,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari } /* until now is parity */ - state_usage_parity(state, l); + state_usage_parity(state, &l, 1); } /* if no error in parity read */ @@ -1196,10 +1199,10 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari for (l = 0; l < state->level; ++l) { unsigned levcur; - io_parity_write(&io, &levcur); + io_parity_write(&io, &levcur, waiting_map, &waiting_mac); /* until now is parity */ - state_usage_parity(state, levcur); + state_usage_parity(state, waiting_map, waiting_mac); } /* write finished */ @@ -1362,6 +1365,7 @@ bail: free(rehandle_alloc); free(failed); free(failed_map); + free(waiting_map); io_done(&io); if (state->opt.expect_recoverable) {