fast-nnt 0.4.0

Rust implementation of the NeighborNet phylogenetic network algorithm.
Documentation
use serde::Serialize;

use crate::weights::cg_weights::CGSolveStats;

#[derive(Serialize)]
pub struct MatrixMeta {
    pub n: usize,
    pub npairs: usize,
    pub delimiter: String,
    pub has_header: bool,
    pub has_index: bool,
    pub symmetry_pairs_fixed: usize,
}

#[derive(Serialize)]
pub struct NNLSMeta {
    pub cutoff: f64,
    pub proj_grad_bound: f64,
    pub cgnr_iterations: usize,
    pub cgnr_tolerance: f64,
    pub active_set_rho: f64,
    pub num_splits: usize,
    pub num_trivial_splits: usize,
    pub num_nontrivial_splits: usize,
    pub sum_weights: f64,
}

#[derive(Serialize)]
pub struct RunTimings {
    pub load_sec: f64,
    pub cycle_sec: f64,
    pub nnls_sec: f64,
    pub fit_sec: f64,
    pub output_sec: f64,
    pub splits_sec: f64,
    pub graph_sec: f64,
    pub total_sec: f64,
}

#[derive(Serialize)]
pub struct SystemStats {
    pub os: String,
    pub arch: String,
    pub num_cpus: usize,
    pub rayon_threads: usize,
    pub peak_rss_bytes: Option<u64>,
    pub current_rss_bytes: u64,
}

#[derive(Serialize)]
pub struct RunLog {
    pub input: String,
    pub out_dir: String,
    pub matrix: MatrixMeta,
    pub nnls: NNLSMeta,
    pub inference: String,
    pub fit_percent: f32,
    pub cg_solve_stats: Option<CGSolveStats>,
    pub timings: RunTimings,
    pub system: SystemStats,
}

pub fn system_stats() -> SystemStats {
    SystemStats {
        os: std::env::consts::OS.to_string(),
        arch: std::env::consts::ARCH.to_string(),
        num_cpus: num_cpus::get(),
        rayon_threads: rayon::current_num_threads(),
        peak_rss_bytes: peak_rss_bytes(),
        current_rss_bytes: current_rss_bytes(),
    }
}

fn current_rss_bytes() -> u64 {
    use sysinfo::System;
    let mut sys = System::new();
    sys.refresh_processes(sysinfo::ProcessesToUpdate::All, true);
    if let Ok(pid) = sysinfo::get_current_pid()
        && let Some(p) = sys.process(pid)
    {
        return p.memory();
    }
    0
}

#[cfg(target_os = "linux")]
fn peak_rss_bytes() -> Option<u64> {
    let s = std::fs::read_to_string("/proc/self/status").ok()?;
    for line in s.lines() {
        if let Some(rest) = line.strip_prefix("VmHWM:") {
            let kb = rest.split_whitespace().next()?.parse::<u64>().ok()?;
            return Some(kb * 1024);
        }
    }
    None
}

#[cfg(not(target_os = "linux"))]
fn peak_rss_bytes() -> Option<u64> {
    None
}