diff options
author | Bryn M. Reeves <bmr@redhat.com> | 2015-08-08 23:59:06 +0100 |
---|---|---|
committer | Bryn M. Reeves <bmr@redhat.com> | 2015-08-08 23:59:06 +0100 |
commit | d4acf8b533b885e3952acc8f9da86d5391b34e23 (patch) | |
tree | eacd3527e8d97549df12e686ae84c3bd9416caa6 | |
parent | dfb4560e24fd1e5b8c6782e70e08ff7acec8774c (diff) | |
download | lvm2-dev-bmr-dmstats.tar.gz |
dmstats: separate report and sample clocksdev-bmr-dmstats
Maintain separate timestamps for sampling interval and report
waits and correct the sleep interval for the time spent collecting
and processing stats.
-rw-r--r-- | tools/dmsetup.c | 93 |
1 files changed, 72 insertions, 21 deletions
diff --git a/tools/dmsetup.c b/tools/dmsetup.c index 62c2b49f2..0fd1da325 100644 --- a/tools/dmsetup.c +++ b/tools/dmsetup.c @@ -208,7 +208,7 @@ static uint64_t _disp_factor = 512; /* display sizes in sectors */ static char _disp_units = 's'; /* report timekeeping */ -static struct dm_timestamp *_ts_start = NULL, *_ts_end = NULL; +static struct dm_timestamp *_ts_stats_start = NULL, *_ts_stats_end = NULL; static uint64_t _last_interval = 0; /* approx. measured interval in nsecs */ static uint64_t _interval = 0; /* configured interval in nsecs */ @@ -459,6 +459,7 @@ static void _destroy_split_name(struct dm_split_name *split_name) static int _display_info_cols(struct dm_task *dmt, struct dm_info *info) { struct dmsetup_report_obj obj; + uint64_t delta_t; int r = 0; if (!info->exists) { @@ -493,13 +494,52 @@ static int _display_info_cols(struct dm_task *dmt, struct dm_info *info) if (!(obj.stats = dm_stats_create(DM_STATS_PROGRAM_ID))) goto_out; - /* use measured approximation for calculations */ - dm_stats_set_sampling_interval_ns(obj.stats, _last_interval); - dm_stats_bind_devno(obj.stats, info->major, info->minor); + + if (!_ts_stats_end) + _ts_stats_end = dm_timestamp_alloc(); + if (!_ts_stats_end) { + log_error("Could not allocate timestamp object."); + goto out; + } + + /* end-of-interval: as close as possible to @stats_print{_clear} */ + if (!dm_timestamp_get(_ts_stats_end)) + goto_out; + if (!(dm_stats_populate(obj.stats, DM_STATS_PROGRAM_ID, DM_STATS_REGIONS_ALL))) { goto out; } + + /* + * Stats clock: maintain a pair of timestamps taken just before + * and just after the dm_stats_populate() call and use the delta + * to estimate the duration of the interval for counter sampling. + * + * FIXME: currently the measured interval of the first region to + * be processed is taken as an estimate for all other regions. + */ + if (!_ts_stats_start) { + _ts_stats_start = dm_timestamp_alloc(); + if (!_ts_stats_start) { + log_error("Could not allocate timestamp object."); + goto out; + } + /* start the first interval */ + if (!dm_timestamp_get(_ts_stats_start)) + goto_out; + /* Pretend we have the configured interval for the first iteration. */ + _last_interval = _interval; + } else if ((delta_t = dm_timestamp_delta(_ts_stats_end, _ts_stats_start)) > _interval) { + /* Only update interval at start of cycle */ + _last_interval = delta_t; + /* start-of-interval: as close as possible to ioctl return */ + if (!dm_timestamp_get(_ts_stats_start)) + goto_out; + } + + /* use measured approximation for calculations */ + dm_stats_set_sampling_interval_ns(obj.stats, _last_interval); } dm_stats_walk_start(obj.stats); @@ -5390,21 +5430,40 @@ static int _perform_command_for_all_repeatable_args(CMD_ARGS) static int _do_report_wait(void) { - if (!dm_timestamp_get(_ts_start)) - goto_out; + static struct dm_timestamp *_last_wake, *_now = NULL; + uint64_t this_interval; + + /* + * Report clock: compensate for time spent in userspace and stats + * message ioctls by keeping track of the last wake time and + * adjusting the sleep interval accordingly. + */ + if (!_last_wake && !_now) { + if (!(_last_wake = dm_timestamp_alloc())) + goto_out; + if (!(_now = dm_timestamp_alloc())) + goto_out; + dm_timestamp_get(_last_wake); + } - if (usleep(_interval / NSEC_PER_USEC)) { + dm_timestamp_get(_now); + + /* adjust for time spent populating and reporting */ + this_interval = _interval - dm_timestamp_delta(_now, _last_wake); + + if (usleep(this_interval / NSEC_PER_USEC)) { if (errno == EINTR) log_error("Report interval interrupted by signal."); if (errno == EINVAL) log_error("Report interval too short."); goto out; } + dm_timestamp_get(_last_wake); - if (!dm_timestamp_get(_ts_end)) - goto_out; - - _last_interval = dm_timestamp_delta(_ts_end, _ts_start); + if(_count == 2) { + dm_timestamp_destroy(_last_wake); + dm_timestamp_destroy(_now); + } return 1; out: @@ -5526,14 +5585,6 @@ unknown: argc--, argv++; } - _ts_start = dm_timestamp_alloc(); - _ts_end = dm_timestamp_alloc(); - if (!_ts_start || !_ts_end) { - log_error("Could not allocate timestamp objects."); - goto out; - } - /* Pretend we have the configured interval for the first iteration. */ - _last_interval = _interval; doit: multiple_devices = (cmd->repeatable_cmd && argc != 2 && (argc != 1 || (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]))); @@ -5561,8 +5612,8 @@ out: if (_dtree) dm_tree_free(_dtree); - dm_timestamp_destroy(_ts_start); - dm_timestamp_destroy(_ts_end); + dm_timestamp_destroy(_ts_stats_start); + dm_timestamp_destroy(_ts_stats_end); dm_free(_table); |