vmm/devices/virtio/balloon/metrics.rs
1// Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Defines the metrics system for balloon devices.
5//!
6//! # Metrics format
7//! The metrics are flushed in JSON when requested by vmm::logger::metrics::METRICS.write().
8//!
9//! ## JSON example with metrics:
10//! ```json
11//! "balloon": {
12//! "activate_fails": "SharedIncMetric",
13//! "inflate_count": "SharedIncMetric",
14//! "stats_updates_count": "SharedIncMetric",
15//! ...
16//! }
17//! }
18//! ```
19//! Each `balloon` field in the example above is a serializable `BalloonDeviceMetrics` structure
20//! collecting metrics such as `activate_fails`, `inflate_count` etc. for the balloon device.
21//! Since balloon doesn't support multiple devices, there is no per device metrics and
22//! `balloon` represents the aggregate balloon metrics.
23//!
24//! # Design
25//! The main design goals of this system are:
26//! * Have a consistent approach of keeping device related metrics in the individual devices
27//! modules.
28//! * To decouple balloon device metrics from logger module by moving BalloonDeviceMetrics out of
29//! FirecrackerDeviceMetrics.
30//! * Rely on `serde` to provide the actual serialization for writing the metrics.
31//!
32//! The system implements 1 type of metrics:
33//! * Shared Incremental Metrics (SharedIncMetrics) - dedicated for the metrics which need a counter
34//! (i.e the number of times an API request failed). These metrics are reset upon flush.
35
36use serde::ser::SerializeMap;
37use serde::{Serialize, Serializer};
38
39use crate::logger::SharedIncMetric;
40
41/// Stores aggregated balloon metrics
42pub(super) static METRICS: BalloonDeviceMetrics = BalloonDeviceMetrics::new();
43
44/// Called by METRICS.flush(), this function facilitates serialization of balloon device metrics.
45pub fn flush_metrics<S: Serializer>(serializer: S) -> Result<S::Ok, S::Error> {
46 let mut seq = serializer.serialize_map(Some(1))?;
47 seq.serialize_entry("balloon", &METRICS)?;
48 seq.end()
49}
50
51/// Balloon Device associated metrics.
52#[derive(Debug, Serialize)]
53pub(super) struct BalloonDeviceMetrics {
54 /// Number of times when activate failed on a balloon device.
55 pub activate_fails: SharedIncMetric,
56 /// Number of balloon device inflations.
57 pub inflate_count: SharedIncMetric,
58 // Number of balloon statistics updates from the driver.
59 pub stats_updates_count: SharedIncMetric,
60 // Number of balloon statistics update failures.
61 pub stats_update_fails: SharedIncMetric,
62 /// Number of balloon device deflations.
63 pub deflate_count: SharedIncMetric,
64 /// Number of times when handling events on a balloon device failed.
65 pub event_fails: SharedIncMetric,
66 /// Number of times when free page repoting was triggered
67 pub free_page_report_count: SharedIncMetric,
68 /// Total memory freed by the reporting driver
69 pub free_page_report_freed: SharedIncMetric,
70 /// Number of errors occurred while reporting
71 pub free_page_report_fails: SharedIncMetric,
72 /// Number of times when free page hinting was triggered
73 pub free_page_hint_count: SharedIncMetric,
74 /// Total memory freed by the hinting driver
75 pub free_page_hint_freed: SharedIncMetric,
76 /// Number of errors occurred while hinting
77 pub free_page_hint_fails: SharedIncMetric,
78}
79impl BalloonDeviceMetrics {
80 /// Const default construction.
81 const fn new() -> Self {
82 Self {
83 activate_fails: SharedIncMetric::new(),
84 inflate_count: SharedIncMetric::new(),
85 stats_updates_count: SharedIncMetric::new(),
86 stats_update_fails: SharedIncMetric::new(),
87 deflate_count: SharedIncMetric::new(),
88 event_fails: SharedIncMetric::new(),
89 free_page_report_count: SharedIncMetric::new(),
90 free_page_report_freed: SharedIncMetric::new(),
91 free_page_report_fails: SharedIncMetric::new(),
92 free_page_hint_count: SharedIncMetric::new(),
93 free_page_hint_freed: SharedIncMetric::new(),
94 free_page_hint_fails: SharedIncMetric::new(),
95 }
96 }
97}
98
99#[cfg(test)]
100pub mod tests {
101 use super::*;
102 use crate::logger::IncMetric;
103
104 #[test]
105 fn test_balloon_dev_metrics() {
106 let balloon_metrics: BalloonDeviceMetrics = BalloonDeviceMetrics::new();
107 let balloon_metrics_local: String = serde_json::to_string(&balloon_metrics).unwrap();
108 // the 1st serialize flushes the metrics and resets values to 0 so that
109 // we can compare the values with local metrics.
110 serde_json::to_string(&METRICS).unwrap();
111 let balloon_metrics_global: String = serde_json::to_string(&METRICS).unwrap();
112 assert_eq!(balloon_metrics_local, balloon_metrics_global);
113 balloon_metrics.inflate_count.inc();
114 assert_eq!(balloon_metrics.inflate_count.count(), 1);
115 }
116}