blob: aa138a83e6066a8cfa8a3ab01f03c2bdb812c381 [file] [log] [blame]
// Copyright 2024, The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! This module provides functions to load zram stats.
#[cfg(test)]
mod tests;
use std::ops::Deref;
use crate::zram::SysfsZramApi;
/// Error from loading zram stats.
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Stat file format is invalid.
#[error("failed to parse")]
Parse,
/// Failed to read stat file.
#[error("failed to read: {0}")]
Io(#[from] std::io::Error),
}
type Result<T> = std::result::Result<T, Error>;
fn parse_next<T: std::str::FromStr>(
iter: &mut impl Iterator<Item = impl Deref<Target = str>>,
) -> Result<T> {
iter.next().ok_or(Error::Parse)?.parse().map_err(|_| Error::Parse)
}
fn parse_next_optional<T: std::str::FromStr>(
iter: &mut impl Iterator<Item = impl Deref<Target = str>>,
) -> Result<Option<T>> {
iter.next().map(|v| v.parse()).transpose().map_err(|_| Error::Parse)
}
/// Loads /sys/block/zram0/disksize
pub fn load_total_zram_size<Z: SysfsZramApi>() -> Result<u64> {
let contents = Z::read_disksize()?;
contents.trim().parse().map_err(|_| Error::Parse)
}
/// Stats from /sys/block/zram0/mm_stat
#[derive(Debug, Default, PartialEq, Eq)]
pub struct ZramMmStat {
/// Uncompressed size of data stored in this disk. This excludes same-element-filled pages
/// (same_pages) since no memory is allocated for them. Unit: bytes
pub orig_data_size: u64,
/// Compressed size of data stored in this disk.
pub compr_data_size: u64,
/// The amount of memory allocated for this disk. This includes allocator fragmentation and
/// metadata overhead, allocated for this disk. So, allocator space efficiency can be calculated
/// using compr_data_size and this statistic. Unit: bytes
pub mem_used_total: u64,
/// The maximum amount of memory ZRAM can use to store The compressed data.
pub mem_limit: u32,
/// The maximum amount of memory zram have consumed to store the data.
///
/// In zram_drv.h we define max_used_pages as atomic_long_t which could be negative, but
/// negative value does not make sense for the variable.
pub mem_used_max: i64,
/// The number of same element filled pages written to this disk. No memory is allocated for
/// such pages.
pub same_pages: u64,
/// The number of pages freed during compaction.
pub pages_compacted: u32,
/// The number of incompressible pages.
/// Start supporting from v4.19.
pub huge_pages: Option<u64>,
/// The number of huge pages since zram set up.
/// Start supporting from v5.15.
pub huge_pages_since: Option<u64>,
}
impl ZramMmStat {
/// Parse /sys/block/zram0/mm_stat.
pub fn load<Z: SysfsZramApi>() -> Result<Self> {
let contents = Z::read_mm_stat()?;
let mut values = contents.split_whitespace();
Ok(ZramMmStat {
orig_data_size: parse_next(&mut values)?,
compr_data_size: parse_next(&mut values)?,
mem_used_total: parse_next(&mut values)?,
mem_limit: parse_next(&mut values)?,
mem_used_max: parse_next(&mut values)?,
same_pages: parse_next(&mut values)?,
pages_compacted: parse_next(&mut values)?,
huge_pages: parse_next_optional(&mut values)?,
huge_pages_since: parse_next_optional(&mut values)?,
})
}
}
/// Stats from /sys/block/zram0/bd_stat
#[derive(Debug, Default, PartialEq, Eq)]
pub struct ZramBdStat {
/// Size of data written in backing device. Unit: page
pub bd_count_pages: u64,
/// The number of reads from backing device. Unit: page
pub bd_reads_pages: u64,
/// The number of writes to backing device. Unit: page
pub bd_writes_pages: u64,
}
impl ZramBdStat {
/// Parse /sys/block/zram0/bd_stat.
pub fn load<Z: SysfsZramApi>() -> Result<Self> {
let contents = Z::read_bd_stat()?;
let mut values = contents.split_whitespace();
Ok(ZramBdStat {
bd_count_pages: parse_next(&mut values)?,
bd_reads_pages: parse_next(&mut values)?,
bd_writes_pages: parse_next(&mut values)?,
})
}
}