Add stdin support

This commit is contained in:
vodhash 2025-11-01 17:24:46 +01:00
parent 30dc73db40
commit 19af8fe871
2 changed files with 162 additions and 29 deletions

View File

@ -1,7 +1,7 @@
use anyhow::{anyhow, Result};
use clap::{arg, Command};
use libloading::Library;
use serde_json::{Map, Value};
use serde_json::{Map, Value, from_str as json_from_str};
use std::{fs, panic, path::PathBuf};
use tig_challenges::*;
use tig_structs::core::{BenchmarkSettings, CPUArchitecture, OutputData};
@ -16,21 +16,64 @@ use {
std::sync::Arc,
};
#[derive(serde::Deserialize, Debug)]
struct StdinConfig {
settings: String,
rand_hash: String,
nonce: u64,
binary: String,
#[serde(default)]
hyperparameters: Option<String>,
#[serde(default)]
ptx: Option<String>,
#[serde(default = "default_fuel")]
fuel: u64,
#[serde(default)]
output: Option<String>,
#[serde(default)]
gpu: Option<usize>,
}
fn default_fuel() -> u64 {
2000000000
}
fn cli() -> Command {
Command::new("tig-runtime")
.about("Executes an algorithm on a single challenge instance")
.arg_required_else_help(true)
.arg(
arg!(--stdin "Read configuration from stdin as JSON")
.action(clap::ArgAction::SetTrue)
.conflicts_with_all(&[
"SETTINGS",
"RAND_HASH",
"NONCE",
"BINARY",
"hyperparameters",
"ptx",
"fuel",
"output",
"gpu",
]),
)
.arg(
arg!(<SETTINGS> "Settings json string or path to json file")
.required_unless_present("stdin")
.value_parser(clap::value_parser!(String)),
)
.arg(
arg!(<RAND_HASH> "A string used in seed generation")
.required_unless_present("stdin")
.value_parser(clap::value_parser!(String)),
)
.arg(arg!(<NONCE> "Nonce value").value_parser(clap::value_parser!(u64)))
.arg(
arg!(<NONCE> "Nonce value")
.required_unless_present("stdin")
.value_parser(clap::value_parser!(u64))
)
.arg(
arg!(<BINARY> "Path to a shared object (*.so) file")
.required_unless_present("stdin")
.value_parser(clap::value_parser!(PathBuf)),
)
.arg(
@ -58,21 +101,50 @@ fn cli() -> Command {
fn main() {
let matches = cli().get_matches();
let result = if matches.get_flag("stdin") {
let mut stdin_content = String::new();
if let Err(e) = std::io::Read::read_to_string(&mut std::io::stdin(), &mut stdin_content) {
eprintln!("Failed to read from stdin: {}", e);
std::process::exit(1);
}
if let Err(e) = compute_solution(
matches.get_one::<String>("SETTINGS").unwrap().clone(),
matches.get_one::<String>("RAND_HASH").unwrap().clone(),
*matches.get_one::<u64>("NONCE").unwrap(),
matches.get_one::<PathBuf>("BINARY").unwrap().clone(),
matches.get_one("hyperparameters").cloned(),
matches.get_one::<PathBuf>("ptx").cloned(),
*matches.get_one::<u64>("fuel").unwrap(),
matches.get_one::<PathBuf>("output").cloned(),
matches.get_one::<usize>("gpu").cloned(),
) {
eprintln!("Runtime Error: {}", e);
std::process::exit(84);
}
let config: StdinConfig = match json_from_str(&stdin_content) {
Ok(cfg) => cfg,
Err(e) => {
eprintln!("Failed to parse JSON from stdin: {}", e);
std::process::exit(1);
}
};
compute_solution(
config.settings,
config.rand_hash,
config.nonce,
PathBuf::from(config.binary),
config.hyperparameters,
config.ptx.map(PathBuf::from),
config.fuel,
config.output.map(PathBuf::from),
config.gpu,
)
} else {
compute_solution(
matches.get_one::<String>("SETTINGS").unwrap().clone(),
matches.get_one::<String>("RAND_HASH").unwrap().clone(),
*matches.get_one::<u64>("NONCE").unwrap(),
matches.get_one::<PathBuf>("BINARY").unwrap().clone(),
matches.get_one("hyperparameters").cloned(),
matches.get_one::<PathBuf>("ptx").cloned(),
*matches.get_one::<u64>("fuel").unwrap(),
matches.get_one::<PathBuf>("output").cloned(),
matches.get_one::<usize>("gpu").cloned(),
)
};
if let Err(e) = result {
eprintln!("Runtime Error: {}", e);
std::process::exit(84);
}
}
pub fn compute_solution(

View File

@ -1,6 +1,6 @@
use anyhow::{anyhow, Result};
use clap::{arg, Command};
use serde_json::{Map, Value};
use serde_json::{Map, Value, from_str as json_from_str};
use std::{fs, io::Read, panic, path::PathBuf};
use tig_challenges::*;
use tig_structs::core::BenchmarkSettings;
@ -9,21 +9,54 @@ use tig_utils::dejsonify;
#[cfg(feature = "cuda")]
use cudarc::{driver::CudaContext, nvrtc::Ptx, runtime::result::device::get_device_prop};
#[derive(serde::Deserialize, Debug)]
struct StdinConfig {
settings: String,
rand_hash: String,
nonce: u64,
solution: String,
#[serde(default)]
ptx: Option<String>,
#[serde(default)]
gpu: Option<usize>,
#[serde(default)]
verbose: bool,
}
fn cli() -> Command {
Command::new("tig-verifier")
.about("Verifies a solution")
.arg_required_else_help(true)
.arg(
arg!(--stdin "Read configuration from stdin as JSON")
.action(clap::ArgAction::SetTrue)
.conflicts_with_all(&[
"SETTINGS",
"RAND_HASH",
"NONCE",
"SOLUTION",
"ptx",
"gpu",
"verbose",
]),
)
.arg(
arg!(<SETTINGS> "Settings json string or path to json file")
.required_unless_present("stdin")
.value_parser(clap::value_parser!(String)),
)
.arg(
arg!(<RAND_HASH> "A string used in seed generation")
.required_unless_present("stdin")
.value_parser(clap::value_parser!(String)),
)
.arg(arg!(<NONCE> "Nonce value").value_parser(clap::value_parser!(u64)))
.arg(
arg!(<NONCE> "Nonce value")
.required_unless_present("stdin")
.value_parser(clap::value_parser!(u64))
)
.arg(
arg!(<SOLUTION> "Solution base64 string, path to json file with solution field, or '-' for stdin")
.required_unless_present("stdin")
.value_parser(clap::value_parser!(String)),
)
.arg(arg!(--ptx [PTX] "Path to a CUDA ptx file").value_parser(clap::value_parser!(PathBuf)))
@ -34,15 +67,43 @@ fn cli() -> Command {
fn main() {
let matches = cli().get_matches();
if let Err(e) = verify_solution(
matches.get_one::<String>("SETTINGS").unwrap().clone(),
matches.get_one::<String>("RAND_HASH").unwrap().clone(),
*matches.get_one::<u64>("NONCE").unwrap(),
matches.get_one::<String>("SOLUTION").unwrap().clone(),
matches.get_one::<PathBuf>("ptx").cloned(),
matches.get_one::<usize>("gpu").cloned(),
matches.get_one::<bool>("verbose").cloned().unwrap_or(false),
) {
let result = if matches.get_flag("stdin") {
let mut stdin_content = String::new();
if let Err(e) = std::io::Read::read_to_string(&mut std::io::stdin(), &mut stdin_content) {
eprintln!("Failed to read from stdin: {}", e);
std::process::exit(1);
}
let config: StdinConfig = match json_from_str(&stdin_content) {
Ok(cfg) => cfg,
Err(e) => {
eprintln!("Failed to parse JSON from stdin: {}", e);
std::process::exit(1);
}
};
verify_solution(
config.settings,
config.rand_hash,
config.nonce,
config.solution,
config.ptx.map(PathBuf::from),
config.gpu,
config.verbose,
)
} else {
verify_solution(
matches.get_one::<String>("SETTINGS").unwrap().clone(),
matches.get_one::<String>("RAND_HASH").unwrap().clone(),
*matches.get_one::<u64>("NONCE").unwrap(),
matches.get_one::<String>("SOLUTION").unwrap().clone(),
matches.get_one::<PathBuf>("ptx").cloned(),
matches.get_one::<usize>("gpu").cloned(),
matches.get_one::<bool>("verbose").cloned().unwrap_or(false),
)
};
if let Err(e) = result {
eprintln!("Error: {}", e);
std::process::exit(1);
}