raytracers/rtiow/src/bin/tracer.rs

146 lines
3.8 KiB
Rust

#[macro_use]
extern crate log;
extern crate chrono;
#[cfg(feature = "profile")]
extern crate cpuprofiler;
extern crate rand;
extern crate rtiow;
extern crate stderrlog;
extern crate structopt;
#[macro_use]
#[cfg(feature = "prom")]
extern crate lazy_static;
#[macro_use]
#[cfg(feature = "prom")]
extern crate prometheus;
use std::fs;
use chrono::DateTime;
use chrono::Utc;
#[cfg(feature = "profile")]
use cpuprofiler::PROFILER;
#[cfg(feature = "prom")]
use prometheus::Encoder;
use structopt::StructOpt;
use rtiow::renderer::opt_hash;
use rtiow::renderer::render;
use rtiow::renderer::Opt;
#[cfg(feature = "prom")]
lazy_static! {
static ref RUNTIME_COUNTER: prometheus::Gauge =
register_gauge!("render_time_seconds", "Wall clock time for render").unwrap();
}
#[cfg(not(feature = "prom"))]
fn push_metrics(_push_gateway_addr: &str, _instance: String, start_time: &DateTime<Utc>) {
let runtime = (Utc::now() - *start_time).to_std().unwrap();
info!(
"Render time {}.{} seconds",
runtime.as_secs(),
runtime.subsec_millis()
);
}
#[cfg(feature = "prom")]
fn push_metrics(push_gateway_addr: &str, instance: String, start_time: &DateTime<Utc>) {
let runtime = (Utc::now() - *start_time).to_std().unwrap();
info!(
"Render time {}.{} seconds",
runtime.as_secs(),
runtime.subsec_millis()
);
RUNTIME_COUNTER.set(runtime.as_secs() as f64 + f64::from(runtime.subsec_nanos()) * 1e-9);
let metric_families = prometheus::gather();
let encoder = prometheus::TextEncoder::new();
let stdout = std::io::stdout();
println!("Prometheus metrics:");
encoder
.encode(&metric_families, &mut stdout.lock())
.unwrap();
if push_gateway_addr.is_empty() {
info!("Logging stats to push gateway disabled");
return;
}
if let Err(err) = prometheus::push_metrics(
"tracer",
labels! {
"instance".to_owned() => instance,
"start_time".to_owned() => start_time.to_rfc3339(),
"timestamp".to_owned() => start_time.timestamp().to_string(),
},
push_gateway_addr,
metric_families,
None,
// TODO(wathiede): auth?
// Some(prometheus::BasicAuthentication {
// username: "user".to_owned(),
// password: "pass".to_owned(),
// }),
) {
error!("Failed to push to prometheus gateway: {}", err);
}
}
#[cfg(not(feature = "profile"))]
struct MockTimer;
#[cfg(not(feature = "profile"))]
impl MockTimer {
fn start<T: Into<Vec<u8>>>(&self, _: T) -> Result<(), ()> {
Ok(())
}
fn stop(&self) -> Result<(), ()> {
Ok(())
}
}
#[cfg(not(feature = "profile"))]
struct MockProfiler;
#[cfg(not(feature = "profile"))]
impl MockProfiler {
fn lock(&self) -> Option<MockTimer> {
Some(MockTimer {})
}
}
#[cfg(not(feature = "profile"))]
static PROFILER: MockProfiler = MockProfiler {};
fn main() -> Result<(), std::io::Error> {
stderrlog::new()
.verbosity(3)
.timestamp(stderrlog::Timestamp::Millisecond)
.init()
.unwrap();
let start_time: DateTime<Utc> = Utc::now();
let opt = Opt::from_args();
let scene = opt.model.scene(&opt);
fs::create_dir_all(&opt.output)?;
if opt.pprof.is_some() && !cfg!(feature = "profile") {
panic!("profiling disabled at compile time, but -pprof specified");
}
if let Some(ref pprof_path) = opt.pprof {
PROFILER
.lock()
.unwrap()
.start(pprof_path.to_str().unwrap().as_bytes())
.unwrap();
}
let res = render(scene, &opt.output);
if let Some(pprof_path) = &opt.pprof {
info!("Saving pprof to {}", pprof_path.to_string_lossy());
PROFILER.lock().unwrap().stop().unwrap();
}
push_metrics(&opt.push_gateway, opt_hash(&opt), &start_time);
res
}