summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2017-12-22 06:41:23 +0000
committerChandler Carruth <chandlerc@gmail.com>2017-12-22 06:41:23 +0000
commit45383c8c8551c1fed32d006c9528a64293e1f936 (patch)
tree511f46a4c35009714da1c2549dd089fbe45d0abc /include
parent30ada0c3f3188ddd5ac70ff28519ee7f81b33342 (diff)
Rewrite the cached map used for locating the most precise DIE among
inlined subroutines for a given address. This is essentially the hot path of llvm-symbolizer when extracting inlined frames during symbolization. Previously, we would read every subprogram and every inlined subroutine, building a std::map across the entire PC space to the best DIE, and then do only a handful of queries as we symbolized a backtrace. A huge fraction of the time was spent building the map itself. This patch changes it two a two-level system. First, we just build a map from PC-interval to DWARF subprograms. These are required to be disjoint and so constructing this is pretty easy. Second, we build a map *just* for the inlined subroutines within the subprogram containing the query address. This allows us to look at far fewer DIEs and build a *much* smaller set of cached maps in the llvm-symbolizer case where only a few address get symbolized during the entire run. It also builds both interval maps in a very different way. It constructs a single flat vector of pairs that maps from offset -> index. The indices point into collections of DIE objects, but can also be "tombstones" (-1) to mark gaps. In the case of subprograms, this mostly just simplifies the data structure a bit. For inlined subroutines, because we carefully split them as we build the map, we end up in many cases having no holes and not having to store both start and stop offsets. Finally, the PC ranges for the inlined subroutines are compressed into 32-bits by making them relative to the base PC of the outer subprogram. This means that if you have a single function body with over 2gb of executable code in it, we will stop mapping address past the first 2gb of that function into inlined subroutines and just give you the subprogram. This doesn't seem like a problem. ;] All of this combines to make llvm-symbolizer *well* over 2x faster for symbolizing backtraces out of LLVM's unittests. Death-test heavy unit tests are running >2x faster. I'm still going to look at completely disabling symbolization there, but figured while I had a good benchmark we should make symbolization a bit better. Sadly, the logic to build the flat interval map for the inlined subroutines is fairly complex. I'm not super happy about this and welcome any simplifying suggestions. Huge thanks to Dave Blaikie who helped walk me through what the various things I needed to do in DWARF to make this work. Differential Revision: https://reviews.llvm.org/D40987 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@321345 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include')
-rw-r--r--include/llvm/DebugInfo/DWARF/DWARFUnit.h44
1 files changed, 37 insertions, 7 deletions
diff --git a/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/include/llvm/DebugInfo/DWARF/DWARFUnit.h
index 09356ade8ef0..3cec58383f87 100644
--- a/include/llvm/DebugInfo/DWARF/DWARFUnit.h
+++ b/include/llvm/DebugInfo/DWARF/DWARFUnit.h
@@ -220,10 +220,40 @@ class DWARFUnit {
/// The compile unit debug information entry items.
std::vector<DWARFDebugInfoEntry> DieArray;
- /// Map from range's start address to end address and corresponding DIE.
- /// IntervalMap does not support range removal, as a result, we use the
- /// std::map::upper_bound for address range lookup.
- std::map<uint64_t, std::pair<uint64_t, DWARFDie>> AddrDieMap;
+ /// The vector of inlined subroutine DIEs that we can map directly to from
+ /// their subprogram below.
+ std::vector<DWARFDie> InlinedSubroutineDIEs;
+
+ /// A type representing a subprogram DIE and a map (built using a sorted
+ /// vector) into that subprogram's inlined subroutine DIEs.
+ struct SubprogramDIEAddrInfo {
+ DWARFDie SubprogramDIE;
+
+ uint64_t SubprogramBasePC;
+
+ /// A vector sorted to allow mapping from a relative PC to the inlined
+ /// subroutine DIE with the most specific address range covering that PC.
+ ///
+ /// The PCs are relative to the `SubprogramBasePC`.
+ ///
+ /// The vector is sorted in ascending order of the first int which
+ /// represents the relative PC for an interval in the map. The second int
+ /// represents the index into the `InlinedSubroutineDIEs` vector of the DIE
+ /// that interval maps to. An index of '-1` indicates an empty mapping. The
+ /// interval covered is from the `.first` relative PC to the next entry's
+ /// `.first` relative PC.
+ std::vector<std::pair<uint32_t, int32_t>> InlinedSubroutineDIEAddrMap;
+ };
+
+ /// Vector of the subprogram DIEs and their subroutine address maps.
+ std::vector<SubprogramDIEAddrInfo> SubprogramDIEAddrInfos;
+
+ /// A vector sorted to allow mapping from a PC to the subprogram DIE (and
+ /// associated addr map) index. Subprograms with overlapping PC ranges aren't
+ /// supported here. Nothing will crash, but the mapping may be inaccurate.
+ /// This vector may also contain "empty" ranges marked by an address with
+ /// a DIE index of '-1'.
+ std::vector<std::pair<uint64_t, int64_t>> SubprogramDIEAddrMap;
using die_iterator_range =
iterator_range<std::vector<DWARFDebugInfoEntry>::iterator>;
@@ -282,9 +312,6 @@ public:
AddrOffsetSectionBase = Base;
}
- /// Recursively update address to Die map.
- void updateAddressDieMap(DWARFDie Die);
-
void setRangesSection(const DWARFSection *RS, uint32_t Base) {
RangeSection = RS;
RangeSectionBase = Base;
@@ -480,6 +507,9 @@ private:
/// parseDWO - Parses .dwo file for current compile unit. Returns true if
/// it was actually constructed.
bool parseDWO();
+
+ void buildSubprogramDIEAddrMap();
+ void buildInlinedSubroutineDIEAddrMap(SubprogramDIEAddrInfo &SPInfo);
};
} // end namespace llvm