malloc_info/
info.rs

1//! Types for parsing the output of `malloc_info` from glibc.
2//!
3//! A best effort was made to account for all edge cases in the XML output of `malloc_info`, but
4//! there may be some cases that are not accounted for. If you find one, please open an issue.
5
6use serde::Deserialize;
7
8/// Types of arena space
9#[derive(Deserialize, Debug, PartialEq, Eq)]
10#[serde(rename_all = "kebab-case")]
11pub enum AspaceType {
12    Total,
13    Mprotect,
14    Subheaps,
15    #[serde(other)]
16    Other,
17}
18
19/// Arena space information
20#[derive(Deserialize, Debug, PartialEq, Eq)]
21#[serde(rename_all = "kebab-case")]
22pub struct Aspace {
23    #[serde(rename = "@type")]
24    pub r#type: AspaceType,
25    #[serde(rename = "@size")]
26    pub size: usize,
27}
28
29/// Types of system memory
30#[derive(Deserialize, Debug, PartialEq, Eq)]
31#[serde(rename_all = "kebab-case")]
32pub enum SystemType {
33    Current,
34    Max,
35    #[serde(other)]
36    Other,
37}
38
39/// System memory information
40#[derive(Deserialize, Debug, PartialEq, Eq)]
41#[serde(rename_all = "kebab-case")]
42pub struct System {
43    #[serde(rename = "@type")]
44    pub r#type: SystemType,
45    #[serde(rename = "@size")]
46    pub size: usize,
47}
48
49/// Types of total memory
50#[derive(Deserialize, Debug, PartialEq, Eq)]
51#[serde(rename_all = "kebab-case")]
52pub enum TotalType {
53    Fast,
54    Rest,
55    Mmap,
56    #[serde(other)]
57    Other,
58}
59
60/// Total memory information
61#[derive(Deserialize, Debug, PartialEq, Eq)]
62#[serde(rename_all = "kebab-case")]
63pub struct Total {
64    #[serde(rename = "@type")]
65    pub r#type: TotalType,
66    #[serde(rename = "@count")]
67    pub count: usize,
68    #[serde(rename = "@size")]
69    pub size: usize,
70}
71
72/// Size information for an arena or the whole heap
73#[derive(Deserialize, Debug, PartialEq, Eq)]
74#[serde(rename_all = "kebab-case")]
75pub enum Size {
76    Size {
77        #[serde(rename = "@from")]
78        from: usize,
79        #[serde(rename = "@to")]
80        to: usize,
81        #[serde(rename = "@total")]
82        total: usize,
83        #[serde(rename = "@count")]
84        count: usize,
85    },
86    Unsorted {
87        #[serde(rename = "@from")]
88        from: usize,
89        #[serde(rename = "@to")]
90        to: usize,
91        #[serde(rename = "@total")]
92        total: usize,
93        #[serde(rename = "@count")]
94        count: usize,
95    },
96}
97
98/// Wrapper type for sizes, which may be an array of XML elements
99#[derive(Deserialize, Debug, PartialEq, Eq)]
100#[serde(rename_all = "kebab-case")]
101pub struct Sizes {
102    #[serde(rename = "$value")]
103    pub sizes: Option<Vec<Size>>,
104}
105
106/// Arena-specific heap information
107#[derive(Deserialize, Debug, PartialEq, Eq)]
108#[serde(rename_all = "kebab-case")]
109pub struct Heap {
110    /// Arena number
111    #[serde(rename = "@nr")]
112    pub nr: usize,
113
114    /// Arena sizes
115    pub sizes: Option<Sizes>,
116}
117
118/// Top-level type for all stats returned from [`malloc_info`](crate::malloc_info)
119#[derive(Deserialize, Debug, PartialEq, Eq)]
120#[serde(rename_all = "kebab-case")]
121pub struct Malloc {
122    #[serde(rename = "@version")]
123    pub version: String,
124    #[serde(rename = "heap")]
125    pub heaps: Vec<Heap>,
126    pub total: Vec<Total>,
127    pub system: Vec<System>,
128    pub aspace: Vec<Aspace>,
129}
130
131#[cfg(test)]
132mod test {
133    use super::*;
134
135    #[test]
136    fn parse_simple() {
137        // Taken from the malloc_info(3) man-page
138        const XML: &str = r#"
139<malloc version="1">
140<heap nr="0">
141<sizes>
142</sizes>
143<total type="fast" count="0" size="0"/>
144<total type="rest" count="0" size="0"/>
145<system type="current" size="135168"/>
146<system type="max" size="135168"/>
147<aspace type="total" size="135168"/>
148<aspace type="mprotect" size="135168"/>
149</heap>
150<total type="fast" count="0" size="0"/>
151<total type="rest" count="0" size="0"/>
152<system type="current" size="135168"/>
153<system type="max" size="135168"/>
154<aspace type="total" size="135168"/>
155<aspace type="mprotect" size="135168"/>
156</malloc>
157"#;
158        let parsed: Malloc = quick_xml::de::from_str(XML).expect("parse XML");
159        assert_eq!(parsed.version, "1");
160        assert_eq!(parsed.heaps.len(), 1);
161        assert_eq!(parsed.total.len(), 2);
162        assert_eq!(parsed.system.len(), 2);
163        assert_eq!(parsed.aspace.len(), 2);
164    }
165
166    #[test]
167    fn parse_complex() {
168        // Taken from the malloc_info(3) man-page
169        const XML: &str = r#"
170<malloc version="1">
171<heap nr="0">
172<sizes>
173</sizes>
174<total type="fast" count="0" size="0"/>
175<total type="rest" count="0" size="0"/>
176<system type="current" size="1081344"/>
177<system type="max" size="1081344"/>
178<aspace type="total" size="1081344"/>
179<aspace type="mprotect" size="1081344"/>
180</heap>
181<heap nr="1">
182<sizes>
183</sizes>
184<total type="fast" count="0" size="0"/>
185<total type="rest" count="0" size="0"/>
186<system type="current" size="1032192"/>
187<system type="max" size="1032192"/>
188<aspace type="total" size="1032192"/>
189<aspace type="mprotect" size="1032192"/>
190</heap>
191<total type="fast" count="0" size="0"/>
192<total type="rest" count="0" size="0"/>
193<system type="current" size="2113536"/>
194<system type="max" size="2113536"/>
195<aspace type="total" size="2113536"/>
196<aspace type="mprotect" size="2113536"/>
197</malloc>
198"#;
199        let parsed: Malloc = quick_xml::de::from_str(XML).expect("parse XML");
200        assert_eq!(parsed.version, "1");
201        assert_eq!(parsed.heaps.len(), 2);
202        assert_eq!(parsed.total.len(), 2);
203        assert_eq!(parsed.system.len(), 2);
204        assert_eq!(parsed.aspace.len(), 2);
205    }
206
207    #[test]
208    #[should_panic]
209    fn parse_invalid() {
210        const XML: &str = r#"
211<malloc version="1">
212</malloc>
213"#;
214        let _ = quick_xml::de::from_str::<Malloc>(XML).expect("parse XML");
215    }
216}