From a26236ab5426e4a4543dc17e6d439b46bcebd6da Mon Sep 17 00:00:00 2001 From: Yang Hau Date: Sat, 3 Aug 2024 00:51:17 +0800 Subject: [PATCH] wip --- src/uu/lsmem/src/lsmem.rs | 279 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 265 insertions(+), 14 deletions(-) diff --git a/src/uu/lsmem/src/lsmem.rs b/src/uu/lsmem/src/lsmem.rs index aad467e..1249159 100644 --- a/src/uu/lsmem/src/lsmem.rs +++ b/src/uu/lsmem/src/lsmem.rs @@ -6,16 +6,18 @@ use clap::{crate_version, Command}; use uucore::{error::UResult, format_usage, help_about, help_usage}; -use std::fs; -use std::io; -use std::path::Path; +use std::borrow::BorrowMut; +use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; +use std::path::{Path, PathBuf}; +use std::{default, fs}; const ABOUT: &str = help_about!("lsmem.md"); const USAGE: &str = help_usage!("lsmem.md"); const PATH_SYS_MEMORY: &str = "/sys/devices/system/memory"; +const PATH_BLOCK_SIZE_BYTES: &str = "/sys/devices/system/memory/block_size_bytes"; -#[repr(u8)] +#[derive(PartialEq, Clone)] enum ZoneId { ZoneDma = 0, ZoneDma32, @@ -28,16 +30,110 @@ enum ZoneId { MaxNrZones, } +static ZONE_NAMES: [&str; ZoneId::MaxNrZones as usize] = [ + "DMA", "DMA32", "Normal", "Highmem", "Movable", "Device", + "None", // Block contains more than one zone, can't be offlined + "Unknown", +]; + +#[derive(PartialEq, Clone)] +enum MemoryState { + Online = 0, + Offline, + GoingOffline, + Unknown, +} + +#[derive(Clone)] struct MemoryBlock { index: u64, count: u64, - state: i32, + state: MemoryState, node: i32, - nr_zones: i32, - zones: [i32; ZoneId::MaxNrZones as usize], + nr_zones: usize, + zones: [ZoneId; ZoneId::MaxNrZones as usize], removable: u8, } +struct Lsmem { + ndirs: usize, + dirs: Vec, + blocks: Vec, + nblocks: usize, + block_size: u64, + mem_online: u64, + mem_offline: u64, + + have_nodes: bool, + raw: bool, + export: bool, + json: bool, + noheadings: bool, + summary: bool, + list_all: bool, + bytes: bool, + want_summary: bool, + want_table: bool, + split_by_node: bool, + split_by_state: bool, + split_by_removable: bool, + split_by_zones: bool, + have_zones: bool, +} + +impl Lsmem { + fn new() -> Lsmem { + Lsmem { + ndirs: 0, + dirs: Vec::default(), + blocks: Vec::default(), + nblocks: 0, + block_size: 0, + mem_online: 0, + mem_offline: 0, + + have_nodes: false, + raw: false, + export: false, + json: false, + noheadings: false, + summary: false, + list_all: false, + bytes: false, + want_summary: false, + want_table: false, + split_by_node: false, + split_by_state: false, + split_by_removable: false, + split_by_zones: false, + have_zones: false, + } + } +} + +fn read_info() -> Lsmem { + let mut lsmem = Lsmem::new(); + lsmem.block_size = read_block_size_bytes().unwrap(); + let mut blocks = get_blocks(); + lsmem.ndirs = blocks.len(); + + for i in 0..lsmem.ndirs { + let blk = blocks[i].borrow_mut(); + if blk.state == MemoryState::Online { + lsmem.mem_online += lsmem.block_size; + } else { + lsmem.mem_offline += lsmem.block_size; + } + if is_mergeable(&lsmem, &blk) { + blocks[lsmem.nblocks - 1].count += 1; + continue; + } + lsmem.nblocks += 1; + lsmem.blocks.push(blk.clone()); + } + return lsmem; +} + fn get_blocks() -> Vec { let mut blocks = Vec::::new(); @@ -46,22 +142,177 @@ fn get_blocks() -> Vec { return blocks; } -fn list_files_and_folders>(path: P) -> io::Result<()> { +fn is_mergeable(lsmem: &Lsmem, blk: &MemoryBlock) -> bool { + if lsmem.nblocks == 0 { + return false; + } + + if lsmem.list_all { + return false; + } + + let curr_block = &lsmem.blocks[lsmem.nblocks - 1]; + if curr_block.index + curr_block.count != blk.index { + return false; + } + if lsmem.split_by_state && curr_block.state != blk.state { + return false; + } + if lsmem.split_by_removable && curr_block.removable != blk.removable { + return false; + } + if lsmem.split_by_node && lsmem.have_nodes { + if curr_block.node != blk.node { + return false; + } + } + if lsmem.split_by_zones && lsmem.have_zones { + if curr_block.nr_zones != blk.nr_zones { + return false; + } + + for i in 0..curr_block.nr_zones { + if curr_block.zones[i] == ZoneId::ZoneUnknown || curr_block.zones[i] != blk.zones[i] { + return false; + } + } + } + + return true; +} + +fn print_summary(lsmem: &Lsmem) { + if lsmem.bytes { + println!("{:<23} {:>15}", "Memory block size:", lsmem.block_size); + println!("{:<23} {:>15}", "Total online memory:", lsmem.mem_online); + println!("{:<23} {:>15}", "Total offline memory:", lsmem.mem_offline); + } else { + println!( + "{:<23} {:>15}", + "Memory block size:", + size_to_human_string(lsmem.block_size) + ); + println!( + "{:<23} {:>15}", + "Total online memory:", + size_to_human_string(lsmem.mem_online) + ); + println!( + "{:<23} {:>15}", + "Total offline memory:", + size_to_human_string(lsmem.mem_offline) + ); + } +} + +fn size_to_human_string(bytes: u64) -> String { + // char buf[32]; + // int dec, exp; + // uint64_t frac; + // const char *letters = "BKMGTPE"; + // char suffix[sizeof(" KiB")], *psuf = suffix; + // char c; + + // if (options & SIZE_SUFFIX_SPACE) + // *psuf++ = ' '; + + // exp = get_exp(bytes); + // c = *(letters + (exp ? exp / 10 : 0)); + // dec = exp ? bytes / (1ULL << exp) : bytes; + // frac = exp ? bytes % (1ULL << exp) : 0; + + // *psuf++ = c; + + // if ((options & SIZE_SUFFIX_3LETTER) && (c != 'B')) { + // *psuf++ = 'i'; + // *psuf++ = 'B'; + // } + + // *psuf = '\0'; + + // /* fprintf(stderr, "exp: %d, unit: %c, dec: %d, frac: %jd\n", + // * exp, suffix[0], dec, frac); + // */ + // /* round */ + // if (frac) { + // /* get 3 digits after decimal point */ + // if (frac >= UINT64_MAX / 1000) + // frac = ((frac / 1024) * 1000) / (1ULL << (exp - 10)) ; + // else + // frac = (frac * 1000) / (1ULL << (exp)) ; + + // if (options & SIZE_DECIMAL_2DIGITS) { + // /* round 4/5 and keep 2 digits after decimal point */ + // frac = (frac + 5) / 10 ; + // } else { + // /* round 4/5 and keep 1 digit after decimal point */ + // frac = ((frac + 50) / 100) * 10 ; + // } + + // /* rounding could have overflowed */ + // if (frac == 100) { + // dec++; + // frac = 0; + // } + // } + + // if (frac) { + // struct lconv const *l = localeconv(); + // char *dp = l ? l->decimal_point : NULL; + // int len; + + // if (!dp || !*dp) + // dp = "."; + + // len = snprintf(buf, sizeof(buf), "%d%s%02" PRIu64, dec, dp, frac); + // if (len > 0 && (size_t) len < sizeof(buf)) { + // /* remove potential extraneous zero */ + // if (buf[len - 1] == '0') + // buf[len--] = '\0'; + // /* append suffix */ + // xstrncpy(buf+len, suffix, sizeof(buf) - len); + // } else + // *buf = '\0'; /* snprintf error */ + // } else + // snprintf(buf, sizeof(buf), "%d%s", dec, suffix); + + // return strdup(buf); + todo!("todo") +} + +fn list_files_and_folders>(path: P) -> io::Result> { + let mut paths = Vec::::new(); for entry in fs::read_dir(path)? { let entry = entry?; let path = entry.path(); - if path.is_dir() { - println!("Directory: {:?}", path); - } else { - println!("File: {:?}", path); + let filename_str = path.to_string_lossy(); + if path.is_dir() && filename_str.starts_with("memory") { + paths.push(path); } } - Ok(()) + + Ok(paths) +} + +fn read_block_size_bytes() -> io::Result { + // Open the file + let file = fs::File::open("/sys/devices/system/memory/block_size_bytes")?; + + // Create a buffered reader + let mut reader = io::BufReader::new(file); + + // Read the contents into a String + let mut content = String::new(); + reader.read_line(&mut content)?; + + // Return the trimmed content to remove any trailing newline + Ok(content.trim().to_string().parse().unwrap()) } #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { - get_blocks(); + let lsmem = read_info(); + print_summary(&lsmem); let _matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?; Ok(()) }