Skip to content

Commit 418893d

Browse files
committed
Speed up accelerator table lookups
When debugging a large program like clang and doing "frame variable *this", the ValueObject pretty printer is doing hundreds of scoped FindTypes lookups. The ones that take longest are the ones where the DWARFDeclContext ends in something like ::Iterator which produces many false positives that need to be filtered out *after* extracting the DIEs. This patch demonstrates a way to filter out false positives at the accerator table lookup step. With this patch lldb clang-10 -o "b EmitFunctionStart" -o r -o "f 2" -o "fr v *this" -b -- ... goes (in user time) from 5.6s -> 4.8s or (in wall clock) from 6.9s -> 6.0s. Differential Revision: https://reviews.llvm.org/D68678 llvm-svn: 374401
1 parent 715bfa4 commit 418893d

File tree

12 files changed

+116
-3
lines changed

12 files changed

+116
-3
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# There is no guaranteed order in which the linker will order these
2+
# files, so we just have a lot of them to make it unlikely that we hit
3+
# the right one first by pure luck.
4+
5+
CXX_SOURCES := main.cpp a.cpp b.cpp c.cpp d.cpp e.cpp f.cpp g.cpp
6+
7+
include Makefile.rules
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import lldb
2+
from lldbsuite.test.decorators import *
3+
from lldbsuite.test.lldbtest import *
4+
from lldbsuite.test import lldbutil
5+
6+
7+
class CPPAcceleratorTableTestCase(TestBase):
8+
9+
mydir = TestBase.compute_mydir(__file__)
10+
11+
@skipUnlessDarwin
12+
@skipIf(debug_info=no_match(["dwarf"]))
13+
def test(self):
14+
"""Test that type lookups fail early (performance)"""
15+
self.build()
16+
logfile = self.getBuildArtifact('dwarf.log')
17+
self.expect('log enable dwarf lookups -f' + logfile)
18+
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
19+
self, 'break here', lldb.SBFileSpec('main.cpp'))
20+
# Pick one from the middle of the list to have a high chance
21+
# of it not being in the first file looked at.
22+
self.expect('frame variable inner_d')
23+
24+
log = open(logfile, 'r')
25+
n = 0
26+
for line in log:
27+
if re.findall(r'[abcdefg]\.o: FindByNameAndTag\(\)', line):
28+
self.assertTrue("d.o" in line)
29+
n += 1
30+
31+
self.assertEqual(n, 1, log)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include "source.h"
2+
CLASS(A)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include "source.h"
2+
CLASS(B)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include "source.h"
2+
CLASS(C)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include "source.h"
2+
CLASS(D)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include "source.h"
2+
CLASS(E)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include "source.h"
2+
CLASS(F)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include "source.h"
2+
CLASS(G)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#define CLASS(NAME) \
2+
class NAME { \
3+
public: \
4+
struct Inner; \
5+
Inner *i = nullptr; \
6+
}; \
7+
NAME::Inner &getInner##NAME();
8+
9+
CLASS(A)
10+
CLASS(B)
11+
CLASS(C)
12+
CLASS(D)
13+
CLASS(E)
14+
CLASS(F)
15+
CLASS(G)
16+
17+
int main()
18+
{
19+
A::Inner &inner_a = getInnerA();
20+
B::Inner &inner_b = getInnerB();
21+
C::Inner &inner_c = getInnerC();
22+
D::Inner &inner_d = getInnerD();
23+
E::Inner &inner_e = getInnerE();
24+
F::Inner &inner_f = getInnerF();
25+
G::Inner &inner_g = getInnerG();
26+
27+
return 0; // break here
28+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#define CLASS(NAME) \
2+
class NAME { \
3+
public: \
4+
class Inner { \
5+
int j = #NAME[0]; \
6+
}; \
7+
Inner *i = nullptr; \
8+
}; \
9+
\
10+
static NAME::Inner inner; \
11+
static NAME obj; \
12+
NAME::Inner &getInner##NAME() { return inner; }

lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ void AppleDWARFIndex::GetTypes(const DWARFDeclContext &context,
110110
const bool has_qualified_name_hash =
111111
m_apple_types_up->GetHeader().header_data.ContainsAtom(
112112
DWARFMappedHash::eAtomTypeQualNameHash);
113+
113114
const ConstString type_name(context[0].name);
114115
const dw_tag_t tag = context[0].tag;
115116
if (has_tag && has_qualified_name_hash) {
@@ -119,12 +120,32 @@ void AppleDWARFIndex::GetTypes(const DWARFDeclContext &context,
119120
m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()");
120121
m_apple_types_up->FindByNameAndTagAndQualifiedNameHash(
121122
type_name.GetStringRef(), tag, qualified_name_hash, offsets);
122-
} else if (has_tag) {
123+
return;
124+
}
125+
126+
if (has_tag) {
127+
// When searching for a scoped type (for example,
128+
// "std::vector<int>::const_iterator") searching for the innermost
129+
// name alone ("const_iterator") could yield many false
130+
// positives. By searching for the parent type ("vector<int>")
131+
// first we can avoid extracting type DIEs from object files that
132+
// would fail the filter anyway.
133+
if (!has_qualified_name_hash && (context.GetSize() > 1) &&
134+
(context[1].tag == DW_TAG_class_type ||
135+
context[1].tag == DW_TAG_structure_type)) {
136+
DIEArray class_matches;
137+
m_apple_types_up->FindByName(context[1].name, class_matches);
138+
if (class_matches.empty())
139+
return;
140+
}
141+
123142
if (log)
124143
m_module.LogMessage(log, "FindByNameAndTag()");
125144
m_apple_types_up->FindByNameAndTag(type_name.GetStringRef(), tag, offsets);
126-
} else
127-
m_apple_types_up->FindByName(type_name.GetStringRef(), offsets);
145+
return;
146+
}
147+
148+
m_apple_types_up->FindByName(type_name.GetStringRef(), offsets);
128149
}
129150

130151
void AppleDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) {

0 commit comments

Comments
 (0)