blob: befc1e2544e21d5819758a6b5537af4699efb45b [file] [log] [blame]
// Copyright 2025 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use starnix_core::mm::PAGE_SIZE;
use starnix_core::task::{CurrentTask, KernelStats};
use starnix_core::vfs::FsNodeOps;
use starnix_core::vfs::pseudo::dynamic_file::{DynamicFile, DynamicFileBuf, DynamicFileSource};
use starnix_logging::log_error;
use starnix_uapi::errno;
use starnix_uapi::errors::Errno;
use std::sync::Arc;
#[derive(Clone)]
pub struct ZoneInfoFile {
kernel_stats: Arc<KernelStats>,
}
impl ZoneInfoFile {
pub fn new_node(kernel_stats: &Arc<KernelStats>) -> impl FsNodeOps {
DynamicFile::new_node(Self { kernel_stats: kernel_stats.clone() })
}
}
impl DynamicFileSource for ZoneInfoFile {
fn generate(
&self,
_current_task: &CurrentTask,
sink: &mut DynamicFileBuf,
) -> Result<(), Errno> {
let mem_stats = self
.kernel_stats
.get()
.get_memory_stats_extended(zx::MonotonicInstant::INFINITE)
.map_err(|e| {
log_error!("FIDL error getting memory stats: {e}");
errno!(EIO)
})?;
let userpager_total = mem_stats.vmo_pager_total_bytes.unwrap_or_default() / *PAGE_SIZE;
let userpager_active = mem_stats.vmo_pager_newest_bytes.unwrap_or_default() / *PAGE_SIZE;
let nr_active_file = userpager_active;
let nr_inactive_file = userpager_total.saturating_sub(userpager_active);
let free = mem_stats.free_bytes.unwrap_or_default() / *PAGE_SIZE;
let present = mem_stats.total_bytes.unwrap_or_default() / *PAGE_SIZE;
// Pages min: minimum number of free pages the kernel tries to maintain in this memory zone.
// Can be set by writing to `/proc/sys/vm/min_free_kbytes`. It is observed to be ~3% of the
// total memory.
let pages_min = present * 3 / 100;
// Pages low: more aggressive memory reclaimation when free pages fall below this level.
// Typically ~4% of the total memory.
let pages_low = present * 4 / 100;
// Pages high: page reclamation begins when free pages drop below this level.
// Typically ~4% of the total memory.
let pages_high = present * 6 / 100;
// Only required fields are written. Add more fields as needed.
writeln!(sink, "Node 0, zone Normal")?;
writeln!(sink, " per-node stats")?;
writeln!(sink, " nr_inactive_file {}", nr_inactive_file)?;
writeln!(sink, " nr_active_file {}", nr_active_file)?;
writeln!(sink, " pages free {}", free)?;
writeln!(sink, " min {}", pages_min)?;
writeln!(sink, " low {}", pages_low)?;
writeln!(sink, " high {}", pages_high)?;
writeln!(sink, " present {}", present)?;
writeln!(sink, " pagesets")?;
Ok(())
}
}