This is an archive of the discontinued LLVM Phabricator instance.

support on-demand indexing in ManualDWARFIndex
Needs ReviewPublic

Authored by Eric on Apr 19 2021, 9:07 AM.

Details

Summary

Currently we always do a full index in ManualDWARFIndex when any variables are looked up. This can be expensive as it requires loading every dwo. With this change, we support partial indexing where we only load what is necessary for a specific dwo when asked for variables in a specific DWARFUnit

Diff Detail

Event Timeline

Eric created this revision.Apr 19 2021, 9:07 AM
Eric requested review of this revision.Apr 19 2021, 9:07 AM

I can combine this with https://reviews.llvm.org/D100299 if it would make reviewing easier.

I wasn't sure if the DWO Id was the right ID to use to find the unit. The issue is that I get the non-skeleton unit and need to search for the matching skeleton unit. I had to update some tests where the .dwos did not have a dwo id to match the skeleton unit. If there are symbol files like that in the wild this could break variable lookup for them.

Eric updated this revision to Diff 338881.Apr 20 2021, 8:25 AM

Rebased to not depend on other cl

I'm sorry about the delay.

Before I review this in detail, I'd like to understand your use case better. Do I understand correctly that you want to open a binary, and the _only_ thing you want to do with it is look up a bunch of variables?

AFAICS, that's the only use case where this will make a difference. Any other action will still trigger a full index, and I don't see how that could be avoided like you did here (when setting a breakpoint, for example, you don't know which compile unit it's going to be in, so you need to search through all units anyway...)

Am I missing something?

I can combine this with https://reviews.llvm.org/D100299 if it would make reviewing easier.

Splitting it up is great.

I wasn't sure if the DWO Id was the right ID to use to find the unit. The issue is that I get the non-skeleton unit and need to search for the matching skeleton unit. I had to update some tests where the .dwos did not have a dwo id to match the skeleton unit. If there are symbol files like that in the wild this could break variable lookup for them.

I'm pretty sure that the test issues are just a result of over-reduction.

That said, I think that a better solution to this would be remove the ->GetNonSkeletonUnit() bit from the call in SymbolFileDWARF::ParseVariablesForContext (and add to this function, where needed).

Eric updated this revision to Diff 339506.Apr 22 2021, 1:23 AM

Changed contract of DWARFIndex::GetGlobalVariables to take a non-const reference to the skeleton unit and changed each implementation to get the skeleton unit. This allowed further changes to cache by offset using existing m_units_to_avoid rather than cache by dwo id.

Eric added a comment.Apr 22 2021, 1:40 AM

Before I review this in detail, I'd like to understand your use case better. Do I understand correctly that you want to open a binary, and the _only_ thing you want to do with it is look up a bunch of variables?

and set breakpoints by source code line, and step, and translate the location of exceptions to source code lines...

AFAICS, that's the only use case where this will make a difference. Any other action will still trigger a full index, and I don't see how that could be avoided like you did here (when setting a breakpoint, for example, you don't know which compile unit it's going to be in, so you need to search through all units anyway...)

The other scenarios I care about are taken care of in https://reviews.llvm.org/D100299 (though only for DWARF5, which is a limitation I can live with). Please review that change as well!

I wasn't sure if the DWO Id was the right ID to use to find the unit. The issue is that I get the non-skeleton unit and need to search for the matching skeleton unit. I had to update some tests where the .dwos did not have a dwo id to match the skeleton unit. If there are symbol files like that in the wild this could break variable lookup for them.

I'm pretty sure that the test issues are just a result of over-reduction.

That said, I think that a better solution to this would be remove the ->GetNonSkeletonUnit() bit from the call in SymbolFileDWARF::ParseVariablesForContext (and add to this function, where needed).

Done. Turns out this requires changing every DWARFIndex implementation, but it's still a straightforward change that simplifies the ManualDWARFIndex change a little. Hope you like this better!

Eric updated this revision to Diff 339534.Apr 22 2021, 2:32 AM
Eric added a reviewer: kimanh.Apr 22 2021, 3:26 AM

Thank you for explaining the use case. The new implementation does look better, though I have some questions/suggestions for improvement. See inline comments for details.

I think we should also have a test case for this feature. IIUC, this feature only kicks when the setting target.preload-symbols is false, and we only have like one or two tests that exercise that. It would be good to have a test case which explicitly exercises the global variable fetching scenario without symbol preloading.

lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp
82–85

btw, the apple index is not compatible with split dwarf, so this change is a no-op.

lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
93 ↗(On Diff #339534)

did this sneak in from the other change?

lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
373

Any reason for not passing the unit directly? We could also use the convention that nullptr means "index everything" and ditch the first argument.

lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
83

What's this used for? AFAICT, the type units will be indexed exactly the first time that a "full" index is performed...

Eric marked 3 inline comments as done.Apr 22 2021, 8:35 AM

I'll get started on the test, but I'll probably want to use the same test file to test both CLs. What I want to do is write a case that references two dwos, only one of which actually exists, so that I can verify that certain queries can be done without attempting to load the other one.

lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp
82–85

Noted. I think I'll leave it as is unless you object in case that changes in the future.

lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
93 ↗(On Diff #339534)

It's actually left over from the previous iteration of this change, where I needed to get a DWO id from a const reference.

Happy to delete.

lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
83

I actually index the type units on a partial index. Some tests were broken when I didn't index them.

Eric updated this revision to Diff 339661.Apr 22 2021, 8:36 AM
Eric marked 2 inline comments as done.
Eric updated this revision to Diff 339989.Apr 23 2021, 5:23 AM
labath added inline comments.Apr 23 2021, 12:16 PM
lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp
82–85

I don't think that can change without a significant (incompatible) redesign of the apple index (at which point, one could just use debug_names), but I don't mind leaving this in.

lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
83

Ah, I got the logic backwards. Sorry about that.

However, this broken tests remark has me worried, and I think we should understand what's going on here. I'm worried that those broken tests were a symptom of a deeper problem, which this logic fixes only in a limited fashion.

My reasoning is this: if in the dwp+type unit scenario, we need the type units to be indexed immediately, what will happen if we compile the same source code in a different mode. For example, if we're debugging from .dwo files, we will not be indexing /all/ type units immediately -- only those that code from the same dwo file. This may be sufficient, but it also may not be -- clang tries hard to avoid producing debug info if it knows its already available elsewhere, so it's possible the type not be available in the dwo file we are looking at. Something similar could happen in the no-dwo, no-type unit scenario. In this case the type could only be present in some different compile unit, and we may not find it until we index that particular type unit.

Overall, it seems to be that if this "on-demand" indexing idea is sound, it should not need to rely on pre-indexing of type units. I could be wrong, but it seems like its at least worth having a closer look.

Eric added inline comments.Apr 28 2021, 12:53 PM
lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
83

After some debugging, it appears that the problem was due to the non-skeleton units in the dwp file not being indexed because they were type units. I think I prefer to leave this as is because adding additional logic to prevent indexing the units in the dwp would be more complicated than this, and because it seems to be a common behavior in lldb to iterate over all compile units and get their global variables, and with this code the equivalent to a full index would be done but I'm not sure I could guarantee that without eagerly evaluating type units.

Eric added a comment.Apr 30 2021, 9:43 AM

My plan for testing this is not panning out, as lldb provides no error when it fails to load symbols and no way to find out what symbols have been loaded or have been attempted, so there's no way to test that it is behaving lazily. Is there any particular thing you want me to test? Many tests are already hitting this code.

Eric added a comment.May 17 2021, 9:30 AM

This change is turning out to be less important as we seem to usually avoid building a full manual index if everything it built with -gpubnames. However the other change (https://reviews.llvm.org/D100299) is still necessary to prevent eagerly loading all non-skeleton information. Let's focus on that change and I will revisit this one if it turns out customers are still hitting the manual fallback.

Eric updated this revision to Diff 361701.Jul 26 2021, 9:40 AM

Language in Dump now distinguishes between unknown and not loaded.

@Eric you have update inappropriate review, this patch should have been in D100299.

Eric added a comment.Jul 26 2021, 12:49 PM

Yes I did, thank you. This patch will probably be abandoned anyway if https://reviews.llvm.org/D106355 is accepted.

Eric updated this revision to Diff 362853.Jul 29 2021, 12:57 PM

@Eric you have (again :-) ) updated inappropriate review, this patch should have been in D100299.

Eric added a comment.Jul 29 2021, 1:59 PM

Argh. Okay, I need to close this tab.

Eric updated this revision to Diff 362877.Jul 29 2021, 2:02 PM

Restoring previous diff.