Skip to content

Commit

Permalink
For NordicHPC#152 - Remove clap dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
Lars T Hansen committed Apr 4, 2024
1 parent f2f229a commit 6afba0f
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 80 deletions.
53 changes: 0 additions & 53 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ edition = "2021"
subprocess = "0.2"
chrono = "0.4"
hostname = "0.3"
clap = { version = "4.5", features = ["derive"] }
csv = "1.3"
log = "0.4"
env_logger = "0.11"
Expand Down
172 changes: 146 additions & 26 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
extern crate env_logger;

use clap::{Parser, Subcommand};

mod amd;
mod batchless;
mod command;
Expand All @@ -18,60 +16,41 @@ mod util;

const TIMEOUT_SECONDS: u64 = 5; // For subprocesses

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
#[command(subcommand)]
command: Commands,
}

#[derive(Subcommand)]
enum Commands {
/// Take a snapshot of the currently running processes
PS {
/// Synthesize a job ID from the process tree in which a process finds itself
#[arg(long, default_value_t = false)]
batchless: bool,

/// Merge process records that have the same job ID and command name
#[arg(long, default_value_t = false)]
rollup: bool,

/// Include records for jobs that have on average used at least this percentage of CPU,
/// note this is nonmonotonic [default: none]
#[arg(long)]
min_cpu_percent: Option<f64>,

/// Include records for jobs that presently use at least this percentage of real memory,
/// note this is nonmonotonic [default: none]
#[arg(long)]
min_mem_percent: Option<f64>,

/// Include records for jobs that have used at least this much CPU time (in seconds)
/// [default: none]
#[arg(long)]
min_cpu_time: Option<usize>,

/// Exclude records for system jobs (uid < 1000)
#[arg(long, default_value_t = false)]
exclude_system_jobs: bool,

/// Exclude records whose users match these comma-separated names [default: none]
#[arg(long)]
exclude_users: Option<String>,

/// Exclude records whose commands start with these comma-separated names [default: none]
#[arg(long)]
exclude_commands: Option<String>,

/// Create a per-host lockfile in this directory and exit early if the file exists on startup [default: none]
#[arg(long)]
lockdir: Option<String>,
},
/// Extract system information
Sysinfo {},
/// Not yet implemented
Analyze {},
}

fn main() {
Expand All @@ -83,9 +62,7 @@ fn main() {

env_logger::init();

let cli = Cli::parse();

match &cli.command {
match &command_line() {
Commands::PS {
rollup,
batchless,
Expand Down Expand Up @@ -127,8 +104,151 @@ fn main() {
Commands::Sysinfo {} => {
sysinfo::show_system(&timestamp);
}
Commands::Analyze {} => {
println!("sonar analyze not yet completed");
}
}

// For the sake of simplicity:
// - allow repeated options to overwrite earlier values
// - all error reporting is via a generic "usage" message, without specificity as to what was wrong

fn command_line() -> Commands {
let mut args = std::env::args();
let _executable = args.next();
if let Some(command) = args.next() {
match command.as_str() {
"ps" => {
let mut batchless = false;
let mut rollup = false;
let mut min_cpu_percent = None;
let mut min_mem_percent = None;
let mut min_cpu_time = None;
let mut exclude_system_jobs = false;
let mut exclude_users = None;
let mut exclude_commands = None;
let mut lockdir = None;
loop {
if let Some(arg) = args.next() {
match arg.as_str() {
"--batchless" => {
batchless = true;
}
"--rollup" => {
rollup = true;
}
"--exclude-system-jobs" => {
exclude_system_jobs = true;
}
"--exclude-users" => {
(args, exclude_users) = string_value(args);
}
"--exclude-commands" => {
(args, exclude_commands) = string_value(args);
}
"--lockdir" => {
(args, lockdir) = string_value(args);
}
"--min-cpu-percent" => {
(args, min_cpu_percent) = parsed_value::<f64>(args);
}
"--min-mem-percent" => {
(args, min_mem_percent) = parsed_value::<f64>(args);
}
"--min-cpu-time" => {
(args, min_cpu_time) = parsed_value::<usize>(args);
}
_ => {
usage(true);
}
}
} else {
break;
}
}
return Commands::PS {
batchless,
rollup,
min_cpu_percent,
min_mem_percent,
min_cpu_time,
exclude_system_jobs,
exclude_users,
exclude_commands,
lockdir,
}
}
"sysinfo" => {
return Commands::Sysinfo {}
}
"help" => {
usage(false);
}
_ => {
usage(true);
}
}
} else {
usage(true);
}
}

fn string_value(mut args: std::env::Args) -> (std::env::Args, Option<String>) {
if let Some(val) = args.next() {
(args, Some(val))
} else {
usage(true);
}
}

fn parsed_value<T: std::str::FromStr>(mut args: std::env::Args) -> (std::env::Args, Option<T>) {
if let Some(val) = args.next() {
match val.parse::<T>() {
Ok(value) => {
(args, Some(value))
}
_ => {
usage(true);
}
}
} else {
usage(true);
}
}

fn usage(is_error: bool) -> ! {
let mut stdout = std::io::stdout();
let mut stderr = std::io::stderr();
let out: &mut dyn std::io::Write = if is_error { &mut stderr } else { &mut stdout };
let _ = out.write(b"Usage: sonar <COMMAND>
Commands:
ps Take a snapshot of the currently running processes
sysinfo Extract system information
help Print this message
Options for `ps`:
--batchless
Synthesize a job ID from the process tree in which a process finds itself
--rollup
Merge process records that have the same job ID and command name
--min-cpu-percent percentage
Include records for jobs that have on average used at least this
percentage of CPU, note this is nonmonotonic [default: none]
--min-mem-percent percentage
Include records for jobs that presently use at least this percentage of
real memory, note this is nonmonotonic [default: none]
--min-cpu-time seconds
Include records for jobs that have used at least this much CPU time
[default: none]
--exclude-system-jobs
Exclude records for system jobs (uid < 1000)
--exclude-users user,user,...
Exclude records whose users match these names [default: none]
--exclude-commands command,command,...
Exclude records whose commands start with these names [default: none]
--lockdir directory
Create a per-host lockfile in this directory and exit early if the file
exists on startup [default: none]
");
let _ = out.flush();
std::process::exit(if is_error { 2 } else { 0 });
}

0 comments on commit 6afba0f

Please sign in to comment.