Keeps stats about usage time of disk and cpu.

This commit is contained in:
Andrea Mazzoleni 2014-06-25 22:32:36 +02:00
parent fb4f257593
commit 5dfc67ec18
11 changed files with 230 additions and 8 deletions

View file

@ -14,6 +14,8 @@ SnapRAID HISTORY
* Auto exclude the lock file.
* Don't prints the 'UUID set' message anymore because it's the normal
condition for empty disks.
* In 'sync' keeps stats about the amount of time spent waiting for
each disk and what is spent in CPU computation.
* In Windows, if the disk doesn't support reading physical offsets,
allows SnapRAID to continue anyway.

11
TODO
View file

@ -3,16 +3,11 @@ SnapRAID TODO
This is the list of TODO items for SnapRAID.
/* close the last file in the disk */
in sync.c
- Next
* Recognize if the content file is older than parity,
and in case make a full sync after asking for configuration
with a --force option.
* Measures the time waited in blocking syscall for each disk,
and prints stats of the disk speeds when the command finish,
or when it's running.
* In status prints the allocated parity in each data disk.
In case, also takes into account the extra available space
in the parity disks.

View file

@ -644,6 +644,7 @@ struct snapraid_disk* disk_alloc(const char* name, const char* dir, uint64_t dev
pathslash(disk->dir, sizeof(disk->dir));
disk->device = dev;
disk->tick = 0;
disk->first_free_block = 0;
disk->has_volatile_inodes = 0;
disk->has_unreliable_physical = 0;

View file

@ -293,6 +293,8 @@ struct snapraid_disk {
char dir[PATH_MAX]; /**< Mount point of the disk. It always terminates with /. */
uint64_t device; /**< Device identifier. */
uint64_t tick; /**< Usage time of the disk. */
/**
* First free searching block.
* Note that it doesn't necessarely point at the first free block,

View file

@ -1370,5 +1370,15 @@ retry:
return count;
}
uint64_t tick(void)
{
LARGE_INTEGER t;
if (!QueryPerformanceCounter(&t))
return 0;
return t.QuadPart;
}
#endif

View file

@ -236,6 +236,14 @@ int filephy(const char* path, struct stat* st, uint64_t* physical);
*/
int fsinfo(const char* path, int* has_persistent_inode);
/**
* Get the tick counter value.
*
* Note that the frequency is unspecified, becasue the time measure
* is meant to be used to compare the ratio between usage times.
*/
uint64_t tick(void);
/**
* Initializes the system.
*/

View file

@ -84,7 +84,10 @@ void state_init(struct snapraid_state* state)
for(l=0;l<LEV_MAX;++l) {
state->parity_path[l][0] = 0;
state->parity_device[l] = 0;
state->tick[l] = 0;
}
state->tick_cpu = 0;
state->tick_last = tick();
state->share[0] = 0;
state->pool[0] = 0;
state->pool_device = 0;
@ -4309,10 +4312,13 @@ int state_progress(struct snapraid_state* state, block_off_t blockpos, block_off
fflush(stdlog);
} else {
time_t now;
tommy_node* i;
unsigned l;
now = time(0);
if (state->progress_last != now) {
uint64_t tick_total;
time_t delta = now - state->progress_start - state->progress_subtract;
printf("%u%%, %u MiB", countpos * 100 / countmax, (unsigned)(countsize / (1024*1024)));
@ -4321,6 +4327,16 @@ int state_progress(struct snapraid_state* state, block_off_t blockpos, block_off
printf(", %u MiB/s", (unsigned)(countsize / (1024*1024) / delta));
}
tick_total = state->tick_cpu;
for(i=state->disklist;i!=0;i=i->next) {
struct snapraid_disk* disk = i->data;
tick_total += disk->tick;
}
for(l=0;l<state->level;++l)
tick_total += state->tick[l];
if (tick_total)
printf(", CPU %"PRIu64"%%", state->tick_cpu * 100ULL / tick_total);
if (delta > 5 && countpos > 0) {
unsigned m, h;
data_off_t to_do = countmax - countpos;
@ -4352,6 +4368,52 @@ int state_progress(struct snapraid_state* state, block_off_t blockpos, block_off
return 0;
}
void state_usage_print(struct snapraid_state* state)
{
uint64_t tick_total;
uint64_t tick_max;
tommy_node* i;
unsigned l;
tick_max = 0;
tick_total = 0;
for(i=state->disklist;i!=0;i=i->next) {
struct snapraid_disk* disk = i->data;
tick_total += disk->tick;
if (disk->tick > tick_max)
tick_max = disk->tick;
}
for(l=0;l<state->level;++l) {
tick_total += state->tick[l];
if (state->tick[l] > tick_max)
tick_max = state->tick[l];
}
if (!tick_total)
return;
printf("Time for disk:");
for(i=state->disklist;i!=0;i=i->next) {
struct snapraid_disk* disk = i->data;
if (disk->tick == tick_max)
printf(" %s:", disk->name);
else
printf(" ");
printf("%"PRIu64"%%", disk->tick * 100ULL / tick_total);
}
printf("\n");
printf("Time for parity:");
for(l=0;l<state->level;++l) {
if (state->tick[l] == tick_max)
printf(" %s:", lev_config_name(l));
else
printf(" ");
printf("%"PRIu64"%%", state->tick[l] * 100ULL / tick_total);
}
printf("\n");
}
void generate_configuration(const char* path)
{
struct snapraid_state state;

View file

@ -117,6 +117,21 @@ struct snapraid_state {
tommy_hashdyn previmportset; /**< Hashtable by prevhash of all the import blocks. Valid only if we are in a rehash state. */
tommy_arrayblkof infoarr; /**< Block information array. */
/**
* Cumulative time used for parity disks.
*/
uint64_t tick[LEV_MAX];
/**
* Cumulative time used for computations.
*/
uint64_t tick_cpu;
/**
* Last time used for time measure.
*/
uint64_t tick_last;
/**
* Required size of the parity file, computed from the loaded state.
*
@ -251,6 +266,62 @@ void state_progress_stop(struct snapraid_state* state);
*/
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;
}
/**
* Set the usage time for CPU.
*/
static inline void state_usage_cpu(struct snapraid_state* state)
{
uint64_t now = tick();
/* increment the time spent in computations */
state->tick_cpu += now - state->tick_last;
state->tick_last = now;
}
/**
* Set the usage time for data disk.
*/
static inline void state_usage_disk(struct snapraid_state* state, struct snapraid_disk* disk)
{
uint64_t now = tick();
/* increment the time spent in the data disk */
disk->tick += now - state->tick_last;
state->tick_last = now;
}
/**
* Set the usage time for parity disk.
*/
static inline void state_usage_parity(struct snapraid_state* state, unsigned level)
{
uint64_t now = tick();
assert(level < LEV_MAX);
/* increment the time spent in the parity disk */
state->tick[level] += now - state->tick_last;
state->tick_last = now;
}
/**
* Prints the stats of the usage time.
*/
void state_usage_print(struct snapraid_state* state);
/****************************************************************************/
/* misc */

View file

@ -77,6 +77,9 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
}
}
/* drop until now */
state_usage_waste(state);
countsize = 0;
countpos = 0;
if (state_progress_begin(state, blockstart, blockmax, countmax))
@ -113,6 +116,9 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
/* if we have to use the old hash */
rehash = info_get_rehash(info);
/* until now is CPU */
state_usage_cpu(state);
/* if the file is different than the current one, close it */
if (handle[j].file != 0 && handle[j].file != block_file_get(block)) {
/* file we are processing for error reporting */
@ -212,6 +218,9 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
/* LCOV_EXCL_STOP */
}
/* until now is disk */
state_usage_disk(state, disk);
countsize += read_size;
/* now compute the hash */
@ -406,6 +415,9 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
autosavemissing = countmax; /* blocks to do */
autosavedone = 0; /* blocks done */
/* drop until now */
state_usage_waste(state);
countsize = 0;
countpos = 0;
if (state_progress_begin(state, blockstart, blockmax, countmax))
@ -528,6 +540,9 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
continue;
}
/* until now is CPU */
state_usage_cpu(state);
/* if the file is different than the current one, close it */
if (handle[j].file != 0 && handle[j].file != block_file_get(block)) {
/* file we are processing for error reporting */
@ -630,6 +645,9 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
/* LCOV_EXCL_STOP */
}
/* until now is disk */
state_usage_disk(state, disk);
countsize += read_size;
/* now compute the hash */
@ -758,10 +776,14 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
/* if we have something to recover and enough parity */
if (something_to_recover && j == failed_count) {
/* until now is CPU */
state_usage_cpu(state);
/* read the parity */
/* we are sure that parity exists because */
/* we have at least one BLK block */
for(l=0;l<state->level;++l) {
ret = parity_read(parity[l], i, buffer[diskmax+l], state->block_size, stdlog);
if (ret == -1) {
/* LCOV_EXCL_START */
@ -773,6 +795,9 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
goto bail;
/* LCOV_EXCL_STOP */
}
/* until now is parity */
state_usage_parity(state, l);
}
/* try to fix the data */
@ -827,6 +852,9 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
/* compute the parity */
raid_gen(diskmax, state->level, state->block_size, buffer);
/* until now is CPU */
state_usage_cpu(state);
/* write the parity */
for(l=0;l<state->level;++l) {
ret = parity_write(parity[l], i, buffer[diskmax+l], state->block_size);
@ -840,6 +868,9 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
goto bail;
/* LCOV_EXCL_STOP */
}
/* until now is parity */
state_usage_parity(state, l);
}
}
@ -922,11 +953,16 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
state_write(state);
state_progress_restart(state);
/* drop until now */
state_usage_waste(state);
}
}
state_progress_end(state, countpos, countmax, countsize);
state_usage_print(state);
if (error || silent_error) {
printf("\n");
printf("%8u read/write errors\n", error);

View file

@ -235,6 +235,38 @@ int fsinfo(const char* path, int* has_persistent_inode)
return 0;
}
uint64_t tick(void)
{
#if HAVE_MACH_ABSOLUTE_TIME
/* for Mac OS X */
return match_absolute_time();
#elif HAVE_CLOCK_GETTIME && (defined(CLOCK_MONOTONIC) || defined(CLOCK_MONOTONIC_RAW))
/* for Linux */
struct timespec tv;
/* nanosecond precision with clock_gettime() */
#if defined(CLOCK_MONOTONIC_RAW)
if (clock_gettime(CLOCK_MONOTONIC_RAW, &tv) != 0) {
#else
if (clock_gettime(CLOCK_MONOTONIC, &tv) != 0) {
#endif
return 0;
}
return tv.tv_sec * 1000000000ULL + tv.tv_nsec;
#else
/* other platforms */
struct timeval tv;
/* microsecond precision with gettimeofday() */
if (gettimeofday(&tv, 0) != 0) {
return 0;
}
return tv.tv_sec * 1000000ULL + tv.tv_usec;
#endif
}
void os_init(void)
{
}

View file

@ -76,6 +76,9 @@ AC_CHECK_FUNCS([ftruncate fallocate fsync access posix_fallocate posix_fadvise])
AC_CHECK_FUNCS([pread pwrite getc_unlocked ferror_unlocked fnmatch])
AC_CHECK_FUNCS([futimes futimens futimesat localtime_r])
AC_CHECK_FUNCS([fstatat flock statfs])
AC_CHECK_FUNCS([mach_absolute_time])
AC_SEARCH_LIBS([clock_gettime], [rt])
AC_CHECK_FUNCS([clock_gettime])
dnl Checks for architecture
AC_C_BIGENDIAN