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

Don't allocate on SimplifyCfg/Locals/Const on every MIR pass #110477

Merged
merged 1 commit into from
Apr 19, 2023

Conversation

miguelraz
Copy link
Contributor

@miguelraz miguelraz commented Apr 18, 2023

Hey! 👋🏾 This is a first PR attempt to see if I could speed up some rustc internals.

Thought process:

pub struct SimplifyCfg {
    label: String,
}

in compiler/src/rustc_mir_transform/simplify.rs fires multiple times per MIR analysis. This means that a likely string allocation is happening in each of these runs, which may add up, as they are not being lazily allocated or cached in between the different passes.

...yes, I know that adding a global static array is probably not the future-proof solution, but I wanted to lob this now as a proof of concept to see if it's worth shaving off a few cycles and then making more robust.

@rustbot
Copy link
Collaborator

rustbot commented Apr 18, 2023

r? @compiler-errors

(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 Apr 18, 2023
@rustbot
Copy link
Collaborator

rustbot commented Apr 18, 2023

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

@miguelraz miguelraz changed the title try interning SimplifyCfg strings Don't allocate on SimplifyCfg/Locals/Const on every MIR pass Apr 18, 2023
@compiler-errors
Copy link
Member

compiler-errors commented Apr 18, 2023

Do you have any evidence to suggest that these are expensive operations? I don't think this code is really worth the extra complication and possibly introducing new panic edges to the compiler just to avoid some string formatting.

@jyn514
Copy link
Member

jyn514 commented Apr 18, 2023

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Apr 18, 2023
@bors
Copy link
Contributor

bors commented Apr 18, 2023

⌛ Trying commit ccc7a0c1af6f58b3081024583d3cfdbcfb4f3434 with merge b89ba5d787d15245a9be6ac6f1619c153b23ea97...

@bors
Copy link
Contributor

bors commented Apr 18, 2023

☀️ Try build successful - checks-actions
Build commit: b89ba5d787d15245a9be6ac6f1619c153b23ea97 (b89ba5d787d15245a9be6ac6f1619c153b23ea97)

@rust-timer

This comment has been minimized.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (b89ba5d787d15245a9be6ac6f1619c153b23ea97): comparison URL.

Overall result: ✅ improvements - no action needed

Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf.

@bors rollup=never
@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

This is a highly reliable metric that was used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-0.7% [-2.8%, -0.2%] 19
Improvements ✅
(secondary)
-2.4% [-7.5%, -0.2%] 17
All ❌✅ (primary) -0.7% [-2.8%, -0.2%] 19

Max RSS (memory usage)

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
1.7% [1.7%, 1.7%] 1
Regressions ❌
(secondary)
2.3% [2.0%, 2.5%] 2
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-4.1% [-4.1%, -4.1%] 1
All ❌✅ (primary) 1.7% [1.7%, 1.7%] 1

Cycles

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-3.5% [-4.7%, -2.7%] 3
All ❌✅ (primary) - - 0

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Apr 18, 2023
@compiler-errors
Copy link
Member

Apparently keccak and codegen-cranelift have been particularly noisy recently, so I've been advised to ignore those.

As for the other positive perf results, I'll have to take a closer look at them to see if they're legit or just noise as well. (Or maybe I'll queue another perf run in the morning and see if these perf results stick?)

@workingjubilee
Copy link
Member

comment worth noting from a sidebar conversation about (current behavior, as it relates to this PR):

[11:57 PM] compilererrors: there are 273521 calls to format! [editor's note: when constructing mir passes] to bootstrap stdlib

@compiler-errors
Copy link
Member

compiler-errors commented Apr 18, 2023

Anyways, @miguelraz, I did some thinking. I think the right approach for this would be to make SimplifyCfg/etc's constructors instead take some enum that actually makes the matches you constructed above exhaustive. We can probably store those enums in the mir pass structs instead of a &'static str, then match on them in fn name to turn them into a &'static str.

Something like:

enum SimplifyCfgPassName {
    Initial,
    PromoteConsts,
    ...
}

impl SimplifyCfg {
  fn new(e: SimplifyCfgPassName) -> Self {
    SimplifyCfg { e }
  }

  fn name(&self) -> &'static str {
    match self.e {
      SimplifyCfgPassName::Initial => "SimplifyCfg-initial",
    }
}

@JakobDegen
Copy link
Contributor

The improvement is probably legit. I've seen major regressions in the past resulting from over-calling name and creating string allocations for it

@workingjubilee
Copy link
Member

workingjubilee commented Apr 18, 2023

We can probably store those enums in the mir pass structs instead of a &'static str, then match on them in fn name to turn them into a &'static str.

This would also reduce the size from the size of the string ref (pointer and length) to the size of the enum, which will save about 7~15 bytes per instance of this struct that is in memory at any given moment. Not the most important win compared to allocation overhead, but y'know, everything counts in large amounts.

@Noratrieb
Copy link
Member

cachegrind results from libc Debug Full:

1,260,425  ???:<rustc_passes::dead::MarkSymbolVisitor as rustc_hir::intravisit::Visitor>::visit_qpath
  888,494  ???:<core::cell::once::OnceCell<bool>>::get_or_try_init::<<core::cell::once::OnceCell<bool>>::get_or_init<<rustc_middle::mir::basic_blocks::BasicBlocks>::is_cfg_cyclic::{closure#0}>::{closure#0}, !>
 -790,524  library/core/src/fmt/mod.rs:core::fmt::write
 -710,531  ???:<rustc_data_structures::graph::iterate::TriColorDepthFirstSearch<rustc_middle::mir::basic_blocks::BasicBlocks>>::run_from_start::<rustc_data_structures::graph::iterate::CycleDetector>
 -659,804  obj/build/x86_64-unknown-linux-gnu/stage1-rustc/x86_64-unknown-linux-gnu/release/build/jemalloc-sys-5bd9bcfdf2a83955/out/build/src/arena.c:_rjem_je_arena_ralloc
 -638,356  ???:<rustc_passes::dead::MarkSymbolVisitor>::check_def_id
 -634,657  ./string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:__memcpy_avx_unaligned_erms
 -564,660  library/core/src/fmt/mod.rs:<&mut W as core::fmt::Write>::write_str
 -527,874  ???:<rustc_passes::dead::MarkSymbolVisitor as rustc_hir::intravisit::Visitor>::visit_ty
 -513,184  obj/build/x86_64-unknown-linux-gnu/stage1-rustc/x86_64-unknown-linux-gnu/release/build/jemalloc-sys-5bd9bcfdf2a83955/out/build/src/jemalloc.c:do_rallocx
 -508,194  library/core/src/fmt/mod.rs:core::fmt::Formatter::pad
 -435,018  ???:rustc_ast::mut_visit::noop_visit_fn_decl::<rustc_expand::expand::InvocationCollector>
 -417,494  ???:rustc_passes::reachable::has_custom_linkage
 -399,892  ???:<rustc_middle::ty::context::TyCtxt>::def_kind::<rustc_span::def_id::LocalDefId>
 -395,262  library/core/src/fmt/mod.rs:alloc::fmt::format::format_inner

lots of noise, but there are some memcpys and core::fmt, so this looks like a legit improvement. Awesome!

@Noratrieb
Copy link
Member

I quickly profiled a few other allocation sites inside simplify and found a few interesting results, it may be worth it to SmallVec a bunch of these: https://hackmd.io/3ViTm3u5QDST-c6mUIyjXg

@lqd
Copy link
Member

lqd commented Apr 18, 2023

keccak and cranelift-codegen are indeed noisy right now unfortunately.

image
image

Some of the other wins look related to formatting so probably legit.

There shouldn't be many instances of these structs in-flight at the same time, so maybe we wouldn't really see size reduction benefits (nor exhaustiveness for such debugging info), and can e.g. take the name as &'static str and do the Simplify*-$pass concatenations at the 10 or so call-sites instead.

@cjgillot
Copy link
Contributor

I think the right approach for this would be to make SimplifyCfg/etc's constructors instead take some enum that actually makes the matches you constructed above exhaustive. We can probably store those enums in the mir pass structs instead of a &'static str, then match on them in fn name to turn them into a &'static str.

Even simpler: we can make SimplifyCfg itself an enum, and have fn name match on self?

@miguelraz
Copy link
Contributor Author

@cjgillot yes, I just realized that and push that very change, thanks for the tip!

Copy link
Member

@compiler-errors compiler-errors left a comment

Choose a reason for hiding this comment

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

@miguelraz can you squash this into one commit? Other than that, this PR looks good to go.

@miguelraz miguelraz force-pushed the canoodling2-electric-boogaloo branch from 36b3f70 to fc27ae1 Compare April 18, 2023 18:34
@jyn514
Copy link
Member

jyn514 commented Apr 18, 2023

@bors r=compiler-errors

@bors
Copy link
Contributor

bors commented Apr 18, 2023

📌 Commit fc27ae1 has been approved by compiler-errors

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 Apr 18, 2023
@bors
Copy link
Contributor

bors commented Apr 19, 2023

⌛ Testing commit fc27ae1 with merge 9e7f72c...

pub fn new(label: &str) -> Self {
SimplifyConstCondition { label: format!("SimplifyConstCondition-{}", label) }
}
pub enum SimplifyConstConditionPassName {
Copy link
Contributor

Choose a reason for hiding this comment

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

(nit) no need to block the PR on this, but if you touch this code again in the future could you rename this to just SimplifyConstCondition? That would make it consistent with all the other ones

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for this, finally got around to this fix.
#110657

@bors
Copy link
Contributor

bors commented Apr 19, 2023

☀️ Test successful - checks-actions
Approved by: compiler-errors
Pushing 9e7f72c to master...

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (9e7f72c): comparison URL.

Overall result: ✅ improvements - no action needed

@rustbot label: -perf-regression

Instruction count

This is a highly reliable metric that was used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-0.5% [-0.7%, -0.3%] 10
Improvements ✅
(secondary)
-0.6% [-0.7%, -0.4%] 9
All ❌✅ (primary) -0.5% [-0.7%, -0.3%] 10

Max RSS (memory usage)

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
2.5% [1.9%, 3.1%] 2
Regressions ❌
(secondary)
1.6% [1.6%, 1.6%] 1
Improvements ✅
(primary)
-3.6% [-3.6%, -3.6%] 1
Improvements ✅
(secondary)
-4.2% [-4.2%, -4.2%] 1
All ❌✅ (primary) 0.5% [-3.6%, 3.1%] 3

Cycles

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
3.3% [2.7%, 3.6%] 4
Improvements ✅
(primary)
-2.9% [-4.6%, -1.5%] 8
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) -2.9% [-4.6%, -1.5%] 8

@miguelraz
Copy link
Contributor Author

For the record, this PR was a revived attempt of #108026.

@miguelraz miguelraz deleted the canoodling2-electric-boogaloo branch April 21, 2023 21:27
JohnTitor added a commit to JohnTitor/rust that referenced this pull request Apr 22, 2023
…ctor, r=compiler-errors

nit: consistent naming for SimplifyConstCondition

Fixing a small naming inconsistency that `@JakobDegen` brought up in rust-lang#110477 (comment).

Please signal for rollup.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. 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.