Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coverage: Replace ExpressionOperandId with enum Operand #113428

Merged
merged 4 commits into from
Aug 1, 2023

Conversation

Zalathar
Copy link
Contributor

@Zalathar Zalathar commented Jul 7, 2023

This is one step in my larger coverage refactoring ambitions described at rust-lang/compiler-team#645.

LLVM coverage has a concept of “mapping expressions” that allow a span's execution count to be computed as a simple arithmetic expression over other counters/expressions, instead of requiring a dedicated physical counter for every control-flow branch.

These expressions have an operator (+ or -) and two operands. Operands are currently represented as ExpressionOperandId, which wraps a u32 with the following semantics:

  • 0 represents a special counter that always has a value of zero
  • Values ascending from 1 represent counter IDs
  • Values descending from u32::MAX represent the IDs of other expressions

This change replaces that whole ExpressionOperandId scheme with a simple enum that explicitly distinguishes between the three cases.

This lets us remove a lot of fiddly code for dealing with the different operand kinds:

  • Previously it was only possible to distinguish between counter-ID operands and expression-ID operands by comparing the operand ID with the total number of counters in a function. This is unnecessary now that the enum distinguishes them explicitly.
  • There's no need for expression IDs to descend from u32::MAX and then get translated into zero-based indices in certain places. Now that they ascend from zero, they can be used as indices directly.
  • There's no need to reserve ID number 0 for the special zero operand, since it can just have its own variant in the enum, so counter IDs can count up from 0.

(Making counter IDs ascend from 0 also lets us fix an off-by-one error in the query for counting the total number of counters, which would cause LLVM to emit an extra unused counter for every instrumented function.)


This PR may be easiest to review as individual patches, since that breaks it up into clearly distinct parts:

  • Replace a u32 wrapper with an explicit enum, without changing the semantics of the underlying IDs being stored.
  • Change the numbering scheme used by Operand::Expression to make expression IDs ascend from 0 (instead of descending from u32::MAX).
  • Change the numbering scheme used by Operand::Counter to make counter IDs ascend from 0 (instead of ascending from 1).

@rustbot
Copy link
Collaborator

rustbot commented Jul 7, 2023

r? @jackh726

(rustbot has picked a reviewer for you, use r? to override)

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jul 7, 2023
@rustbot
Copy link
Collaborator

rustbot commented Jul 7, 2023

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

@Zalathar
Copy link
Contributor Author

Zalathar commented Jul 7, 2023

@rustbot label +A-code-coverage

@rustbot rustbot added the A-code-coverage Area: Source-based code coverage (-Cinstrument-coverage) label Jul 7, 2023
@Zalathar Zalathar force-pushed the operand branch 5 times, most recently from d21eb94 to cf38b8d Compare July 13, 2023 01:37
@Zalathar Zalathar changed the title Replace coverage ExpressionOperandId with enum Operand coverage: Replace ExpressionOperandId with enum Operand Jul 13, 2023
@Zalathar Zalathar force-pushed the operand branch 2 times, most recently from 787b627 to 5c4dd5b Compare July 16, 2023 03:48
@jackh726
Copy link
Member

r? compiler

@Zalathar
Copy link
Contributor Author

(I've been rebasing this periodically because I have local changes that build on top of it, but the actual changes in this PR should be stable/complete.)

@Zalathar Zalathar force-pushed the operand branch 4 times, most recently from 0620d11 to b6c0982 Compare July 23, 2023 00:34
@Zalathar Zalathar force-pushed the operand branch 3 times, most recently from 766b854 to 088d7b0 Compare July 26, 2023 03:16
@compiler-errors
Copy link
Member

i'm not really qualified to review this

r? compiler

@rustbot rustbot assigned davidtwco and unassigned compiler-errors Jul 26, 2023
@apiraino
Copy link
Contributor

apiraino commented Jul 27, 2023

Nominating to signal boost this PR and help find a reviewer with more context

@rustbot label +I-compiler-nominated

@rustbot rustbot added the I-compiler-nominated Nominated for discussion during a compiler team meeting. label Jul 27, 2023
@Zalathar
Copy link
Contributor Author

I’m happy to help guide someone through this as necessary.

It’s not actually doing anything fundamentally complicated, since it’s mostly just replacing a u32 with an enum and then tidying up afterwards.

@Zalathar Zalathar force-pushed the operand branch 5 times, most recently from dde3122 to d816611 Compare July 30, 2023 23:31
The actual motivation here is to prevent `rustfmt` from suddenly reformatting
these enum variants onto a single line, when they become slightly shorter in
the future.

But there's no harm in adding some helpful documentation at the same time.
Because the three kinds of operand are now distinguished explicitly, we no
longer need fiddly code to disambiguate counter IDs and expression IDs based on
the total number of counters/expressions in a function.

This does increase the size of operands from 4 bytes to 8 bytes, but that
shouldn't be a big deal since they are mostly stored inside boxed structures,
and the current coverage code is not particularly size-optimized anyway.
Operand types are now tracked explicitly, so there is no need for expression
IDs to avoid counter IDs by descending from `u32::MAX`. Instead they can just
count up from 0, and can be used directly as indices when necessary.
Operand types are now tracked explicitly, so there is no need to reserve ID 0
for the special always-zero counter.

As part of the renumbering, this change fixes an off-by-one error in the way
counters were counted by the `coverageinfo` query. As a result, functions
should now have exactly the number of counters they actually need, instead of
always having an extra counter that is never used.
Copy link
Member

@davidtwco davidtwco left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I've left one nitpick comment which isn't a big deal so I'll just go ahead and approve this.

/// expression. Counter/expression operands are referred to by ID.
#[derive(Copy, Clone, PartialEq, Eq)]
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub enum Operand {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe we could rename this to CoverageOperand (or something like that), just because mir::Operand is quite common and it could be easy to get mixed up when reading the coverage code for the first time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I haven't interacted directly with actual MIR very much, so this didn't occur to me.

I have a bunch of other changes stacked up behind this one that use Operand, so to avoid churning those I definitely won't be renaming it in the near future. But it's something to bear in mind once my current coverage work has settled down.

@davidtwco
Copy link
Member

@bors r+

@bors
Copy link
Contributor

bors commented Aug 1, 2023

📌 Commit 3920e07 has been approved by davidtwco

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 1, 2023
bors added a commit to rust-lang-ci/rust that referenced this pull request Aug 1, 2023
…iaskrgr

Rollup of 7 pull requests

Successful merges:

 - rust-lang#100455 (Implement RefUnwindSafe for Backtrace)
 - rust-lang#113428 (coverage: Replace `ExpressionOperandId` with enum `Operand`)
 - rust-lang#114283 (Use parking lot's rwlock even without parallel-rustc)
 - rust-lang#114288 (Improve diagnostic for wrong borrow on binary operations)
 - rust-lang#114296 (interpret: fix alignment handling for Repeat expressions)
 - rust-lang#114306 ([rustc_data_structures][perf] Simplify base_n::push_str.)
 - rust-lang#114320 (Cover statements for stable_mir)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 52bfceb into rust-lang:master Aug 1, 2023
@rustbot rustbot added this to the 1.73.0 milestone Aug 1, 2023
@Zalathar Zalathar deleted the operand branch August 1, 2023 23:52
@apiraino apiraino removed the I-compiler-nominated Nominated for discussion during a compiler team meeting. label Aug 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-code-coverage Area: Source-based code coverage (-Cinstrument-coverage) S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants