summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryn M. Reeves <bmr@redhat.com>2015-08-08 23:59:06 +0100
committerBryn M. Reeves <bmr@redhat.com>2015-08-08 23:59:06 +0100
commitd4acf8b533b885e3952acc8f9da86d5391b34e23 (patch)
treeeacd3527e8d97549df12e686ae84c3bd9416caa6
parentdfb4560e24fd1e5b8c6782e70e08ff7acec8774c (diff)
downloadlvm2-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.c93
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);