From 34be937d5f67d789969b1b731967fa26cc490a9c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 12:31:53 -0400 Subject: [PATCH] add -Zmiri-report-progress to regularly print a stacktrace of what we are executing --- README.md | 4 ++++ src/bin/miri.rs | 9 +++++++++ src/diagnostics.rs | 3 +++ src/eval.rs | 3 +++ src/machine.rs | 17 +++++++++++++++++ test-cargo-miri/build.rs | 2 +- 6 files changed, 37 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f373f078a09..117794b77ee6 100644 --- a/README.md +++ b/README.md @@ -292,6 +292,10 @@ environment variable. We first document the most relevant and most commonly used * `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables preemption. +* `-Zmiri-report-progress` makes Miri print the current stacktrace every now and then, so you can + tell what it is doing when a program just keeps running. You can customize how frequently the + report is printed via `-Zmiri-report-progress=`, which prints the report every N basic + blocks. * `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve non-determinism. This RNG is used to pick base addresses for allocations, to determine preemption and failure of `compare_exchange_weak`, and to control store buffering for weak memory emulation. When isolation diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 7dc642365c50..91148400c99b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -468,6 +468,15 @@ fn main() { ), }; miri_config.preemption_rate = rate; + } else if arg == "-Zmiri-report-progress" { + // This makes it take a few seconds between progress reports on my laptop. + miri_config.report_progress = Some(1_000_000); + } else if let Some(param) = arg.strip_prefix("-Zmiri-report-progress=") { + let interval = match param.parse::() { + Ok(i) => i, + Err(err) => panic!("-Zmiri-report-progress requires a `u32`: {}", err), + }; + miri_config.report_progress = Some(interval); } else if let Some(param) = arg.strip_prefix("-Zmiri-measureme=") { miri_config.measureme_out = Some(param.to_string()); } else if let Some(param) = arg.strip_prefix("-Zmiri-backtrace=") { diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 230f46c569db..6986d9c57271 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -68,6 +68,7 @@ pub enum NonHaltingDiagnostic { CreatedAlloc(AllocId), FreedAlloc(AllocId), RejectedIsolatedOp(String), + ProgressReport, } /// Level of Miri specific diagnostics @@ -465,6 +466,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx FreedAlloc(AllocId(id)) => format!("freed allocation with id {id}"), RejectedIsolatedOp(ref op) => format!("{op} was made to return an error due to isolation"), + ProgressReport => + format!("progress report: current operation being executed is here"), }; let (title, diag_level) = match e { diff --git a/src/eval.rs b/src/eval.rs index db843b851e58..7beb2ec9c4ad 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -124,6 +124,8 @@ pub struct MiriConfig { pub mute_stdout_stderr: bool, /// The probability of the active thread being preempted at the end of each basic block. pub preemption_rate: f64, + /// Report the current instruction being executed every N basic blocks. + pub report_progress: Option, } impl Default for MiriConfig { @@ -154,6 +156,7 @@ impl Default for MiriConfig { provenance_mode: ProvenanceMode::Legacy, mute_stdout_stderr: false, preemption_rate: 0.01, // 1% + report_progress: None, } } } diff --git a/src/machine.rs b/src/machine.rs index 79414ada5eac..3621744e8025 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -333,6 +333,11 @@ pub struct Evaluator<'mir, 'tcx> { /// The probability of the active thread being preempted at the end of each basic block. pub(crate) preemption_rate: f64, + + /// If `Some`, we will report the current stack every N basic blocks. + pub(crate) report_progress: Option, + /// The number of blocks that passed since the last progress report. + pub(crate) since_progress_report: u32, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -390,6 +395,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { mute_stdout_stderr: config.mute_stdout_stderr, weak_memory: config.weak_memory_emulation, preemption_rate: config.preemption_rate, + report_progress: config.report_progress, + since_progress_report: 0, } } @@ -862,6 +869,16 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + // Possibly report our progress. + if let Some(report_progress) = ecx.machine.report_progress { + if ecx.machine.since_progress_report >= report_progress { + register_diagnostic(NonHaltingDiagnostic::ProgressReport); + ecx.machine.since_progress_report = 0; + } + // Cannot overflow, since it is strictly less than `report_progress`. + ecx.machine.since_progress_report += 1; + } + // These are our preemption points. ecx.maybe_preempt_active_thread(); Ok(()) } diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index 72a4ee0de30b..8b1e3af6231a 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -16,7 +16,7 @@ fn main() { not_in_miri(); // Cargo calls `miri --print=cfg` to populate the `CARGO_CFG_*` env vars. // Make sure that the "miri" flag is set. - assert!(env::var_os("CARGO_CFG_MIRI").is_some()); + assert!(env::var_os("CARGO_CFG_MIRI").is_some(), "cargo failed to tell us about `--cfg miri`"); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-env-changed=MIRITESTVAR"); println!("cargo:rustc-env=MIRITESTVAR=testval");