Skip to content

An efficient, zero-allocations /proc/meminfo parsing library for Rust.

License

Notifications You must be signed in to change notification settings

marcoradocchia/linux-meminfo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Linux MemInfo

GitHub source size GitHub open issues GitHub open pull requests GitHub sponsors GitHub license Crates.io downloads Crates.io version

This library provides easy and low level access to meminfo, the pseudofile placed by the Linux kernel inside the proc pseudo-filesystem (for more information, see the proc manpage).

The public API is built around the MemInfo type, a struct responsible for retrieving memory-related information about the system. Calling its constructor opens the /proc/meminfo pseudofile and reads its data into an internal buffer. Having MemInfo to own both the open file and a buffer of its data allows separation of concerns between reading from the pseudofile, managing and parsing the buffered data.

The parser implementation responsible for parsing /proc/meminfo entries works exclusively on string slices, just owning a reference to the pseudofile buffered bytes. This allows for efficient, zero-allocation parsing.

Examples

The following example shows the most basic usage of the MemInfo API. First we construct a new instance, which translates to /proc/meminfo being opened and read into the internal buffer; then we call the MemInfo::parse, which returns a lazy iterator over parsed entries, in this case represented by the MemInfoEntry type. The iterator being lazy meaning it parses a new entry on each call to the next method. In other words: you only pay for the entries you parse.

use std::error;

use meminfo::MemInfo;

fn main() -> Result<(), Box<dyn error::Error>> {
    let mut meminfo = MemInfo::new()?;
    let mut entries = meminfo.parse();

    let mem_total = entries.next().unwrap();
    assert_eq!("MemTotal", mem_total.label());
    assert_eq!(Some("kB"), mem_total.unit());

    println!("System's total usable RAM: {}kB", mem_total.size()?);

    Ok(())
}

Users may have distinct use cases that call for regular retrieval of a particular set of entries within the /proc/meminfo pseudofile. The MemInfo::parse_extended efficiently addresses this requirement, extending parsed entries with additional information pertaining to the byte range they occupy in the file stream. This functionality allows users to selectively read and parse specific entries as needed. Also, this way, the internal buffer can be shrank to the capacity required to read in such entries, reducing the runtime memory footprint of the program.

use std::io::SeekFrom;
use std::time::Duration;
use std::{error, thread};

use meminfo::{MemInfo, MemInfoError};

#[derive(Debug)]
struct MemAvailable {
    size: usize,
    start_pos: usize,
}

impl MemAvailable {
    fn new(meminfo: &mut MemInfo) -> Result<Self, MemInfoError> {
        let mut entries = meminfo.parse_extended().skip(2);

        let mem_available = entries.next().unwrap();
        assert_eq!("MemAvailable", mem_available.label());
        assert_eq!(Some("kB"), mem_available.unit());

        let size = mem_available.size().unwrap();
        let start_pos = mem_available.start_pos();
        let capacity = mem_available.required_capacity();

        drop(entries);
        meminfo.clear();
        meminfo.shrink_to(capacity);

        Ok(MemAvailable { size, start_pos })
    }

    fn fetch(&mut self, meminfo: &mut MemInfo) -> Result<(), MemInfoError> {
        let seek_pos = SeekFrom::Start(self.start_pos as u64);
        meminfo.seek(seek_pos)?;

        meminfo.clear();
        meminfo.read()?;

        let entry = meminfo.parse().next().unwrap();
        self.size = entry.size().unwrap();

        Ok(())
    }
}

fn main() -> Result<(), Box<dyn error::Error>> {
    let mut meminfo = MemInfo::new()?;
    let mut mem_available = MemAvailable::new(&mut meminfo)?;

    loop {
        println!("System's available RAM: {}kB", mem_available.size);
        thread::sleep(Duration::from_secs(2));
        mem_available.fetch(&mut meminfo)?;
    }
}

Usage

To use this library in your project, run the following command in your project root directory:

cargo add linux-meminfo

Features

By default, the MemInfoEntry and MemInfoEntryExtended constructors perform UTF-8 validation on /proc/meminfo parsed data. Malformed data would cause a panic in this case. However, enabling the utf8-unchecked feature removes such validation, potentially increasing parsing performance. To achieve this, the new constructors make use of unsafe code, thus the user should be aware that malformed /proc/meminfo data would cause undefined behaviour.

To opt-in such feature, run the following command in your the project root directory:

cargo add linux-meminfo --features=utf8-unchecked

License

This library is licensed under the terms of the GPLv3 license.

Contributions

Any contribution is welcome and encouraged.

About

An efficient, zero-allocations /proc/meminfo parsing library for Rust.

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Languages