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}