From 6d96b00d57d236e2746f8245df6c8ea64abc64c1 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 3 Aug 2007 20:07:09 -0400 Subject: [PATCH] Add I/O statistics to e2fsck This patch instruments the libext2fs unix I/O manager and adds bytes read/written and data rate to e2fsck -tt pass/overall timing output. Signed-off-by: Jim Garlick Signed-off-by: "Theodore Ts'o" --- e2fsck/e2fsck.h | 8 ++++++-- e2fsck/pass1.c | 4 ++-- e2fsck/pass2.c | 4 ++-- e2fsck/pass3.c | 7 ++++--- e2fsck/pass4.c | 4 ++-- e2fsck/pass5.c | 4 ++-- e2fsck/rehash.c | 4 ++-- e2fsck/swapfs.c | 4 ++-- e2fsck/unix.c | 12 ++++++------ e2fsck/util.c | 34 ++++++++++++++++++++++++++++++++-- lib/ext2fs/ext2_io.h | 9 +++++++++ lib/ext2fs/test_io.c | 20 +++++++++++++++++++- lib/ext2fs/unix_io.c | 27 +++++++++++++++++++++++++-- 13 files changed, 113 insertions(+), 28 deletions(-) diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h index 96b83dab..5a9b44f3 100644 --- a/e2fsck/e2fsck.h +++ b/e2fsck/e2fsck.h @@ -135,6 +135,8 @@ struct resource_track { struct timeval user_start; struct timeval system_start; void *brk_start; + unsigned long long bytes_read; + unsigned long long bytes_written; }; #endif @@ -469,8 +471,10 @@ extern void preenhalt(e2fsck_t ctx); extern char *string_copy(e2fsck_t ctx, const char *str, int len); #ifdef RESOURCE_TRACK extern void print_resource_track(const char *desc, - struct resource_track *track); -extern void init_resource_track(struct resource_track *track); + struct resource_track *track, + io_channel channel); +extern void init_resource_track(struct resource_track *track, + io_channel channel); #endif extern int inode_has_valid_blocks(struct ext2_inode *inode); extern void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino, diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index bed1ec89..5c2c1aa2 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -485,7 +485,7 @@ void e2fsck_pass1(e2fsck_t ctx) int inode_size; #ifdef RESOURCE_TRACK - init_resource_track(&rtrack); + init_resource_track(&rtrack, ctx->fs->io); #endif clear_problem_context(&pctx); @@ -1013,7 +1013,7 @@ endit: #ifdef RESOURCE_TRACK if (ctx->options & E2F_OPT_TIME2) { e2fsck_clear_progbar(ctx); - print_resource_track(_("Pass 1"), &rtrack); + print_resource_track(_("Pass 1"), &rtrack, ctx->fs->io); } #endif } diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c index 5e088e2d..7f7635f2 100644 --- a/e2fsck/pass2.c +++ b/e2fsck/pass2.c @@ -102,7 +102,7 @@ void e2fsck_pass2(e2fsck_t ctx) int bad_dir; #ifdef RESOURCE_TRACK - init_resource_track(&rtrack); + init_resource_track(&rtrack, ctx->fs->io); #endif clear_problem_context(&cd.pctx); @@ -287,7 +287,7 @@ void e2fsck_pass2(e2fsck_t ctx) #ifdef RESOURCE_TRACK if (ctx->options & E2F_OPT_TIME2) { e2fsck_clear_progbar(ctx); - print_resource_track(_("Pass 2"), &rtrack); + print_resource_track(_("Pass 2"), &rtrack, fs->io); } #endif } diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c index b9c6edd3..867cbf83 100644 --- a/e2fsck/pass3.c +++ b/e2fsck/pass3.c @@ -61,7 +61,7 @@ void e2fsck_pass3(e2fsck_t ctx) unsigned long maxdirs, count; #ifdef RESOURCE_TRACK - init_resource_track(&rtrack); + init_resource_track(&rtrack, ctx->fs->io); #endif clear_problem_context(&pctx); @@ -87,7 +87,8 @@ void e2fsck_pass3(e2fsck_t ctx) #ifdef RESOURCE_TRACK if (ctx->options & E2F_OPT_TIME) { e2fsck_clear_progbar(ctx); - print_resource_track(_("Peak memory"), &ctx->global_rtrack); + print_resource_track(_("Peak memory"), &ctx->global_rtrack, + NULL); } #endif @@ -142,7 +143,7 @@ abort_exit: #ifdef RESOURCE_TRACK if (ctx->options & E2F_OPT_TIME2) { e2fsck_clear_progbar(ctx); - print_resource_track(_("Pass 3"), &rtrack); + print_resource_track(_("Pass 3"), &rtrack, ctx->fs->io); } #endif } diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c index dfb3a37b..0fb8ee7d 100644 --- a/e2fsck/pass4.c +++ b/e2fsck/pass4.c @@ -93,7 +93,7 @@ void e2fsck_pass4(e2fsck_t ctx) int group, maxgroup; #ifdef RESOURCE_TRACK - init_resource_track(&rtrack); + init_resource_track(&rtrack, ctx->fs->io); #endif #ifdef MTRACE @@ -173,7 +173,7 @@ errout: #ifdef RESOURCE_TRACK if (ctx->options & E2F_OPT_TIME2) { e2fsck_clear_progbar(ctx); - print_resource_track(_("Pass 4"), &rtrack); + print_resource_track(_("Pass 4"), &rtrack, ctx->fs->io); } #endif } diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c index deb558a8..53248b01 100644 --- a/e2fsck/pass5.c +++ b/e2fsck/pass5.c @@ -30,7 +30,7 @@ void e2fsck_pass5(e2fsck_t ctx) #endif #ifdef RESOURCE_TRACK - init_resource_track(&rtrack); + init_resource_track(&rtrack, ctx->fs->io); #endif clear_problem_context(&pctx); @@ -67,7 +67,7 @@ void e2fsck_pass5(e2fsck_t ctx) #ifdef RESOURCE_TRACK if (ctx->options & E2F_OPT_TIME2) { e2fsck_clear_progbar(ctx); - print_resource_track(_("Pass 5"), &rtrack); + print_resource_track(_("Pass 5"), &rtrack, ctx->fs->io); } #endif } diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c index 3aa3c06d..8c1459c4 100644 --- a/e2fsck/rehash.c +++ b/e2fsck/rehash.c @@ -778,7 +778,7 @@ void e2fsck_rehash_directories(e2fsck_t ctx) int cur, max, all_dirs, dir_index, first = 1; #ifdef RESOURCE_TRACK - init_resource_track(&rtrack); + init_resource_track(&rtrack, ctx->fs->io); #endif all_dirs = ctx->options & E2F_OPT_COMPRESS_DIRS; @@ -847,7 +847,7 @@ void e2fsck_rehash_directories(e2fsck_t ctx) #ifdef RESOURCE_TRACK if (ctx->options & E2F_OPT_TIME2) { e2fsck_clear_progbar(ctx); - print_resource_track("Pass 3A", &rtrack); + print_resource_track("Pass 3A", &rtrack, ctx->fs->io); } #endif } diff --git a/e2fsck/swapfs.c b/e2fsck/swapfs.c index fb7270c0..81f3ca2c 100644 --- a/e2fsck/swapfs.c +++ b/e2fsck/swapfs.c @@ -219,7 +219,7 @@ void swap_filesys(e2fsck_t ctx) #ifdef RESOURCE_TRACK struct resource_track rtrack; - init_resource_track(&rtrack); + init_resource_track(&rtrack, ctx->fs->io); #endif if (!(ctx->options & E2F_OPT_PREEN)) @@ -265,7 +265,7 @@ void swap_filesys(e2fsck_t ctx) #ifdef RESOURCE_TRACK if (ctx->options & E2F_OPT_TIME2) - print_resource_track(_("Byte swap"), &rtrack); + print_resource_track(_("Byte swap"), &rtrack, fs->io); #endif } diff --git a/e2fsck/unix.c b/e2fsck/unix.c index 5a617d91..1809be49 100644 --- a/e2fsck/unix.c +++ b/e2fsck/unix.c @@ -883,7 +883,7 @@ int main (int argc, char *argv[]) reserve_stdio_fds(); #ifdef RESOURCE_TRACK - init_resource_track(&ctx->global_rtrack); + init_resource_track(&ctx->global_rtrack, NULL); #endif if (!(ctx->options & E2F_OPT_PREEN) || show_version_only) @@ -1293,16 +1293,16 @@ no_journal: } e2fsck_write_bitmaps(ctx); - +#ifdef RESOURCE_TRACK + io_channel_flush(ctx->fs->io); + if (ctx->options & E2F_OPT_TIME) + print_resource_track(NULL, &ctx->global_rtrack, ctx->fs->io); +#endif ext2fs_close(fs); ctx->fs = NULL; free(ctx->filesystem_name); free(ctx->journal_name); -#ifdef RESOURCE_TRACK - if (ctx->options & E2F_OPT_TIME) - print_resource_track(NULL, &ctx->global_rtrack); -#endif e2fsck_free_context(ctx); remove_error_table(&et_ext2_error_table); remove_error_table(&et_prof_error_table); diff --git a/e2fsck/util.c b/e2fsck/util.c index f761ebba..59a08b90 100644 --- a/e2fsck/util.c +++ b/e2fsck/util.c @@ -276,11 +276,12 @@ void preenhalt(e2fsck_t ctx) } #ifdef RESOURCE_TRACK -void init_resource_track(struct resource_track *track) +void init_resource_track(struct resource_track *track, io_channel channel) { #ifdef HAVE_GETRUSAGE struct rusage r; #endif + io_stats io_start = 0; track->brk_start = sbrk(0); gettimeofday(&track->time_start, 0); @@ -295,6 +296,14 @@ void init_resource_track(struct resource_track *track) track->user_start.tv_sec = track->user_start.tv_usec = 0; track->system_start.tv_sec = track->system_start.tv_usec = 0; #endif + track->bytes_read = 0; + track->bytes_written = 0; + if (channel && channel->manager && channel->manager->get_stats) + channel->manager->get_stats(channel, &io_start); + if (io_start) { + track->bytes_read = io_start->bytes_read; + track->bytes_written = io_start->bytes_written; + } } #ifdef __GNUC__ @@ -310,7 +319,8 @@ static _INLINE_ float timeval_subtract(struct timeval *tv1, ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000); } -void print_resource_track(const char *desc, struct resource_track *track) +void print_resource_track(const char *desc, struct resource_track *track, + io_channel channel) { #ifdef HAVE_GETRUSAGE struct rusage r; @@ -347,6 +357,26 @@ void print_resource_track(const char *desc, struct resource_track *track) printf(_("elapsed time: %6.3f\n"), timeval_subtract(&time_end, &track->time_start)); #endif +#define mbytes(x) (((x) + 1048575) / 1048576) + if (channel && channel->manager && channel->manager->get_stats) { + io_stats delta = 0; + unsigned long long bytes_read = 0; + unsigned long long bytes_written = 0; + + if (desc) + printf("%s: ", desc); + + channel->manager->get_stats(channel, &delta); + if (delta) { + bytes_read = delta->bytes_read - track->bytes_read; + bytes_written = delta->bytes_written - + track->bytes_written; + } + printf("I/O read: %lluMB, write: %lluMB, rate: %.2fMB/s\n", + mbytes(bytes_read), mbytes(bytes_written), + (double)mbytes(bytes_read + bytes_written) / + timeval_subtract(&time_end, &track->time_start)); + } } #endif /* RESOURCE_TRACK */ diff --git a/lib/ext2fs/ext2_io.h b/lib/ext2fs/ext2_io.h index eada278e..bee75a6a 100644 --- a/lib/ext2fs/ext2_io.h +++ b/lib/ext2fs/ext2_io.h @@ -26,6 +26,7 @@ ext2_loff_t ext2fs_llseek (int, ext2_loff_t, int); typedef struct struct_io_manager *io_manager; typedef struct struct_io_channel *io_channel; +typedef struct struct_io_stats *io_stats; #define CHANNEL_FLAGS_WRITETHROUGH 0x01 @@ -55,6 +56,13 @@ struct struct_io_channel { void *app_data; }; +struct struct_io_stats { + int num_fields; + int reserved; + unsigned long long bytes_read; + unsigned long long bytes_written; +}; + struct struct_io_manager { errcode_t magic; const char *name; @@ -70,6 +78,7 @@ struct struct_io_manager { int count, const void *data); errcode_t (*set_option)(io_channel channel, const char *option, const char *arg); + errcode_t (*get_stats)(io_channel channel, io_stats *io_stats); int reserved[14]; }; diff --git a/lib/ext2fs/test_io.c b/lib/ext2fs/test_io.c index 03d63ce1..2fe10d24 100644 --- a/lib/ext2fs/test_io.c +++ b/lib/ext2fs/test_io.c @@ -66,6 +66,8 @@ static errcode_t test_write_byte(io_channel channel, unsigned long offset, int count, const void *buf); static errcode_t test_set_option(io_channel channel, const char *option, const char *arg); +static errcode_t test_get_stats(io_channel channel, io_stats *stats); + static struct struct_io_manager struct_test_manager = { EXT2_ET_MAGIC_IO_MANAGER, @@ -77,7 +79,8 @@ static struct struct_io_manager struct_test_manager = { test_write_blk, test_flush, test_write_byte, - test_set_option + test_set_option, + test_get_stats, }; io_manager test_io_manager = &struct_test_manager; @@ -409,3 +412,18 @@ static errcode_t test_set_option(io_channel channel, const char *option, } return retval; } + +static errcode_t test_get_stats(io_channel channel, io_stats *stats) +{ + struct test_private_data *data; + errcode_t retval = 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct test_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); + + if (data->real && data->real->manager->get_stats) { + retval = (data->real->manager->get_stats)(data->real, stats); + } + return retval; +} diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c index 4ede0009..8497a415 100644 --- a/lib/ext2fs/unix_io.c +++ b/lib/ext2fs/unix_io.c @@ -70,6 +70,7 @@ struct unix_private_data { int access_time; ext2_loff_t offset; struct unix_cache cache[CACHE_SIZE]; + struct struct_io_stats io_stats; }; static errcode_t unix_open(const char *name, int flags, io_channel *channel); @@ -84,7 +85,8 @@ static errcode_t unix_write_byte(io_channel channel, unsigned long offset, int size, const void *data); static errcode_t unix_set_option(io_channel channel, const char *option, const char *arg); - +static errcode_t unix_get_stats(io_channel channel, io_stats *stats) +; static void reuse_cache(io_channel channel, struct unix_private_data *data, struct unix_cache *cache, unsigned long block); @@ -110,11 +112,28 @@ static struct struct_io_manager struct_unix_manager = { #else unix_write_byte, #endif - unix_set_option + unix_set_option, + unix_get_stats, }; io_manager unix_io_manager = &struct_unix_manager; +static errcode_t unix_get_stats(io_channel channel, io_stats *stats) +{ + errcode_t retval = 0; + + struct unix_private_data *data; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct unix_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); + + if (stats) + *stats = &data->io_stats; + + return retval; +} + /* * Here are the raw I/O functions */ @@ -130,6 +149,7 @@ static errcode_t raw_read_blk(io_channel channel, int actual = 0; size = (count < 0) ? -count : count * channel->block_size; + data->io_stats.bytes_read += size; location = ((ext2_loff_t) block * channel->block_size) + data->offset; if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; @@ -168,6 +188,7 @@ static errcode_t raw_read_blk(io_channel channel, char sector[BLOCKALIGN]; size = (count < 0) ? -count : count * channel->block_size; + data->io_stats.bytes_read += size; location = ((ext2_loff_t) block * channel->block_size) + data->offset; #ifdef DEBUG printf("count=%d, size=%d, block=%lu, blk_size=%d, location=%llx\n", @@ -224,6 +245,7 @@ static errcode_t raw_write_blk(io_channel channel, else size = count * channel->block_size; } + data->io_stats.bytes_written += size; location = ((ext2_loff_t) block * channel->block_size) + data->offset; if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { @@ -407,6 +429,7 @@ static errcode_t unix_open(const char *name, int flags, io_channel *channel) memset(data, 0, sizeof(struct unix_private_data)); data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; + data->io_stats.num_fields = 2; if ((retval = alloc_cache(io, data))) goto cleanup;