replay_features/
replay_features.rs1use std::path::PathBuf;
4use std::time::Instant;
5
6use anyhow::Context;
7use clap::Parser;
8use koth_ms::{config::KothConfig, input::read_hills, output::write_features_parquet};
9
10#[derive(Parser)]
11struct Args {
12 hills: PathBuf,
13 #[arg(long, required = true)]
14 config: Vec<PathBuf>,
15 #[arg(long)]
16 output: PathBuf,
17 #[arg(long, default_value_t = 8)]
18 threads: usize,
19}
20
21fn main() -> anyhow::Result<()> {
22 let args = Args::parse();
23 rayon::ThreadPoolBuilder::new()
24 .num_threads(args.threads)
25 .build_global()?;
26 let start = Instant::now();
27 let hills = read_hills(&args.hills).context("read cached hills")?;
28 let read_s = start.elapsed().as_secs_f64();
29 for config_path in &args.config {
30 let label = config_path
31 .file_stem()
32 .context("config needs a file stem")?;
33 let out = args.output.join(label);
34 anyhow::ensure!(!out.exists(), "refusing to overwrite {}", out.display());
35 let config = KothConfig::from_toml(config_path)?;
36 let start = Instant::now();
37 let features = koth_ms::run_features(&hills, &config.features, &config.file)?;
38 let feature_s = start.elapsed().as_secs_f64();
39 let start = Instant::now();
40 let scored = koth_ms::run_scoring(
41 &features,
42 &config.scoring,
43 &config.features,
44 config.file.polarity,
45 );
46 let scoring_s = start.elapsed().as_secs_f64();
47 std::fs::create_dir_all(&out)?;
48 let start = Instant::now();
49 write_features_parquet(&scored, &out.join("features.parquet"), config.file.polarity)?;
50 let write_s = start.elapsed().as_secs_f64();
51 std::fs::write(out.join("config.toml"), config.to_toml_string()?)?;
52 let report = serde_json::json!({
53 "hills": hills.len(), "features_before_filter": features.len(),
54 "features_after_filter": scored.len(), "read_hills_s": read_s,
55 "feature_s": feature_s, "scoring_s": scoring_s, "write_s": write_s,
56 "input": args.hills, "config": config_path, "threads": args.threads,
57 });
58 std::fs::write(
59 out.join("timing.json"),
60 serde_json::to_string_pretty(&report)?,
61 )?;
62 println!(
63 "{}: {} features, detection {:.2}s, scoring {:.2}s, writing {:.2}s",
64 label.to_string_lossy(),
65 scored.len(),
66 feature_s,
67 scoring_s,
68 write_s
69 );
70 }
71 Ok(())
72}