]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu_monitor: Extract 'timed_stats' of block devices
authorPeter Krempa <pkrempa@redhat.com>
Thu, 11 Sep 2025 15:07:11 +0000 (17:07 +0200)
committerPeter Krempa <pkrempa@redhat.com>
Wed, 5 Nov 2025 13:27:57 +0000 (14:27 +0100)
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>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
src/qemu/qemu_monitor.c
src/qemu/qemu_monitor.h
src/qemu/qemu_monitor_json.c

index 8fd949d351b1637bdd985f55b8ae5697b1b498be..f61da140ea5fb7f0e4b5c36211e4cf97b89e0dd8 100644 (file)
@@ -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);
 }
index 0466f2f0fe2bab3004da4d4fe89e123137063027..83d702a96c9fd7cf4b6cad2e1f6ec648cfcf9198 100644 (file)
@@ -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);
 
index 7ea9fe68f0be3324252b0880bf351c9351905ff0..c7d291a201a32a9f9a195ba488157415dbcbca37 100644 (file)
@@ -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);
 }