fn build_pool_stats_output(
pool_stats: &rustc_hash::FxHashMap<
crate::services::memory_manager::PoolType,
crate::services::memory_manager::PoolStats,
>,
) -> HashMap<String, PoolStatsOutput> {
let mut pool_stats_output = HashMap::new();
for (pool_type, pool_stats) in pool_stats {
let efficiency_rating = calculate_pool_efficiency_rating(pool_stats.reuse_ratio);
pool_stats_output.insert(
format!("{pool_type:?}"),
PoolStatsOutput {
buffer_count: pool_stats.buffer_count,
total_size: pool_stats.total_size,
allocation_count: pool_stats.allocation_count,
reuse_count: pool_stats.reuse_count,
reuse_ratio: pool_stats.reuse_ratio,
efficiency_rating: efficiency_rating.to_string(),
},
);
}
pool_stats_output
}
fn nothing_was_recorded(stats: &crate::services::memory_manager::MemoryStats) -> bool {
stats.total_allocated == 0
&& stats.peak_usage == 0
&& stats
.pool_stats
.values()
.all(|p| p.allocation_count == 0 && p.reuse_count == 0)
}
const NO_MEMORY_DATA_NOTE: &str =
"No allocations were recorded in this process: `pmat memory` reads the in-process pool \
manager, which starts empty, so these counters measure nothing.";
fn generate_memory_recommendations(
stats: &crate::services::memory_manager::MemoryStats,
) -> Vec<String> {
if nothing_was_recorded(stats) {
return vec![NO_MEMORY_DATA_NOTE.to_string()];
}
let mut recommendations = Vec::new();
add_pressure_recommendations(&mut recommendations, stats.allocation_pressure);
add_pool_efficiency_recommendations(&mut recommendations, &stats.pool_stats);
if recommendations.is_empty() {
recommendations.push("Memory usage is optimal.".to_string());
}
recommendations
}
fn add_pressure_recommendations(recommendations: &mut Vec<String>, allocation_pressure: f64) {
if allocation_pressure > 0.9 {
recommendations.push(
"CRITICAL: Memory pressure very high. Consider reducing workload or increasing limits."
.to_string(),
);
} else if allocation_pressure > 0.8 {
recommendations.push("WARNING: High memory pressure. Monitor usage closely.".to_string());
}
}
fn add_pool_efficiency_recommendations(
recommendations: &mut Vec<String>,
pool_stats: &rustc_hash::FxHashMap<
crate::services::memory_manager::PoolType,
crate::services::memory_manager::PoolStats,
>,
) {
for (pool_type, pool_stats) in pool_stats {
if pool_stats.allocation_count == 0 {
continue;
}
if pool_stats.reuse_ratio < 0.3 {
recommendations.push(format!(
"Pool {:?} has low reuse efficiency ({:.1}%). Consider adjusting pool size.",
pool_type,
pool_stats.reuse_ratio * 100.0
));
}
}
}
fn output_memory_stats(output: &MemoryStatsOutput, format: &str, detailed: bool) -> Result<()> {
match format {
"json" => output_json_format(output),
"csv" => output_csv_format(output),
"table" => print_memory_stats_table(output, detailed),
_ => print_memory_stats_table(output, detailed),
}
}
fn output_json_format(output: &MemoryStatsOutput) -> Result<()> {
println!("{}", serde_json::to_string_pretty(output)?);
Ok(())
}
fn output_csv_format(output: &MemoryStatsOutput) -> Result<()> {
println!("metric,value");
println!("total_allocated,{}", output.total_allocated);
println!("peak_usage,{}", output.peak_usage);
println!("allocation_pressure,{:.3}", output.allocation_pressure);
println!("string_intern_size,{}", output.string_intern_size);
Ok(())
}
fn print_memory_stats_table(stats: &MemoryStatsOutput, detailed: bool) -> Result<()> {
print_header();
print_overall_stats(stats);
if detailed {
print_pool_stats(&stats.pool_stats);
}
print_recommendations(&stats.recommendations);
Ok(())
}
fn print_header() {
use crate::cli::colors as c;
println!("{}", c::header("PMAT Memory Statistics"));
println!();
}
fn print_overall_stats(stats: &MemoryStatsOutput) {
use crate::cli::colors as c;
println!("{}", c::subheader("Overall Memory Usage:"));
println!(" {}: {}", c::label("Total Allocated"), c::number(&format_bytes(stats.total_allocated)));
println!(" {}: {}", c::label("Peak Usage"), c::number(&format_bytes(stats.peak_usage)));
println!(
" {}: {}",
c::label("Pressure"),
c::pct_inverse(stats.allocation_pressure * 100.0, 30.0, 60.0)
);
println!(
" {}: {}",
c::label("String Intern"),
c::number(&format_bytes(stats.string_intern_size))
);
println!();
}
fn print_pool_stats(pool_stats: &HashMap<String, PoolStatsOutput>) {
use crate::cli::colors as c;
println!("{}", c::subheader("Pool Statistics:"));
for (pool_name, stats) in pool_stats {
print_single_pool_stats(pool_name, stats);
}
}
fn print_single_pool_stats(pool_name: &str, stats: &PoolStatsOutput) {
use crate::cli::colors as c;
println!(" {}:", c::label(pool_name));
println!(" {}: {}", c::label("Buffers"), c::number(&stats.buffer_count.to_string()));
println!(" {}: {}", c::label("Size"), c::number(&format_bytes(stats.total_size)));
println!(" {}: {}", c::label("Allocations"), c::number(&stats.allocation_count.to_string()));
println!(" {}: {}", c::label("Reuses"), c::number(&stats.reuse_count.to_string()));
let colored_rating = match stats.efficiency_rating.as_str() {
"Excellent" | "Good" => format!("{}{}{}", c::GREEN, stats.efficiency_rating, c::RESET),
"Fair" => format!("{}{}{}", c::YELLOW, stats.efficiency_rating, c::RESET),
_ => format!("{}{}{}", c::RED, stats.efficiency_rating, c::RESET),
};
println!(
" {}: {} ({})",
c::label("Efficiency"),
colored_rating,
c::pct(stats.reuse_ratio * 100.0, 80.0, 60.0)
);
println!();
}
fn print_recommendations(recommendations: &[String]) {
use crate::cli::colors as c;
println!("{}", c::subheader("Recommendations:"));
for rec in recommendations {
if rec.starts_with("CRITICAL:") {
println!(" {}", c::fail(rec));
} else if rec.starts_with("WARNING:") {
println!(" {}", c::warn(rec));
} else {
println!(" {}", c::dim(rec));
}
}
}
fn calculate_pool_efficiency_rating(reuse_ratio: f64) -> &'static str {
if reuse_ratio > 0.8 {
"Excellent"
} else if reuse_ratio > 0.6 {
"Good"
} else if reuse_ratio > 0.4 {
"Fair"
} else {
"Poor"
}
}
fn format_bytes(bytes: usize) -> String {
batuta_common::fmt::format_bytes(bytes as u64)
}
#[cfg(test)]
mod unrecorded_memory_tests {
use super::{generate_memory_recommendations, nothing_was_recorded};
use crate::services::memory_manager::{MemoryStats, PoolStats, PoolType};
fn stats_with(pool: PoolStats, total_allocated: usize) -> MemoryStats {
let mut pool_stats = rustc_hash::FxHashMap::default();
pool_stats.insert(PoolType::AstParsing, pool);
MemoryStats {
total_allocated,
pool_stats,
string_intern_size: 0,
peak_usage: total_allocated,
allocation_pressure: 0.0,
}
}
fn empty_pool() -> PoolStats {
PoolStats {
buffer_count: 0,
total_size: 0,
allocation_count: 0,
reuse_count: 0,
reuse_ratio: 0.0,
}
}
#[test]
fn test_untouched_pools_yield_a_not_measured_note_not_tuning_advice() {
let stats = stats_with(empty_pool(), 0);
assert!(nothing_was_recorded(&stats));
let recommendations = generate_memory_recommendations(&stats);
assert_eq!(recommendations.len(), 1);
assert!(
!recommendations[0].contains("low reuse efficiency"),
"a pool that was never used cannot have low reuse efficiency: {:?}",
recommendations[0]
);
assert!(recommendations[0].contains("measure nothing"));
}
#[test]
fn test_a_used_pool_with_poor_reuse_still_gets_advice() {
let used = PoolStats {
buffer_count: 4,
total_size: 4096,
allocation_count: 100,
reuse_count: 5,
reuse_ratio: 0.05,
};
let stats = stats_with(used, 4096);
assert!(!nothing_was_recorded(&stats));
let recommendations = generate_memory_recommendations(&stats);
assert!(
recommendations
.iter()
.any(|r| r.contains("low reuse efficiency")),
"measured poor reuse must still be reported: {recommendations:?}"
);
}
}