[RFC PATCH 11/16] qemu_monitor: Extract 'timed_stats' of block devices

Peter Krempa via Devel posted 16 patches 2 weeks, 4 days ago
[RFC PATCH 11/16] qemu_monitor: Extract 'timed_stats' of block devices
Posted by Peter Krempa via Devel 2 weeks, 4 days ago
From: Peter Krempa <pkrempa@redhat.com>

The 'timed_stats' block is a set of statistics gathered in configurable
time intervals. The stats include latency timings of reads/writes as
well as the depth of the request queues.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
---
 src/qemu/qemu_monitor.c      |  1 +
 src/qemu/qemu_monitor.h      | 29 ++++++++++++++++++++++++
 src/qemu/qemu_monitor_json.c | 44 ++++++++++++++++++++++++++++++++++++
 3 files changed, 74 insertions(+)

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 554898b93f..fb01335f89 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1984,6 +1984,7 @@ qemuBlockStatsFinalize(GObject *object)
         return;

     g_free(stats->limits);
+    g_free(stats->timed_stats);

     G_OBJECT_CLASS(qemu_block_stats_parent_class)->finalize(object);
 }
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 9b9292e48d..a93d722418 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -806,6 +806,31 @@ struct qemuBlockStatsLimits {
 };


+struct qemuBlockStatsTimed {
+    unsigned long long interval_length;
+
+    /* latencies are in nanoseconds */
+    unsigned long long rd_latency_min;
+    unsigned long long rd_latency_max;
+    unsigned long long rd_latency_avg;
+
+    unsigned long long wr_latency_min;
+    unsigned long long wr_latency_max;
+    unsigned long long wr_latency_avg;
+
+    unsigned long long zone_append_latency_min;
+    unsigned long long zone_append_latency_max;
+    unsigned long long zone_append_latency_avg;
+
+    unsigned long long flush_latency_min;
+    unsigned long long flush_latency_max;
+    unsigned long long flush_latency_avg;
+
+    double rd_queue_depth_avg;
+    double wr_queue_depth_avg;
+    double zone_append_queue_depth_avg;
+};
+
 struct _qemuBlockStats {
     GObject parent;

@@ -829,6 +854,10 @@ struct _qemuBlockStats {
     unsigned long long write_threshold;

     struct qemuBlockStatsLimits *limits;
+
+    /* block accounting/timed stats from qemu - one entry per interval configured */
+    size_t n_timed_stats;
+    struct qemuBlockStatsTimed *timed_stats;
 };
 G_DECLARE_FINAL_TYPE(qemuBlockStats, qemu_block_stats, QEMU, BLOCK_STATS, GObject);

diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index cf63f43318..0cb20d4387 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2386,6 +2386,45 @@ qemuMonitorJSONGetBlockInfo(qemuMonitor *mon,
 }


+static void
+qemuMonitorJSONBlockStatsCollectDataTimedOne(virJSONValue *j,
+                                             struct qemuBlockStatsTimed *s)
+{
+    virJSONValueObjectGetNumberUlong(j, "interval_length", &s->interval_length);
+
+    virJSONValueObjectGetNumberUlong(j, "min_rd_latency_ns", &s->rd_latency_min);
+    virJSONValueObjectGetNumberUlong(j, "max_rd_latency_ns", &s->rd_latency_max);
+    virJSONValueObjectGetNumberUlong(j, "avg_rd_latency_ns", &s->rd_latency_avg);
+
+    virJSONValueObjectGetNumberUlong(j, "min_wr_latency_ns", &s->wr_latency_min);
+    virJSONValueObjectGetNumberUlong(j, "max_wr_latency_ns", &s->wr_latency_max);
+    virJSONValueObjectGetNumberUlong(j, "avg_wr_latency_ns", &s->wr_latency_avg);
+
+    virJSONValueObjectGetNumberUlong(j, "min_zone_append_latency_ns", &s->zone_append_latency_min);
+    virJSONValueObjectGetNumberUlong(j, "max_zone_append_latency_ns", &s->zone_append_latency_max);
+    virJSONValueObjectGetNumberUlong(j, "avg_zone_append_latency_ns", &s->zone_append_latency_avg);
+
+    virJSONValueObjectGetNumberDouble(j, "avg_rd_queue_depth", &s->rd_queue_depth_avg);
+    virJSONValueObjectGetNumberDouble(j, "avg_wr_queue_depth", &s->wr_queue_depth_avg);
+    virJSONValueObjectGetNumberDouble(j, "avg_zone_append_queue_depth", &s->zone_append_queue_depth_avg);
+}
+
+
+static void
+qemuMonitorJSONBlockStatsCollectDataTimed(virJSONValue *timed_stats,
+                                          qemuBlockStats *bstats)
+{
+    size_t i;
+
+    bstats->n_timed_stats = virJSONValueArraySize(timed_stats);
+    bstats->timed_stats = g_new0(struct qemuBlockStatsTimed, bstats->n_timed_stats);
+
+    for (i = 0; i < bstats->n_timed_stats; i++)
+        qemuMonitorJSONBlockStatsCollectDataTimedOne(virJSONValueArrayGet(timed_stats, i),
+                                                     bstats->timed_stats + i);
+}
+
+
 static qemuBlockStats *
 qemuMonitorJSONBlockStatsCollectData(virJSONValue *dev,
                                      int *nstats)
@@ -2394,6 +2433,7 @@ qemuMonitorJSONBlockStatsCollectData(virJSONValue *dev,
     virJSONValue *parent;
     virJSONValue *parentstats;
     virJSONValue *stats;
+    virJSONValue *timed_stats;

     if ((stats = virJSONValueObjectGetObject(dev, "stats")) == NULL) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -2429,6 +2469,10 @@ qemuMonitorJSONBlockStatsCollectData(virJSONValue *dev,
             bstats->wr_highest_offset_valid = true;
     }

+    if ((timed_stats = virJSONValueObjectGetArray(stats, "timed_stats")) &&
+        virJSONValueArraySize(timed_stats) > 0)
+        qemuMonitorJSONBlockStatsCollectDataTimed(timed_stats, bstats);
+
     return g_steal_pointer(&bstats);
 }

-- 
2.51.0