[PATCH] D40987: Rewrite the cached map used for locating the most precise DIE among inlined subroutines for a given address.

Chandler Carruth via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 7 15:24:33 PST 2017


chandlerc created this revision.
Herald added subscribers: mgrang, JDevlieghere, hiraditya, aprantl, mcrosier, sanjoy.

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.

Also, the names of various components here seem a bit confusing and/or
redundant. I've tried a bunch of options and this is the least bad one
I've found but I'd love better naming patterns to use.

And last but not least, some aspects of the algorithm for this changed
several times while I was working on this. I may have some stale
comments or failing to comment things that really should be; don't
hesitate to let me know about these or to just ignore them and I'll do
a thorough once over tomorrow.

Huge thanks to Dave Blaikie who helped walk me through what the various
things I needed to do in DWARF to make this work.


https://reviews.llvm.org/D40987

Files:
  llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
  llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp

-------------- next part --------------
A non-text attachment was scrubbed...
Name: D40987.126062.patch
Type: text/x-patch
Size: 20325 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20171207/b6bcf3c3/attachment.bin>


More information about the llvm-commits mailing list