diff --git a/.gitignore b/.gitignore index 765772864e..5f3b8f2899 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ tags target Cargo.lock .*.rustfmt +cretonne.dbg* diff --git a/lib/cretonne/src/dbg.rs b/lib/cretonne/src/dbg.rs new file mode 100644 index 0000000000..06723fa018 --- /dev/null +++ b/lib/cretonne/src/dbg.rs @@ -0,0 +1,100 @@ +//! Debug tracing macros. +//! +//! This module defines the `dbg!` macro which works like `println!` except it writes to the +//! Cretonne tracing output file if enabled. +//! +//! Tracing can be enabled by setting the `CRETONNE_DBG` environment variable to something +/// other than `0`. +/// +/// The output will appear in files named `cretonne.dbg.*`, where the suffix is named after the +/// thread doing the logging. + +use std::ascii::AsciiExt; +use std::cell::RefCell; +use std::env; +use std::ffi::OsStr; +use std::fs::File; +use std::io::{Write, BufWriter}; +use std::sync::atomic; +use std::thread; + +static STATE: atomic::AtomicIsize = atomic::ATOMIC_ISIZE_INIT; + +/// Is debug tracing enabled? +/// +/// Debug tracing can be enabled by setting the `CRETONNE_DBG` environment variable to something +/// other than `0`. +/// +/// This inline function turns into a constant `false` when debug assertions are disabled. +#[inline] +pub fn enabled() -> bool { + if cfg!(debug_assertions) { + match STATE.load(atomic::Ordering::Relaxed) { + 0 => initialize(), + s => s > 0, + } + } else { + false + } +} + +/// Initialize `STATE` from the environment variable. +fn initialize() -> bool { + let enable = match env::var_os("CRETONNE_DBG") { + Some(s) => s != OsStr::new("0"), + None => false, + }; + + if enable { + STATE.store(1, atomic::Ordering::Relaxed); + } else { + STATE.store(-1, atomic::Ordering::Relaxed); + } + + enable +} + +thread_local! { + static WRITER : RefCell> = RefCell::new(open_file()); +} + +/// Execute a closure with mutable access to the tracing file writer. +/// +/// This is for use by the `dbg!` macro. +pub fn with_writer(f: F) -> R + where F: FnOnce(&mut Write) -> R +{ + WRITER.with(|rc| f(&mut *rc.borrow_mut())) +} + +/// Open the tracing file for the current thread. +fn open_file() -> BufWriter { + let file = match thread::current().name() { + None => File::create("cretonne.dbg"), + Some(name) => { + let mut path = "cretonne.dbg.".to_owned(); + for ch in name.chars() { + if ch.is_ascii() && ch.is_alphanumeric() { + path.push(ch); + } + } + File::create(path) + } + } + .expect("Can't open tracing file"); + BufWriter::new(file) +} + +/// Write a line to the debug trace file if tracing is enabled. +/// +/// Arguments are the same as for `printf!`. +#[macro_export] +macro_rules! dbg { + ($($arg:tt)+) => { + if $crate::dbg::enabled() { + // Drop the error result so we don't get compiler errors for ignoring it. + // What are you going to do, log the error? + $crate::dbg::with_writer(|w| { writeln!(w, $($arg)+).ok(); }) + } + } +} diff --git a/lib/cretonne/src/lib.rs b/lib/cretonne/src/lib.rs index 2839ecfc1f..733506a605 100644 --- a/lib/cretonne/src/lib.rs +++ b/lib/cretonne/src/lib.rs @@ -21,6 +21,9 @@ pub mod settings; pub mod sparse_map; pub mod verifier; +#[macro_use] +pub mod dbg; + mod abi; mod constant_hash; mod context; diff --git a/src/cton-util.rs b/src/cton-util.rs index 89fee3c5a5..681ab5b8bc 100644 --- a/src/cton-util.rs +++ b/src/cton-util.rs @@ -1,4 +1,4 @@ - +#[macro_use(dbg)] extern crate cretonne; extern crate cton_reader; extern crate docopt; diff --git a/src/filetest/concurrent.rs b/src/filetest/concurrent.rs index aa0fba8f1d..effe454d38 100644 --- a/src/filetest/concurrent.rs +++ b/src/filetest/concurrent.rs @@ -137,6 +137,10 @@ fn worker_thread(thread_num: usize, } }); + if let &Err(ref msg) = &result { + dbg!("FAIL: {}", msg); + } + replies.send(Reply::Done { jobid: jobid, result: result, diff --git a/src/filetest/runone.rs b/src/filetest/runone.rs index 8e707d4ff5..ed4cae1ee7 100644 --- a/src/filetest/runone.rs +++ b/src/filetest/runone.rs @@ -17,6 +17,7 @@ use filetest::subtest::{SubTest, Context, Result}; /// /// If running this test causes a panic, it will propagate as normal. pub fn run(path: &Path) -> TestResult { + dbg!("---\nFile: {}", path.to_string_lossy()); let started = time::Instant::now(); let buffer = read_to_string(path).map_err(|e| e.to_string())?; let testfile = parse_test(&buffer).map_err(|e| e.to_string())?; @@ -108,6 +109,7 @@ fn run_one_test<'a>(tuple: (&'a SubTest, &'a Flags, Option<&'a TargetIsa>), -> Result<()> { let (test, flags, isa) = tuple; let name = format!("{}({})", test.name(), func.name); + dbg!("Test: {} {}", name, isa.map(TargetIsa::name).unwrap_or("-")); context.flags = flags; context.isa = isa;