use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::PathBuf;
use std::time::Instant;
use num_cpus;
use clap::{self, Parser};
pub use noel::*;
#[derive(Parser, Debug)]
#[command(
author = "Alejandro Gonzales-Irribarren",
version = "0.2.1",
about = "An extremely fast GTF/GFF per gene Non-Overlapping Exon Length calculator written in Rust."
)]
struct Args {
#[clap(
short = 'g',
long = "gtf",
help = "GTF/GFF file",
value_name = "GTF/GFF",
required = true
)]
gtf: PathBuf,
#[clap(
short = 'o',
long = "out",
help = "Output .txt file",
value_name = "OUTPUT",
required = true
)]
out: PathBuf,
#[clap(
short = 't',
long,
help = "Number of threads",
value_name = "THREADS",
default_value_t = num_cpus::get()
)]
threads: usize,
}
fn main() {
let start = Instant::now();
let start_mem = max_mem_usage_mb();
let args = Args::parse();
let mut output = BufWriter::new(File::create(&args.out).unwrap());
rayon::ThreadPoolBuilder::new()
.num_threads(args.threads)
.build_global()
.unwrap();
let exons = noel_reader(&args.gtf).expect("Error reading GTF/GFF file");
let genes = get_lengths(exons).expect("Error calculating exon lengths");
genes.iter().for_each(|(gene, bp)| {
writeln!(output, "{}\t{}", gene, bp).unwrap();
});
let elapsed = start.elapsed().as_secs_f64();
let mem = (max_mem_usage_mb() - start_mem).max(0.0);
println!("Elapsed: {:.4}s | Memory: {:.4} MB", elapsed, mem);
}
fn max_mem_usage_mb() -> f64 {
let rusage = unsafe {
let mut rusage = std::mem::MaybeUninit::uninit();
libc::getrusage(libc::RUSAGE_SELF, rusage.as_mut_ptr());
rusage.assume_init()
};
let maxrss = rusage.ru_maxrss as f64;
if cfg!(target_os = "macos") {
maxrss / 1024.0 / 1024.0
} else {
maxrss / 1024.0
}
}