Skip to content

Commit b95e079

Browse files
committed
Auto merge of #153402 - RalfJung:miri, r=RalfJung
miri subtree update Subtree update of `miri` to rust-lang/miri@c37cbf8. Created using https://github.com/rust-lang/josh-sync. r? @ghost
2 parents b90dc1e + a512d62 commit b95e079

40 files changed

+604
-287
lines changed

src/tools/miri/CONTRIBUTING.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ you can visualize in [Perfetto](https://ui.perfetto.dev/). For example:
189189
MIRI_TRACING=1 ./miri run --features=tracing tests/pass/hello.rs
190190
```
191191

192+
See [doc/tracing.md](./doc/tracing.md) for more information.
193+
192194
### UI testing
193195

194196
We use ui-testing in Miri, meaning we generate `.stderr` and `.stdout` files for the output

src/tools/miri/doc/tracing.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
Miri can be traced to understand how much time is spent in its various components (e.g. borrow tracker, data race checker, etc.). When tracing is enabled, running Miri will create a `.json` trace file that can be opened and analyzed in [Perfetto](https://ui.perfetto.dev/). For any questions regarding this documentation you may contact [Stypox](https://rust-lang.zulipchat.com/#narrow/dm/627563-Stypox) on Zulip.
44

5+
> [!WARNING]
6+
> Tracing in Miri at the moment is broken due to two bugs in tracing libraries: https://github.com/tokio-rs/tracing/pull/3392 and https://github.com/davidbarsky/tracing-tree/issues/93. Also see https://github.com/rust-lang/miri/issues/4752.
7+
58
## Obtaining a trace file
69

710
### From the Miri codebase
@@ -240,7 +243,7 @@ let _trace = enter_trace_span!(M, "borrow_tracker", borrow_tracker = "on_stack_p
240243

241244
### `tracing_separate_thread` parameter
242245

243-
Miri saves traces using the the `tracing_chrome` `tracing::Layer` so that they can be visualized in Perfetto. To instruct `tracing_chrome` to put some spans on a separate trace thread/line than other spans when viewed in Perfetto, you can pass `tracing_separate_thread = tracing::field::Empty` to the tracing macros. This is useful to separate out spans which just indicate the current step or program frame being processed by the interpreter. As explained in [The timeline](#the-timeline), those spans end up under the "Global Legacy Events" track. You should use a value of `tracing::field::Empty` so that other tracing layers (e.g. the logger) will ignore the `tracing_separate_thread` field. For example:
246+
Miri saves traces using the `tracing_chrome` `tracing::Layer` so that they can be visualized in Perfetto. To instruct `tracing_chrome` to put some spans on a separate trace thread/line than other spans when viewed in Perfetto, you can pass `tracing_separate_thread = tracing::field::Empty` to the tracing macros. This is useful to separate out spans which just indicate the current step or program frame being processed by the interpreter. As explained in [The timeline](#the-timeline), those spans end up under the "Global Legacy Events" track. You should use a value of `tracing::field::Empty` so that other tracing layers (e.g. the logger) will ignore the `tracing_separate_thread` field. For example:
244247
```rust
245248
let _trace = enter_trace_span!(M, step::eval_statement, tracing_separate_thread = tracing::field::Empty);
246249
```
@@ -277,9 +280,12 @@ So the solution was to copy-paste [the only file](https://github.com/thoren-d/tr
277280
278281
### Time measurements
279282
280-
tracing-chrome originally used `std::time::Instant` to measure time, however on some x86/x86_64 Linux systems it might be unbearably slow since the underlying system call (`clock_gettime`) would take ≈1.3µs. Read more [here](https://btorpey.github.io/blog/2014/02/18/clock-sources-in-linux/) about how the Linux kernel chooses the clock source.
283+
tracing-chrome uses `std::time::Instant` to measure time. On most modern systems this is ok, since the underlying system call (`clock_gettime`) uses very fast hardware counters (e.g. `tsc`) and has a latency of ≈16ns.
284+
285+
On some x86/x86_64 Linux systems, however, `tsc` is not "reliable" and the system thus relies on other timers, e.g. `hpet` which takes ≈1.3µs. Read [here](https://btorpey.github.io/blog/2014/02/18/clock-sources-in-linux/) how the Linux kernel chooses the clock source, and how to check if your system is using `tsc`. If it doesn't use `tsc`, then expect most of the trace time being spent in time measurements, which degrades traces' usefulness... See [here](https://github.com/rust-lang/miri/issues/4563) for some discussion.
281286
282-
Therefore, on x86/x86_64 Linux systems with a CPU that has an invariant TSC counter, we read from that instead to measure time, which takes only ≈13ns. There are unfortunately a lot of caveats to this approach though, as explained [in the code](https://github.com/rust-lang/miri/blob/master/src/bin/log/tracing_chrome_instant.rs) and [in the PR](https://github.com/rust-lang/miri/pull/4524). The most impactful one is that: every thread spawned in Miri that wants to trace something (which requires measuring time) needs to pin itself to a single CPU core (using `sched_setaffinity`).
287+
> [!WARNING]
288+
> A (somewhat risky) workaround is to add `tsc=reliable clocksource=tsc hpet=disable` to the kernel boot parameters, which forces it to use `tsc` even if it is unreliable. But this may render the system unstable, so try it at your own risk!
283289
284290
## Other useful stuff
285291

src/tools/miri/rust-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
7bee525095c0872e87c038c412c781b9bbb3f5dc
1+
d933cf483edf1605142ac6899ff32536c0ad8b22

src/tools/miri/src/alloc_addresses/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
168168
if let Some(GlobalAlloc::Function { instance, .. }) =
169169
this.tcx.try_get_global_alloc(alloc_id)
170170
{
171-
let fn_sig = this.tcx.fn_sig(instance.def_id()).skip_binder().skip_binder();
171+
let fn_sig = this.tcx.instantiate_bound_regions_with_erased(
172+
this.tcx
173+
.fn_sig(instance.def_id())
174+
.instantiate(*this.tcx, instance.args),
175+
);
172176
let fn_ptr = crate::shims::native_lib::build_libffi_closure(this, fn_sig)?;
173177

174178
#[expect(

src/tools/miri/src/bin/log/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
pub mod setup;
22
mod tracing_chrome;
3-
mod tracing_chrome_instant;

src/tools/miri/src/bin/log/tracing_chrome.rs

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,8 @@ use std::{
5050
thread::JoinHandle,
5151
};
5252

53-
use crate::log::tracing_chrome_instant::TracingChromeInstant;
54-
5553
/// Contains thread-local data for threads that send tracing spans or events.
54+
#[derive(Clone)]
5655
struct ThreadData {
5756
/// A unique ID for this thread, will populate "tid" field in the output trace file.
5857
tid: usize,
@@ -61,7 +60,7 @@ struct ThreadData {
6160
out: Sender<Message>,
6261
/// The instant in time this thread was started. All events happening on this thread will be
6362
/// saved to the trace file with a timestamp (the "ts" field) measured relative to this instant.
64-
start: TracingChromeInstant,
63+
start: std::time::Instant,
6564
}
6665

6766
thread_local! {
@@ -562,28 +561,46 @@ where
562561
#[inline(always)]
563562
fn with_elapsed_micros_subtracting_tracing(&self, f: impl Fn(f64, usize, &Sender<Message>)) {
564563
THREAD_DATA.with(|value| {
565-
let mut thread_data = value.borrow_mut();
566-
let (ThreadData { tid, out, start }, new_thread) = match thread_data.as_mut() {
567-
Some(thread_data) => (thread_data, false),
568-
None => {
569-
let tid = self.max_tid.fetch_add(1, Ordering::SeqCst);
570-
let out = self.out.lock().unwrap().clone();
571-
let start = TracingChromeInstant::setup_for_thread_and_start(tid);
572-
*thread_data = Some(ThreadData { tid, out, start });
573-
(thread_data.as_mut().unwrap(), true)
564+
// Make sure not to keep `value` borrowed when calling `f` below, since the user tracing
565+
// code that `f` might invoke (e.g. fmt::Debug argument formatting) may contain nested
566+
// tracing calls that would cause `value` to be doubly-borrowed mutably.
567+
let (ThreadData { tid, out, start }, new_thread) = {
568+
let mut thread_data = value.borrow_mut();
569+
match thread_data.as_mut() {
570+
Some(thread_data) => (thread_data.clone(), false),
571+
None => {
572+
let tid = self.max_tid.fetch_add(1, Ordering::SeqCst);
573+
let out = self.out.lock().unwrap().clone();
574+
let start = std::time::Instant::now();
575+
*thread_data = Some(ThreadData { tid, out: out.clone(), start });
576+
(ThreadData { tid, out, start }, true)
577+
}
574578
}
575579
};
576580

577-
start.with_elapsed_micros_subtracting_tracing(|ts| {
578-
if new_thread {
579-
let name = match std::thread::current().name() {
580-
Some(name) => name.to_owned(),
581-
None => tid.to_string(),
582-
};
583-
let _ignored = out.send(Message::NewThread(*tid, name));
584-
}
585-
f(ts, *tid, out);
586-
});
581+
// Obtain the current time (before executing `f`).
582+
let instant_before_f = std::time::Instant::now();
583+
584+
// Using the current time (`instant_before_f`), calculate the elapsed time (in
585+
// microseconds) since `start` was instantiated, accounting for any time that was
586+
// previously spent executing `f`. The "accounting" part is not computed in this
587+
// line, but is rather done by shifting forward the `start` down below.
588+
let ts = (instant_before_f - start).as_nanos() as f64 / 1000.0;
589+
590+
// Run the function (supposedly a function internal to the tracing infrastructure).
591+
if new_thread {
592+
let name = match std::thread::current().name() {
593+
Some(name) => name.to_owned(),
594+
None => tid.to_string(),
595+
};
596+
let _ignored = out.send(Message::NewThread(tid, name));
597+
}
598+
f(ts, tid, &out);
599+
600+
// Measure how much time was spent executing `f` and shift `start` forward
601+
// by that amount. This "removes" that time from the trace.
602+
// See comment at the top of this function for why we have to re-borrow here.
603+
value.borrow_mut().as_mut().unwrap().start += std::time::Instant::now() - instant_before_f;
587604
});
588605
}
589606
}

src/tools/miri/src/bin/log/tracing_chrome_instant.rs

Lines changed: 0 additions & 183 deletions
This file was deleted.

0 commit comments

Comments
 (0)