Skip to main content

lpfs/proc/
pagetypeinfo.rs

1//! > cat /proc/pagetypeinfo
2//! > 
3//! > Page block order: 9
4//! > Pages per block:  512
5//! > Free pages count per migrate type at order       0      1      2      3      4      5      6      7      8      9     10
6//! > Node    0, zone      DMA, type    Unmovable      0      0      0      1      1      1      1      1      1      1      0
7//! > Node    0, zone      DMA, type  Reclaimable      0      0      0      0      0      0      0      0      0      0      0
8//! > Node    0, zone      DMA, type      Movable      1      1      2      1      2      1      1      0      1      0      2
9//! > Node    0, zone      DMA, type      Reserve      0      0      0      0      0      0      0      0      0      1      0
10//! > Node    0, zone      DMA, type      Isolate      0      0      0      0      0      0      0      0      0      0      0
11//! > Node    0, zone    DMA32, type    Unmovable    103     54     77      1      1      1     11      8      7      1      9
12//! > Node    0, zone    DMA32, type  Reclaimable      0      0      2      1      0      0      0      0      1      0      0
13//! > Node    0, zone    DMA32, type      Movable    169    152    113     91     77     54     39     13      6      1    452
14//! > Node    0, zone    DMA32, type      Reserve      1      2      2      2      2      0      1      1      1      1      0
15//! > Node    0, zone    DMA32, type      Isolate      0      0      0      0      0      0      0      0      0      0      0
16//! > Number of blocks type     Unmovable  Reclaimable      Movable      Reserve      Isolate
17//! > Node 0, zone      DMA            2            0            5            1            0
18//! > Node 0, zone    DMA32           41            6          967            2            0
19//! >
20//! > Fragmentation avoidance in the kernel works by grouping pages of different
21//! > migrate types into the same contiguous regions of memory called page blocks.
22//! > A page block is typically the size of the default hugepage size e.g. 2MB on
23//! > X86-64. By keeping pages grouped based on their ability to move, the kernel
24//! > can reclaim pages within a page block to satisfy a high-order allocation.
25//! > The pagetypinfo begins with information on the size of a page block. It
26//! > then gives the same type of information as buddyinfo except broken down
27//! > by migrate-type and finishes with details on how many page blocks of each
28//! > type exist.
29//! > If min_free_kbytes has been tuned correctly (recommendations made by hugeadm
30//! > from libhugetlbfs http://sourceforge.net/projects/libhugetlbfs/), one can
31//! > make an estimate of the likely number of huge pages that can be allocated
32//! > at a given point in time. All the "Movable" blocks should be allocatable
33//! > unless memory has been mlock()'d. Some of the Reclaimable blocks should
34//! > also be allocatable although a lot of filesystem metadata may have to be
35//! > reclaimed to achieve this.
36//! > 
37//! > -- https://android.googlesource.com/kernel/msm/+/android-wear-5.1.1_r0.6/Documentation/filesystems/proc.txt?autodive=0%2F%2F%2F#716
38//! 
39
40define_struct! {
41    /// Represent the content of /proc/pagetypeinfo, returned by [`pagetypeinfo()`](fn.pagetypeinfo.html)
42    /// 
43    /// Reference to [`mm/vmstat.c`](https://github.com/torvalds/linux/blob/master/mm/vmstat.c#L1372)
44    /// 
45    /// See [`free_pages()`](struct.PageTypeInfo.html#method.free_pages), 
46    /// [`blocks_type_number()`](struct.PageTypeInfo.html#method.blocks_type_number) for details.
47    pub struct PageTypeInfo {
48        page_block_order: i32,
49        pages_per_block: u64,
50        /// (node, zone, type, counts)
51        free_pages: Vec<(i32, String, String, [u64;11])>,
52        /// (node, zone, counts)
53        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}