1define_struct! {
41 pub struct PageTypeInfo {
48 page_block_order: i32,
49 pages_per_block: u64,
50 free_pages: Vec<(i32, String, String, [u64;11])>,
52 blocks_type_number: Vec<(i32, String, [u64;6])>,
54 }
55}
56
57#[derive(Debug, PartialEq)]
58struct FreePage {
59 node: i32,
60 zone: String,
61 migrate: String,
62 counts: [u64;11]
63}
64
65impl FreePage {
66 fn into_tuple(self) -> (i32, String, String, [u64;11]) {
67 (self.node, self.zone, self.migrate, self.counts)
68 }
69}
70
71use std::str::FromStr;
72impl FromStr for FreePage {
73 type Err = crate::ProcErr;
74
75 fn from_str(s: &str) -> Result<FreePage, crate::ProcErr> {
76 let columns: Vec<&str> = s.split_ascii_whitespace().collect();
77 if columns.len() != 17 {
78 return Err("no enough fileds to parse a free page".into())
79 }
80
81 let node = columns[1].trim_end_matches(',').parse::<i32>()?;
82 let zone = columns[3].trim_end_matches(',').to_string();
83 let migrate = columns[5].to_string();
84 let mut counts = [0;11];
85 for (c, v) in counts.iter_mut().zip(columns[6..].iter()) {
86 *c = v.parse::<u64>()?;
87 }
88
89 Ok(FreePage{
90 node, zone, migrate, counts
91 })
92 }
93}
94
95#[derive(Debug, PartialEq)]
96struct BlockTypeNumber {
97 node: i32,
98 zone: String,
99 counts: [u64; 6]
100}
101
102impl BlockTypeNumber {
103 fn into_tuple(self) -> (i32, String, [u64;6]) {
104 (self.node, self.zone, self.counts)
105 }
106}
107
108impl FromStr for BlockTypeNumber {
109 type Err = crate::ProcErr;
110
111 fn from_str(s: &str) -> Result<BlockTypeNumber, crate::ProcErr> {
112 let columns: Vec<&str> = s.split_ascii_whitespace().collect();
113 if columns.len() != 10 {
114 return Err("no enough fields to parse blocks type number".into())
115 }
116
117 let node = columns[1].trim_end_matches(',').parse::<i32>()?;
118 let zone = columns[3].to_string();
119 let mut counts = [0;6];
120 for (c, v) in counts.iter_mut().zip(columns[4..].iter()) {
121 *c = v.parse::<u64>()?;
122 }
123
124 Ok(BlockTypeNumber{
125 node, zone, counts
126 })
127 }
128}
129
130impl FromStr for PageTypeInfo {
131 type Err = crate::ProcErr;
132
133 fn from_str(s: &str) -> Result<PageTypeInfo, crate::ProcErr> {
134 let blocks: Vec<&str> = s.split("\n\n").collect();
135 if blocks.len() != 3 {
136 println!("{:?}", blocks);
137 return Err("pagetypeinfo should have 3 blocks".into())
138 }
139
140 let b1: Vec<&str> = blocks[0].split_ascii_whitespace().collect();
141 if b1.len() != 8 {
142 return Err("first block of pagetypeinfo should 8 items".into())
143 }
144 let page_block_order = b1[3].parse::<i32>()?;
145 let pages_per_block = b1[7].parse::<u64>()?;
146
147 let mut free_pages = vec![];
148 for line in blocks[1].lines().skip(1) {
149 let l = line.parse::<FreePage>()?;
150 free_pages.push(l.into_tuple());
151 }
152
153 let mut blocks_type_number = vec![];
154 for line in blocks[2].lines().skip(1) {
155 let l = line.parse::<BlockTypeNumber>()?;
156 blocks_type_number.push(l.into_tuple())
157 }
158
159 Ok(PageTypeInfo{
160 page_block_order, pages_per_block,
161 free_pages, blocks_type_number
162 })
163 }
164}
165
166instance_impl! {
167 pagetypeinfo, "/proc/pagetypeinfo", PageTypeInfo
168}
169
170#[cfg(test)]
171mod test {
172 use super::*;
173
174 #[test]
175 fn test_parse_freepage() {
176 let source = "Node 0, zone DMA, type Unmovable 2 10 13 8 4 1 2 2 0 0 0";
177 let correct = FreePage {
178 node: 0,
179 zone: String::from("DMA"),
180 migrate: String::from("Unmovable"),
181 counts: [2,10,13,8,4,1,2,2,0,0,0]
182 };
183 assert_eq!(correct, source.parse::<FreePage>().unwrap());
184 }
185
186 #[test]
187 fn test_parse_blocktypenumber() {
188 let source = "Node 0, zone DMA 2 1 5 0 0 0";
189 let correct = BlockTypeNumber{
190 node: 0,
191 zone: String::from("DMA"),
192 counts: [2,1,5,0,0,0]
193 };
194 assert_eq!(correct, source.parse::<BlockTypeNumber>().unwrap());
195 }
196
197 #[test]
198 fn test_parse_pagetypeinfo() {
199 let source = {
200"Page block order: 9
201Pages per block: 512
202
203Free pages count per migrate type at order 0 1 2 3 4 5 6 7 8 9 10
204Node 0, zone DMA, type Unmovable 2 10 13 8 4 1 2 2 0 0 0
205Node 0, zone DMA, type Reclaimable 3 1 2 2 1 0 1 1 1 0 0
206Node 0, zone DMA, type Movable 2 1 1 0 1 1 0 1 2 0 0
207Node 0, zone DMA, type Reserve 0 0 0 0 0 0 0 0 0 0 0
208Node 0, zone DMA, type CMA 0 0 0 0 0 0 0 0 0 0 0
209Node 0, zone DMA, type Isolate 0 0 0 0 0 0 0 0 0 0 0
210Node 0, zone DMA32, type Unmovable 148 77 109 136 20 7 0 0 0 0 0
211Node 0, zone DMA32, type Reclaimable 31 135 247 159 31 11 3 0 0 0 0
212Node 0, zone DMA32, type Movable 452 198 246 1628 565 17 18 16 11 1 0
213Node 0, zone DMA32, type Reserve 0 0 0 0 0 0 0 0 0 0 0
214Node 0, zone DMA32, type CMA 0 0 0 0 0 0 0 0 0 0 0
215Node 0, zone DMA32, type Isolate 0 0 0 0 0 0 0 0 0 0 0
216
217Number of blocks type Unmovable Reclaimable Movable Reserve CMA Isolate
218Node 0, zone DMA 2 1 5 0 0 0
219Node 0, zone DMA32 74 42 756 0 0 0 "
220 };
221 let correct = PageTypeInfo {
222 page_block_order: 9,
223 pages_per_block: 512,
224 free_pages: vec![
225 (0, String::from("DMA"), String::from("Unmovable"), [ 2, 10, 13, 8, 4, 1, 2, 2, 0, 0, 0]),
226 (0, String::from("DMA"), String::from("Reclaimable"), [ 3, 1, 2, 2, 1, 0, 1, 1, 1, 0, 0]),
227 (0, String::from("DMA"), String::from("Movable"), [ 2, 1, 1, 0, 1, 1, 0, 1, 2, 0, 0]),
228 (0, String::from("DMA"), String::from("Reserve"), [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
229 (0, String::from("DMA"), String::from("CMA"), [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
230 (0, String::from("DMA"), String::from("Isolate"), [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
231 (0, String::from("DMA32"), String::from("Unmovable"), [148, 77, 109, 136, 20, 7, 0, 0, 0, 0, 0]),
232 (0, String::from("DMA32"), String::from("Reclaimable"), [ 31, 135, 247, 159, 31, 11, 3, 0, 0, 0, 0]),
233 (0, String::from("DMA32"), String::from("Movable"), [452, 198, 246, 1628, 565, 17, 18, 16, 11, 1, 0]),
234 (0, String::from("DMA32"), String::from("Reserve"), [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
235 (0, String::from("DMA32"), String::from("CMA"), [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
236 (0, String::from("DMA32"), String::from("Isolate"), [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
237 ],
238 blocks_type_number: vec![
239 (0, String::from("DMA"), [ 2, 1, 5, 0, 0, 0]),
240 (0, String::from("DMA32"), [74, 42, 756, 0, 0, 0]),
241 ]
242 };
243 assert_eq!(correct, source.parse::<PageTypeInfo>().unwrap());
244 }
245}