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

Feat: added caching schema for debuginfo type names #88898

Closed
wants to merge 11 commits into from

Conversation

Sl1mb0
Copy link
Contributor

@Sl1mb0 Sl1mb0 commented Sep 12, 2021

This is a WIP addressing #86431. This PR aims to accomplish two things:

  • Implements a caching schema to avoid redundant calls to compute_debuginfo_type_name().
  • Add profiling support for determining the amount of redundant computations that would be performed, if the caching schema were not implemented.
    • As for how: I plan to just use counters to track how many times we call compute_debuginfo_type_name() and how many times we return a name for the cache. @rylev also suggested that determining how many individual memory allocations occur each time redundant work is performed, but I am unsure of how to go about this.

@rust-highfive
Copy link
Collaborator

r? @jackh726

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 12, 2021
@Sl1mb0
Copy link
Contributor Author

Sl1mb0 commented Sep 12, 2021

r? @michaelwoerister

@rust-log-analyzer

This comment has been minimized.

@@ -106,6 +106,8 @@ pub struct TypeMap<'ll, 'tcx> {
type_to_metadata: FxHashMap<Ty<'tcx>, &'ll DIType>,
/// A map from types to `UniqueTypeId`. This is an N:1 mapping.
type_to_unique_id: FxHashMap<Ty<'tcx>, UniqueTypeId>,
/// A map from `UniqueTypeId` to it's type-name string.
unique_id_to_type_name: FxHashMap<UniqueTypeId, String>,
Copy link
Member

Choose a reason for hiding this comment

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

A UniqueTypeId already contains the string. A Symbol is an interned string.

Copy link
Contributor Author

@Sl1mb0 Sl1mb0 Sep 13, 2021

Choose a reason for hiding this comment

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

So we can just check the type_to_unique_id map instead right?

If there is a mapping, return the string by calling get_unique_type_id_as_string(), otherwise create the mapping.

This would also mean that the Symbol stored in UniqueTypeId is the result of compute_debuginfo_type_name(), but it isn't. the name is computed on this line in get_unique_type_id_of_type()

218       let key = self.unique_id_interner.intern(&unique_type_id)

My question is: if the resulting strings from the above line and compute_debuginfo_type_name() are the same, isn't compute_debuginfo_type_name() unnecessary in the first place?

Edit:

I am pretty sure that the string computed in compute_debuginfo_type_name() and the Symbol within a UniqueTypeId are not the same.

Copy link
Member

Choose a reason for hiding this comment

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

Right, seems like it is a hex encoded hash.

@lqd
Copy link
Member

lqd commented Sep 13, 2021

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion.

@rustbot label: +S-waiting-on-perf

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

bors commented Sep 13, 2021

⌛ Trying commit 03361c46dd5c34a4b73ec159438486c64c15310d with merge db7e55346581a97b2acf2430c0b7b42c9da07e0b...

@bors
Copy link
Contributor

bors commented Sep 13, 2021

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

@rust-timer
Copy link
Collaborator

Queued db7e55346581a97b2acf2430c0b7b42c9da07e0b with parent b0ee495, future comparison URL.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (db7e55346581a97b2acf2430c0b7b42c9da07e0b): comparison url.

Summary: This benchmark run did not return any relevant changes.

If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf.

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 led to changes in compiler perf.

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

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Sep 13, 2021
@michaelwoerister
Copy link
Member

Thanks for the PR, @Sl1mb0!

I think for this to really make a performance difference the caching would have to be integrated into compute_debuginfo_type_name() itself, so that two separate calls for two types like foo::Bar1<foo::Baz> and foo::Bar2<foo::Baz> would be able to re-use foo::Baz. You can experiment with adding such a cache as a parameter to compute_debuginfo_type_name(). It would be something like a &mut FxHashMap<(Ty<'tcx>, bool), String> where the bool in the key stands for the qualified parameter.

@Sl1mb0 Sl1mb0 force-pushed the cache-debuginfo-type-names branch from 03361c4 to 69e911c Compare September 15, 2021 22:25
@Sl1mb0
Copy link
Contributor Author

Sl1mb0 commented Sep 16, 2021

@michaelwoerister Do you have any suggestions on where caching should occur?

@michaelwoerister
Copy link
Member

The cache could live in the CrateDebugContext, I think.

pub struct CrateDebugContext<'a, 'tcx> {
llcontext: &'a llvm::Context,
llmod: &'a llvm::Module,
builder: &'a mut DIBuilder<'a>,
created_files: RefCell<FxHashMap<(Option<String>, Option<String>), &'a DIFile>>,
created_enum_disr_types: RefCell<FxHashMap<(DefId, Primitive), &'a DIType>>,
type_map: RefCell<TypeMap<'a, 'tcx>>,
namespace_map: RefCell<DefIdMap<&'a DIScope>>,
// This collection is used to assert that composite types (structs, enums,
// ...) have their members only set once:
composite_types_completed: RefCell<FxHashSet<&'a DIType>>,
}

You can try to add a type_name_cache: RefCell<FxHashMap<(Ty<'tcx>, bool), String>> there and see if you run into any problems.

@bors
Copy link
Contributor

bors commented Sep 17, 2021

☔ The latest upstream changes (presumably #88956) made this pull request unmergeable. Please resolve the merge conflicts.

@Sl1mb0
Copy link
Contributor Author

Sl1mb0 commented Sep 18, 2021

So I've changed a few things; but now the compiler is panicking due to a BorrowMut error, and I am unsure why.

My guess is that it's because I am passing around a mutable reference to the cache, as opposed to passing around a RefCell, and attempting to borrow from that RefCell.

The changes in these commits are:

  • Moved type_name_cache up to the CrateDebugContext
  • Add type_name_cache arg to compute_debuginfo_type_name() and it's helper functions.
  • Upon entry into push_debuginfo_type_name() check if we have computed this name before, compute it if we haven't, and return the computed name.

@Sl1mb0
Copy link
Contributor Author

Sl1mb0 commented Sep 19, 2021

I changed &mut to &RefCell, and everything compiles. However debuginfo/pretty-slices.rs fails when running ./x.py test debuginfo.

stdout:

failures:

---- [debuginfo-lldb] debuginfo/pretty-slices.rs stdout ----
NOTE: compiletest thinks it is using LLDB version 1205
NOTE: compiletest thinks it is using LLDB without native rust support

error: line not found in debugger output:  (&mut [i32]) $1 = size=4 { [0] = 2 [1] = 3 [2] = 5 [3] = 7 }
status: exit status: 0
command: "/usr/bin/python3" "/Users/t1mb0sl1c3/Developer/rust-lang/rust/src/etc/lldb_batchmode.py" "/Users/t1mb0sl1c3/Developer/rust-lang/rust/compiler/build/x86_64-apple-darwin/test/debuginfo/pretty-slices.lldb/a" "/Users/t1mb0sl1c3/Developer/rust-lang/rust/compiler/build/x86_64-apple-darwin/test/debuginfo/pretty-slices.lldb/pretty-slices.debugger.script"
stdout:
------------------------------------------
LLDB batch-mode script
----------------------
Debugger commands script is '/Users/t1mb0sl1c3/Developer/rust-lang/rust/compiler/build/x86_64-apple-darwin/test/debuginfo/pretty-slices.lldb/pretty-slices.debugger.script'.
Target executable is '/Users/t1mb0sl1c3/Developer/rust-lang/rust/compiler/build/x86_64-apple-darwin/test/debuginfo/pretty-slices.lldb/a'.
Current working directory is '/Users/t1mb0sl1c3/Developer/rust-lang/rust/compiler'
Creating a target for '/Users/t1mb0sl1c3/Developer/rust-lang/rust/compiler/build/x86_64-apple-darwin/test/debuginfo/pretty-slices.lldb/a'
settings set auto-confirm true

version
lldb-1205.0.27.3 Apple Swift version 5.4 (swiftlang-1205.0.26.9 clang-1205.0.19.55) 
command script import /Users/t1mb0sl1c3/Developer/rust-lang/rust/./src/etc/lldb_lookup.py
type synthetic add -l lldb_lookup.synthetic_lookup -x '.*' --category Rust
type summary add -F lldb_lookup.summary_lookup  -e -x -h '^(alloc::([a-z_]+::)+)String$' --category Rust
type summary add -F lldb_lookup.summary_lookup  -e -x -h '^&(mut )?str$' --category Rust
type summary add -F lldb_lookup.summary_lookup  -e -x -h '^&(mut )?\[.+\]$' --category Rust
type summary add -F lldb_lookup.summary_lookup  -e -x -h '^(std::ffi::([a-z_]+::)+)OsString$' --category Rust
type summary add -F lldb_lookup.summary_lookup  -e -x -h '^(alloc::([a-z_]+::)+)Vec<.+>$' --category Rust
type summary add -F lldb_lookup.summary_lookup  -e -x -h '^(alloc::([a-z_]+::)+)VecDeque<.+>$' --category Rust
type summary add -F lldb_lookup.summary_lookup  -e -x -h '^(alloc::([a-z_]+::)+)BTreeSet<.+>$' --category Rust
type summary add -F lldb_lookup.summary_lookup  -e -x -h '^(alloc::([a-z_]+::)+)BTreeMap<.+>$' --category Rust
type summary add -F lldb_lookup.summary_lookup  -e -x -h '^(std::collections::([a-z_]+::)+)HashMap<.+>$' --category Rust
type summary add -F lldb_lookup.summary_lookup  -e -x -h '^(std::collections::([a-z_]+::)+)HashSet<.+>$' --category Rust
type summary add -F lldb_lookup.summary_lookup  -e -x -h '^(alloc::([a-z_]+::)+)Rc<.+>$' --category Rust
type summary add -F lldb_lookup.summary_lookup  -e -x -h '^(alloc::([a-z_]+::)+)Arc<.+>$' --category Rust
type summary add -F lldb_lookup.summary_lookup  -e -x -h '^(core::([a-z_]+::)+)Cell<.+>$' --category Rust
type summary add -F lldb_lookup.summary_lookup  -e -x -h '^(core::([a-z_]+::)+)Ref<.+>$' --category Rust
type summary add -F lldb_lookup.summary_lookup  -e -x -h '^(core::([a-z_]+::)+)RefMut<.+>$' --category Rust
type summary add -F lldb_lookup.summary_lookup  -e -x -h '^(core::([a-z_]+::)+)RefCell<.+>$' --category Rust
type category enable Rust

breakpoint set --file 'pretty-slices.rs' --line 45
DEBUG: breakpoint added, id = 1
Breakpoint 1: where = a`pretty_slices::main::h926e671f9dfe1c03 + 155 at pretty-slices.rs:45:5, address = 0x0000000100002cab 
DEBUG: registering breakpoint callback, id = 1
Error while trying to register breakpoint callback, id = 1, message = error: could not get num args: can't find callable: breakpoint_callback

run
Process 39336 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 frame #0: 0x0000000100002cab a`pretty_slices::main::h926e671f9dfe1c03 at pretty-slices.rs:45:5 42 let mut mut_str_slice_buffer = String::from("mutable string slice"); 43 let mut_str_slice: &mut str = mut_str_slice_buffer.as_mut_str(); 44 -> 45 b(); // #break ^ 46 } Target 0: (a) stopped. Process 39336 launched: '/Users/t1mb0sl1c3/Developer/rust-lang/rust/compiler/build/x86_64-apple-darwin/test/debuginfo/pretty-slices.lldb/a' (x86_64) 
print slice
(&[i32]) $0 = size=3 { [0] = 0 [1] = 1 [2] = 2 } 
print mut_slice
(&mut &[i32]) $1 = { data_ptr = 0x00007ffeefbff288 length = 4 } 
print str_slice
(&str) $2 = "string slice" { data_ptr = 0x0000000100003e58 "string slicemutable string slicecalled `Result::unwrap()` on an `Err` value" length = 12 } 
print mut_str_slice
(&mut &str) $3 = { data_ptr = 0x0000000100606070 "mutable string slice" length = 20 } 
quit


------------------------------------------
stderr:
------------------------------------------

------------------------------------------



failures:
    [debuginfo-lldb] debuginfo/pretty-slices.rs

test result: FAILED. 1 passed; 1 failed; 131 ignored; 0 measured; 0 filtered out; finished in 4.69s

Some tests failed in compiletest suite=debuginfo mode=debuginfo host=x86_64-apple-darwin target=x86_64-apple-darwin

@michaelwoerister
Copy link
Member

Hm, that looks like a legitimate error: (&mut [i32]) vs (&mut &[i32]). I'll try to take a look tomorrow. It looks like you are on the right track though otherwise.

Meanwhile, if you clean up the merge conflicts we can run some performance tests via CI.

@Sl1mb0 Sl1mb0 force-pushed the cache-debuginfo-type-names branch from a206b3a to cdd2ba2 Compare September 22, 2021 14:56
@rust-log-analyzer

This comment has been minimized.

Copy link
Member

@michaelwoerister michaelwoerister left a comment

Choose a reason for hiding this comment

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

I left a few comments and might have found the reason for test failures. Give it a try :)

compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs Outdated Show resolved Hide resolved
compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs Outdated Show resolved Hide resolved
compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs Outdated Show resolved Hide resolved
compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs Outdated Show resolved Hide resolved
@@ -438,12 +438,11 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
substs: SubstsRef<'tcx>,
name_to_append_suffix_to: &mut String,
) -> &'ll DIArray {
let type_name_cache = &mut *debug_context(cx).type_name_cache.borrow_mut();
Copy link
Member

Choose a reason for hiding this comment

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

I think holding the RefCell "lock" here for longer than just the type_names::push_generic_params() call might have been the reason why you saw the BorrowMut panics because the type_metadata() call farther below will also try to lock the cache.

@Sl1mb0 Sl1mb0 force-pushed the cache-debuginfo-type-names branch from 7588659 to fdd211a Compare September 23, 2021 18:16
@michaelwoerister
Copy link
Member

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion.

@rustbot label: +S-waiting-on-perf

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

bors commented Sep 23, 2021

⌛ Trying commit fdd211a with merge 7cd33b678f6735d7b26fb78172256d815cb27b33...

@bors
Copy link
Contributor

bors commented Sep 23, 2021

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

@rust-timer
Copy link
Collaborator

Queued 7cd33b678f6735d7b26fb78172256d815cb27b33 with parent bf64232, future comparison URL.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (7cd33b678f6735d7b26fb78172256d815cb27b33): comparison url.

Summary: This benchmark run did not return any relevant changes.

If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf.

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 led to changes in compiler perf.

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

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Sep 24, 2021
Copy link
Member

@michaelwoerister michaelwoerister left a comment

Choose a reason for hiding this comment

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

It looks like this doesn't improve performance much so far. We can try to improve things a little more by avoiding some string data allocations as described below. But I think that's as far as we can get as long as we don't find another way of dealing with recursive types.

@@ -62,6 +63,7 @@ pub struct CrateDebugContext<'a, 'tcx> {
builder: &'a mut DIBuilder<'a>,
created_files: RefCell<FxHashMap<(Option<String>, Option<String>), &'a DIFile>>,
created_enum_disr_types: RefCell<FxHashMap<(DefId, Primitive), &'a DIType>>,
type_name_cache: RefCell<FxHashMap<(Ty<'tcx>, bool), String>>,
Copy link
Member

Choose a reason for hiding this comment

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

Replace String with Rc<str> so that we can cheaply copy strings. A String can easily converted into an Rc<str> as described here: https://doc.rust-lang.org/std/string/struct.String.html#impl-From%3CString%3E-3

@rust-log-analyzer

This comment has been minimized.

@nagisa
Copy link
Member

nagisa commented Oct 4, 2021

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion.

@rustbot label: +S-waiting-on-perf

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

bors commented Oct 4, 2021

⌛ Trying commit 353e42e with merge a35f2fa0b1709e3bffed26d72fff54832568660f...

@bors
Copy link
Contributor

bors commented Oct 4, 2021

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

@rust-timer
Copy link
Collaborator

Queued a35f2fa0b1709e3bffed26d72fff54832568660f with parent 175b8db, future comparison URL.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (a35f2fa0b1709e3bffed26d72fff54832568660f): comparison url.

Summary: This benchmark run did not return any relevant changes.

If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf.

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 led to changes in compiler perf.

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

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Oct 5, 2021
@michaelwoerister
Copy link
Member

Well, it looks like there are no real performance improvements to be had here, unfortunately. Given that the changes add some complexity with no apparent gain, I'd opt for closing the PR (unless you have other ideas that we haven't explored yet).

@Sl1mb0
Copy link
Contributor Author

Sl1mb0 commented Oct 11, 2021

The only thing I can think of (without making a huge change) is that the mapping is too broad. The only field used from a Ty<'tcx> is it's TyKind;

If we get two different types, and they are each the same kind, we are computing that string for each type.

I'll try it and if there's still no improvements I'll close the PR.

@Sl1mb0
Copy link
Contributor Author

Sl1mb0 commented Oct 11, 2021

Seems using a TyKind is discouraged; closing.

@Sl1mb0 Sl1mb0 closed this Oct 11, 2021
@michaelwoerister
Copy link
Member

I hope you still had an interesting learning experience working on this, @Sl1mb0!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.
Projects
None yet
Development

Successfully merging this pull request may close these issues.