mirror of https://github.com/vitalif/e2fsprogs
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 <garlick@llnl.gov> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>bitmap-optimize
parent
894c7fdb13
commit
6d96b00d57
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue