#![allow(clippy::panic, clippy::unwrap_used, clippy::expect_used)]
use perl_workspace_index::workspace::memory::{MemorySnapshot, ScaleReport};
use perl_workspace_index::workspace_index::WorkspaceIndex;
use std::time::Instant;
use url::Url;
fn generate_module(idx: usize) -> (Url, String) {
let uri = Url::parse(&format!("file:///lib/Gen/Module{}.pm", idx))
.expect("valid uri for synthetic module");
let src = format!(
r#"package Gen::Module{idx};
use strict;
use warnings;
our $VERSION = '1.00';
sub new {{
my $class = shift;
return bless {{}}, $class;
}}
sub method_a_{idx} {{
my ($self, $x) = @_;
return $x + {idx};
}}
sub method_b_{idx} {{
my ($self, $y) = @_;
return $y * {idx};
}}
sub method_c_{idx} {{
my ($self) = @_;
return "module_{idx}";
}}
sub _private_{idx} {{
return {idx};
}}
1;
"#
);
(uri, src)
}
fn build_index_at_scale(file_count: usize) -> WorkspaceIndex {
let index = WorkspaceIndex::new();
for i in 0..file_count {
let (uri, src) = generate_module(i);
index.index_file(uri, src).ok();
}
index
}
fn run_profile(scales: &[usize]) -> ScaleReport {
let mut report = ScaleReport::new();
for &scale in scales {
let t0 = Instant::now();
let index = build_index_at_scale(scale);
let build_ms = t0.elapsed().as_millis();
let snap = MemorySnapshot::capture(&index);
eprintln!(
"[profile] scale={:>6} files indexed in {:>5}ms \
total={:>10}B symbols={:>7} B/sym={:>6}",
scale,
build_ms,
snap.total_estimated_bytes(),
snap.symbol_count,
snap.bytes_per_symbol(),
);
report.add_checkpoint(scale, snap);
}
report
}
fn print_json(report: &ScaleReport) {
for (file_count, snap) in report.checkpoints() {
println!(
"{{\"file_count\":{},\"total_bytes\":{},\"files_bytes\":{},\
\"symbols_bytes\":{},\"global_refs_bytes\":{},\
\"document_store_bytes\":{},\"symbol_count\":{},\
\"bytes_per_symbol\":{}}}",
file_count,
snap.total_estimated_bytes(),
snap.files_bytes,
snap.symbols_bytes,
snap.global_refs_bytes,
snap.document_store_bytes,
snap.symbol_count,
snap.bytes_per_symbol(),
);
}
}
fn main() {
let args: Vec<String> = std::env::args().collect();
let mut emit_json = false;
let mut single_scale: Option<usize> = None;
let mut i = 1;
while i < args.len() {
match args[i].as_str() {
"--json" => emit_json = true,
"--scale" => {
i += 1;
if let Some(val) = args.get(i) {
single_scale = val.parse::<usize>().ok();
}
}
_ => {}
}
i += 1;
}
let default_scales: Vec<usize> = vec![100, 500, 1_000, 5_000, 10_000];
let scales: Vec<usize> = match single_scale {
Some(n) => vec![n],
None => default_scales,
};
let report = run_profile(&scales);
if emit_json {
print_json(&report);
} else {
println!("{}", report);
}
}