Files
logViewer/crates/bench/src/suites/memory.rs
dailz e6e0e2cc90 fix(bench): correct lines_read to actual successful reads in bench_scroll_rss
lines_read was incorrectly set to max_lines.min(total) (the loop upper bound)
instead of the actual number of successfully read lines. Now tracks lines_read
via get_line(i).is_some() counter and uses max_lines.min(total) as the correct
loop upper bound to handle empty file edge case.

Fixes #43
2026-06-07 08:50:20 +08:00

238 lines
7.2 KiB
Rust

use std::collections::HashMap;
use crate::metrics::MetricsCollector;
use crate::mmap_reader::{
MmapReaderPhaseAware, MmapReaderPlain, MmapReaderPopulate, MmapReaderRandom,
MmapReaderSequential,
};
use crate::pread_reader::{PreadReaderPlain, PreadReaderRandom, PreadReaderSequential};
use crate::runner::BenchConfig;
use crate::types::BenchmarkResult;
use crate::FileReaderBackend;
pub fn run(config: &BenchConfig) -> Vec<BenchmarkResult> {
let mut results = Vec::new();
results.extend(bench_idle_rss::<MmapReaderPlain>("mmap", "plain", config));
results.extend(bench_idle_rss::<MmapReaderSequential>(
"mmap",
"sequential",
config,
));
results.extend(bench_idle_rss::<MmapReaderRandom>("mmap", "random", config));
results.extend(bench_idle_rss::<MmapReaderPopulate>(
"mmap", "populate", config,
));
results.extend(bench_idle_rss::<MmapReaderPhaseAware>(
"mmap",
"phase_aware",
config,
));
results.extend(bench_idle_rss::<PreadReaderPlain>("pread", "plain", config));
results.extend(bench_idle_rss::<PreadReaderRandom>(
"pread", "random", config,
));
results.extend(bench_idle_rss::<PreadReaderSequential>(
"pread",
"sequential",
config,
));
results.extend(bench_scroll_rss::<MmapReaderPlain>("mmap", "plain", config));
results.extend(bench_scroll_rss::<PreadReaderPlain>(
"pread", "plain", config,
));
results.extend(bench_jump_end_rss::<MmapReaderPlain>(
"mmap", "plain", config,
));
results.extend(bench_jump_end_rss::<PreadReaderPlain>(
"pread", "plain", config,
));
results.extend(bench_rss_reclaim::<MmapReaderPlain>(
"mmap", "plain", config,
));
results.extend(bench_rss_reclaim::<PreadReaderPlain>(
"pread", "plain", config,
));
results
}
fn bench_idle_rss<B: FileReaderBackend>(
backend: &str,
variant: &str,
config: &BenchConfig,
) -> Vec<BenchmarkResult> {
let reader = B::open(&config.test_file).expect("Failed to open file");
let rss = MetricsCollector::read_rss();
let faults = MetricsCollector::read_page_faults();
let mut extra = HashMap::new();
extra.insert("total_lines".into(), reader.total_lines() as f64);
extra.insert(
"file_size_mb".into(),
reader.file_size() as f64 / (1024.0 * 1024.0),
);
reader.close();
vec![BenchmarkResult {
category: "memory".into(),
test_name: "idle_rss".into(),
backend: backend.into(),
variant: variant.into(),
latency_us: vec![],
rss_kb: rss.vm_rss_kb,
rss_peak_kb: rss.vm_hwm_kb,
page_faults: faults.minor_faults + faults.major_faults,
extra,
}]
}
fn bench_scroll_rss<B: FileReaderBackend>(
backend: &str,
variant: &str,
config: &BenchConfig,
) -> Vec<BenchmarkResult> {
let reader = B::open(&config.test_file).expect("Failed to open file");
let total = reader.total_lines();
let sample_interval = 100_000;
let max_lines = if config.quick_mode { 100_000 } else { total };
let upper = max_lines.min(total);
let mut rss_samples = Vec::new();
let mut hwm_samples = Vec::new();
let mut lines_read = 0usize;
for i in (0..upper).step_by(sample_interval) {
if reader.get_line(i).is_some() {
lines_read += 1;
}
let rss = MetricsCollector::read_rss();
rss_samples.push(rss.vm_rss_kb);
hwm_samples.push(rss.vm_hwm_kb);
}
let final_rss = MetricsCollector::read_rss();
let faults = MetricsCollector::read_page_faults();
let mut extra = HashMap::new();
extra.insert("rss_samples_count".into(), rss_samples.len() as f64);
extra.insert(
"max_rss_kb".into(),
rss_samples.iter().copied().fold(0u64, u64::max) as f64,
);
extra.insert(
"max_hwm_kb".into(),
hwm_samples.iter().copied().fold(0u64, u64::max) as f64,
);
extra.insert("lines_read".into(), lines_read as f64);
reader.close();
vec![BenchmarkResult {
category: "memory".into(),
test_name: "scroll_rss".into(),
backend: backend.into(),
variant: variant.into(),
latency_us: vec![],
rss_kb: final_rss.vm_rss_kb,
rss_peak_kb: final_rss.vm_hwm_kb,
page_faults: faults.minor_faults + faults.major_faults,
extra,
}]
}
fn bench_jump_end_rss<B: FileReaderBackend>(
backend: &str,
variant: &str,
config: &BenchConfig,
) -> Vec<BenchmarkResult> {
let reader = B::open(&config.test_file).expect("Failed to open file");
let total = reader.total_lines();
let last_line = total.saturating_sub(1);
let _ = reader.get_line(last_line);
let rss = MetricsCollector::read_rss();
let faults = MetricsCollector::read_page_faults();
let mut extra = HashMap::new();
extra.insert("last_line_idx".into(), last_line as f64);
extra.insert("total_lines".into(), total as f64);
reader.close();
vec![BenchmarkResult {
category: "memory".into(),
test_name: "jump_end_rss".into(),
backend: backend.into(),
variant: variant.into(),
latency_us: vec![],
rss_kb: rss.vm_rss_kb,
rss_peak_kb: rss.vm_hwm_kb,
page_faults: faults.minor_faults + faults.major_faults,
extra,
}]
}
fn bench_rss_reclaim<B: FileReaderBackend>(
backend: &str,
variant: &str,
config: &BenchConfig,
) -> Vec<BenchmarkResult> {
let reader = B::open(&config.test_file).expect("Failed to open file");
let total = reader.total_lines();
let last_line = total.saturating_sub(1);
let _ = reader.get_line(last_line);
let wait_secs: u64 = if config.quick_mode { 5 } else { 30 };
let sample_interval: u64 = 5;
let num_samples = (wait_secs / sample_interval) as usize;
let mut rss_samples = Vec::with_capacity(num_samples);
let mut hwm_samples = Vec::with_capacity(num_samples);
for _ in 0..num_samples {
std::thread::sleep(std::time::Duration::from_secs(sample_interval));
let rss = MetricsCollector::read_rss();
rss_samples.push(rss.vm_rss_kb);
hwm_samples.push(rss.vm_hwm_kb);
}
let final_rss = MetricsCollector::read_rss();
let faults = MetricsCollector::read_page_faults();
reader.close();
let mut extra = HashMap::new();
extra.insert("wait_total_secs".into(), wait_secs as f64);
extra.insert("rss_samples".into(), rss_samples.len() as f64);
if let (Some(&first), Some(&last)) = (rss_samples.first(), rss_samples.last()) {
extra.insert("rss_first_kb".into(), first as f64);
extra.insert("rss_last_kb".into(), last as f64);
extra.insert(
"rss_change_pct".into(),
if first > 0 {
((last as f64 - first as f64) / first as f64) * 100.0
} else {
0.0
},
);
}
vec![BenchmarkResult {
category: "memory".into(),
test_name: "rss_reclaim".into(),
backend: backend.into(),
variant: variant.into(),
latency_us: vec![],
rss_kb: final_rss.vm_rss_kb,
rss_peak_kb: final_rss.vm_hwm_kb,
page_faults: faults.minor_faults + faults.major_faults,
extra,
}]
}