about summary refs log tree commit diff
path: root/src/doc
diff options
context:
space:
mode:
authorUrgau <3616612+Urgau@users.noreply.github.com>2025-06-18 19:40:32 +0200
committerGitHub <noreply@github.com>2025-06-18 19:40:32 +0200
commit2011ab51528ba9469ba313ff3c269b465d042f1d (patch)
tree031540e2af33c73926c4146b48a955eb45a2eca0 /src/doc
parent7c465447c845cd2ccb44fb2a5100be4a6f7e611e (diff)
parent7e423201e69d8650738b2454ff2286a7339145fa (diff)
downloadrust-2011ab51528ba9469ba313ff3c269b465d042f1d.tar.gz
rust-2011ab51528ba9469ba313ff3c269b465d042f1d.zip
Rollup merge of #142123 - Kobzol:timings, r=nnethercote
Implement initial support for timing sections (`--json=timings`)

This PR implements initial support for emitting high-level compilation section timings. The idea is to provide a very lightweight way of emitting durations of various compilation sections (frontend, backend, linker, or on a more granular level macro expansion, typeck, borrowck, etc.). The ultimate goal is to stabilize this output (in some form), make Cargo pass `--json=timings` and then display this information in the HTML output of `cargo build --timings`, to make it easier to quickly profile "what takes so long" during the compilation of a Cargo project. I would personally also like if Cargo printed some of this information in the interactive `cargo build` output, but the `build --timings` use-case is the main one.

Now, this information is already available with several other sources, but I don't think that we can just use them as they are, which is why I proposed a new way of outputting this data (`--json=timings`):
- This data is available under `-Zself-profile`, but that is very expensive and forever unstable. It's just a too big of a hammer to tell us the duration it took to run the linker.
- It could also be extracted with `-Ztime-passes`. That is pretty much "for free" in terms of performance, and it can be emitted in a structured form to JSON via `-Ztime-passes-format=json`. I guess that one alternative might be to stabilize this flag in some form, but that form might just be `--json=timings`? I guess what we could do in theory is take the already emitted time passes and reuse them for `--json=timings`. Happy to hear suggestions!

I'm sending this PR mostly for a vibeck, to see if the way I implemented it is passable. There are some things to figure out:
- How do we represent the sections? Originally I wanted to output `{ section, duration }`, but then I realized that it might be more useful to actually emit `start` and `end` events. Both because it enables to see the output incrementally (in case compilation takes a long time and you read the outputs directly, or Cargo decides to show this data in `cargo build` some day in the future), and because it makes it simpler to represent hierarchy (see below). The timestamps currently emit microseconds elapsed from a predetermined point in time (~start of rustc), but otherwise they are fully opaque, and should be only ever used to calculate the duration using `end - start`. We could also precompute the duration for the user in the `end` event, but that would require doing more work in rustc, which I would ideally like to avoid :P
- Do we want to have some form of hierarchy? I think that it would be nice to show some more granular sections rather than just frontend/backend/linker (e.g. macro expansion, typeck and borrowck as a part of the frontend). But for that we would need some way of representing hierarchy. A simple way would be something like `{ parent: "frontend" }`, but I realized that with start/end timestamps we get the hierarchy "for free", only the client will need to reconstruct it from the order of start/end events (e.g. `start A`, `start B` means that `B` is a child of `A`).
- What exactly do we want to stabilize? This is probably a question for later. I think that we should definitely stabilize the format of the emitted JSON objects, and *maybe* some specific section names (but we should also make it clear that they can be missing, e.g. you don't link everytime you invoke `rustc`).

The PR be tested e.g. with `rustc +stage1 src/main.rs --json=timings --error-format=json -Zunstable-options` on a crate without dependencies (it is not easy to use `--json` with stock Cargo, because it also passes this flag to `rustc`, so this will later need Cargo integration to be usable with it).

Zulip discussions: [#t-compiler > Outputting time spent in various compiler sections](https://rust-lang.zulipchat.com/#narrow/channel/131828-t-compiler/topic/Outputting.20time.20spent.20in.20various.20compiler.20sections/with/518850162)

MCP: https://github.com/rust-lang/compiler-team/issues/873

r? ``@nnethercote``
Diffstat (limited to 'src/doc')
-rw-r--r--src/doc/rustc/src/command-line-arguments.md3
-rw-r--r--src/doc/rustc/src/json.md29
2 files changed, 32 insertions, 0 deletions
diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index b704cee705b..d45ad1be27b 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -471,6 +471,9 @@ to customize the output:
 - `future-incompat` - includes a JSON message that contains a report if the
   crate contains any code that may fail to compile in the future.
 
+- `timings` - output a JSON message when a certain compilation "section"
+  (such as frontend analysis, code generation, linking) begins or ends.
+
 Note that it is invalid to combine the `--json` argument with the
 [`--color`](#option-color) argument, and it is required to combine `--json`
 with `--error-format=json`.
diff --git a/src/doc/rustc/src/json.md b/src/doc/rustc/src/json.md
index c853f34ee03..7421dd62108 100644
--- a/src/doc/rustc/src/json.md
+++ b/src/doc/rustc/src/json.md
@@ -298,6 +298,35 @@ appropriately. (This is needed by Cargo which shares the same dependencies
 across multiple build targets, so it should only report an unused dependency if
 its not used by any of the targets.)
 
+## Timings
+
+**This setting is currently unstable and requires usage of `-Zunstable-options`.**
+
+The `--timings` option will tell `rustc` to emit messages when a certain compilation
+section (such as code generation or linking) begins or ends. The messages currently have
+the following format:
+
+```json
+{
+    "$message_type": "section_timing", /* Type of this message */
+    "event": "start", /* Marks the "start" or "end" of the compilation section */
+    "name": "link",  /* The name of the compilation section */
+    // Opaque timestamp when the message was emitted, in microseconds
+    // The timestamp is currently relative to the beginning of the compilation session
+    "time": 12345
+}
+```
+
+Note that the JSON format of the `timings` messages is unstable and subject to change.
+
+Compilation sections can be nested; for example, if you encounter the start of "foo",
+then the start of "bar", then the end of "bar" and then the end of "bar", it means that the
+"bar" section happened as a part of the "foo" section.
+
+The timestamp should only be used for computing the duration of each section.
+
+We currently do not guarantee any specific section names to be emitted.
+
 [option-emit]: command-line-arguments.md#option-emit
 [option-error-format]: command-line-arguments.md#option-error-format
 [option-json]: command-line-arguments.md#option-json