1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 //! This module provides functions to load zram stats.
16
17 #[cfg(test)]
18 mod tests;
19
20 use std::ops::Deref;
21
22 use crate::zram::SysfsZramApi;
23
24 /// Error from loading zram stats.
25 #[derive(Debug, thiserror::Error)]
26 pub enum Error {
27 /// Stat file format is invalid.
28 #[error("failed to parse")]
29 Parse,
30 /// Failed to read stat file.
31 #[error("failed to read: {0}")]
32 Io(#[from] std::io::Error),
33 }
34
35 type Result<T> = std::result::Result<T, Error>;
36
parse_next<T: std::str::FromStr>( iter: &mut impl Iterator<Item = impl Deref<Target = str>>, ) -> Result<T>37 fn parse_next<T: std::str::FromStr>(
38 iter: &mut impl Iterator<Item = impl Deref<Target = str>>,
39 ) -> Result<T> {
40 iter.next().ok_or(Error::Parse)?.parse().map_err(|_| Error::Parse)
41 }
42
parse_next_optional<T: std::str::FromStr>( iter: &mut impl Iterator<Item = impl Deref<Target = str>>, ) -> Result<Option<T>>43 fn parse_next_optional<T: std::str::FromStr>(
44 iter: &mut impl Iterator<Item = impl Deref<Target = str>>,
45 ) -> Result<Option<T>> {
46 iter.next().map(|v| v.parse()).transpose().map_err(|_| Error::Parse)
47 }
48
49 /// Loads /sys/block/zram0/disksize
load_total_zram_size<Z: SysfsZramApi>() -> Result<u64>50 pub fn load_total_zram_size<Z: SysfsZramApi>() -> Result<u64> {
51 let contents = Z::read_disksize()?;
52 contents.trim().parse().map_err(|_| Error::Parse)
53 }
54
55 /// Stats from /sys/block/zram0/mm_stat
56 #[derive(Debug, Default, PartialEq, Eq)]
57 pub struct ZramMmStat {
58 /// Uncompressed size of data stored in this disk. This excludes same-element-filled pages
59 /// (same_pages) since no memory is allocated for them. Unit: bytes
60 pub orig_data_size: u64,
61 /// Compressed size of data stored in this disk.
62 pub compr_data_size: u64,
63 /// The amount of memory allocated for this disk. This includes allocator fragmentation and
64 /// metadata overhead, allocated for this disk. So, allocator space efficiency can be calculated
65 /// using compr_data_size and this statistic. Unit: bytes
66 pub mem_used_total: u64,
67 /// The maximum amount of memory ZRAM can use to store The compressed data.
68 pub mem_limit: u32,
69 /// The maximum amount of memory zram have consumed to store the data.
70 ///
71 /// In zram_drv.h we define max_used_pages as atomic_long_t which could be negative, but
72 /// negative value does not make sense for the variable.
73 pub mem_used_max: i64,
74 /// The number of same element filled pages written to this disk. No memory is allocated for
75 /// such pages.
76 pub same_pages: u64,
77 /// The number of pages freed during compaction.
78 pub pages_compacted: u32,
79 /// The number of incompressible pages.
80 /// Start supporting from v4.19.
81 pub huge_pages: Option<u64>,
82 /// The number of huge pages since zram set up.
83 /// Start supporting from v5.15.
84 pub huge_pages_since: Option<u64>,
85 }
86
87 impl ZramMmStat {
88 /// Parse /sys/block/zram0/mm_stat.
load<Z: SysfsZramApi>() -> Result<Self>89 pub fn load<Z: SysfsZramApi>() -> Result<Self> {
90 let contents = Z::read_mm_stat()?;
91 let mut values = contents.split_whitespace();
92 Ok(ZramMmStat {
93 orig_data_size: parse_next(&mut values)?,
94 compr_data_size: parse_next(&mut values)?,
95 mem_used_total: parse_next(&mut values)?,
96 mem_limit: parse_next(&mut values)?,
97 mem_used_max: parse_next(&mut values)?,
98 same_pages: parse_next(&mut values)?,
99 pages_compacted: parse_next(&mut values)?,
100 huge_pages: parse_next_optional(&mut values)?,
101 huge_pages_since: parse_next_optional(&mut values)?,
102 })
103 }
104 }
105
106 /// Stats from /sys/block/zram0/bd_stat
107 #[derive(Debug, Default, PartialEq, Eq)]
108 pub struct ZramBdStat {
109 /// Size of data written in backing device. Unit: page
110 pub bd_count_pages: u64,
111 /// The number of reads from backing device. Unit: page
112 pub bd_reads_pages: u64,
113 /// The number of writes to backing device. Unit: page
114 pub bd_writes_pages: u64,
115 }
116
117 impl ZramBdStat {
118 /// Parse /sys/block/zram0/bd_stat.
load<Z: SysfsZramApi>() -> Result<Self>119 pub fn load<Z: SysfsZramApi>() -> Result<Self> {
120 let contents = Z::read_bd_stat()?;
121 let mut values = contents.split_whitespace();
122 Ok(ZramBdStat {
123 bd_count_pages: parse_next(&mut values)?,
124 bd_reads_pages: parse_next(&mut values)?,
125 bd_writes_pages: parse_next(&mut values)?,
126 })
127 }
128 }
129