forked from OSchip/llvm-project
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
This commit is contained in:
parent
715bfa4ef8
commit
418893d8f2
|
@ -0,0 +1,7 @@
|
|||
# There is no guaranteed order in which the linker will order these
|
||||
# files, so we just have a lot of them to make it unlikely that we hit
|
||||
# the right one first by pure luck.
|
||||
|
||||
CXX_SOURCES := main.cpp a.cpp b.cpp c.cpp d.cpp e.cpp f.cpp g.cpp
|
||||
|
||||
include Makefile.rules
|
|
@ -0,0 +1,31 @@
|
|||
import lldb
|
||||
from lldbsuite.test.decorators import *
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test import lldbutil
|
||||
|
||||
|
||||
class CPPAcceleratorTableTestCase(TestBase):
|
||||
|
||||
mydir = TestBase.compute_mydir(__file__)
|
||||
|
||||
@skipUnlessDarwin
|
||||
@skipIf(debug_info=no_match(["dwarf"]))
|
||||
def test(self):
|
||||
"""Test that type lookups fail early (performance)"""
|
||||
self.build()
|
||||
logfile = self.getBuildArtifact('dwarf.log')
|
||||
self.expect('log enable dwarf lookups -f' + logfile)
|
||||
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
|
||||
self, 'break here', lldb.SBFileSpec('main.cpp'))
|
||||
# Pick one from the middle of the list to have a high chance
|
||||
# of it not being in the first file looked at.
|
||||
self.expect('frame variable inner_d')
|
||||
|
||||
log = open(logfile, 'r')
|
||||
n = 0
|
||||
for line in log:
|
||||
if re.findall(r'[abcdefg]\.o: FindByNameAndTag\(\)', line):
|
||||
self.assertTrue("d.o" in line)
|
||||
n += 1
|
||||
|
||||
self.assertEqual(n, 1, log)
|
|
@ -0,0 +1,2 @@
|
|||
#include "source.h"
|
||||
CLASS(A)
|
|
@ -0,0 +1,2 @@
|
|||
#include "source.h"
|
||||
CLASS(B)
|
|
@ -0,0 +1,2 @@
|
|||
#include "source.h"
|
||||
CLASS(C)
|
|
@ -0,0 +1,2 @@
|
|||
#include "source.h"
|
||||
CLASS(D)
|
|
@ -0,0 +1,2 @@
|
|||
#include "source.h"
|
||||
CLASS(E)
|
|
@ -0,0 +1,2 @@
|
|||
#include "source.h"
|
||||
CLASS(F)
|
|
@ -0,0 +1,2 @@
|
|||
#include "source.h"
|
||||
CLASS(G)
|
|
@ -0,0 +1,28 @@
|
|||
#define CLASS(NAME) \
|
||||
class NAME { \
|
||||
public: \
|
||||
struct Inner; \
|
||||
Inner *i = nullptr; \
|
||||
}; \
|
||||
NAME::Inner &getInner##NAME();
|
||||
|
||||
CLASS(A)
|
||||
CLASS(B)
|
||||
CLASS(C)
|
||||
CLASS(D)
|
||||
CLASS(E)
|
||||
CLASS(F)
|
||||
CLASS(G)
|
||||
|
||||
int main()
|
||||
{
|
||||
A::Inner &inner_a = getInnerA();
|
||||
B::Inner &inner_b = getInnerB();
|
||||
C::Inner &inner_c = getInnerC();
|
||||
D::Inner &inner_d = getInnerD();
|
||||
E::Inner &inner_e = getInnerE();
|
||||
F::Inner &inner_f = getInnerF();
|
||||
G::Inner &inner_g = getInnerG();
|
||||
|
||||
return 0; // break here
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#define CLASS(NAME) \
|
||||
class NAME { \
|
||||
public: \
|
||||
class Inner { \
|
||||
int j = #NAME[0]; \
|
||||
}; \
|
||||
Inner *i = nullptr; \
|
||||
}; \
|
||||
\
|
||||
static NAME::Inner inner; \
|
||||
static NAME obj; \
|
||||
NAME::Inner &getInner##NAME() { return inner; }
|
|
@ -110,6 +110,7 @@ void AppleDWARFIndex::GetTypes(const DWARFDeclContext &context,
|
|||
const bool has_qualified_name_hash =
|
||||
m_apple_types_up->GetHeader().header_data.ContainsAtom(
|
||||
DWARFMappedHash::eAtomTypeQualNameHash);
|
||||
|
||||
const ConstString type_name(context[0].name);
|
||||
const dw_tag_t tag = context[0].tag;
|
||||
if (has_tag && has_qualified_name_hash) {
|
||||
|
@ -119,12 +120,32 @@ void AppleDWARFIndex::GetTypes(const DWARFDeclContext &context,
|
|||
m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()");
|
||||
m_apple_types_up->FindByNameAndTagAndQualifiedNameHash(
|
||||
type_name.GetStringRef(), tag, qualified_name_hash, offsets);
|
||||
} else if (has_tag) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_tag) {
|
||||
// When searching for a scoped type (for example,
|
||||
// "std::vector<int>::const_iterator") searching for the innermost
|
||||
// name alone ("const_iterator") could yield many false
|
||||
// positives. By searching for the parent type ("vector<int>")
|
||||
// first we can avoid extracting type DIEs from object files that
|
||||
// would fail the filter anyway.
|
||||
if (!has_qualified_name_hash && (context.GetSize() > 1) &&
|
||||
(context[1].tag == DW_TAG_class_type ||
|
||||
context[1].tag == DW_TAG_structure_type)) {
|
||||
DIEArray class_matches;
|
||||
m_apple_types_up->FindByName(context[1].name, class_matches);
|
||||
if (class_matches.empty())
|
||||
return;
|
||||
}
|
||||
|
||||
if (log)
|
||||
m_module.LogMessage(log, "FindByNameAndTag()");
|
||||
m_apple_types_up->FindByNameAndTag(type_name.GetStringRef(), tag, offsets);
|
||||
} else
|
||||
m_apple_types_up->FindByName(type_name.GetStringRef(), offsets);
|
||||
return;
|
||||
}
|
||||
|
||||
m_apple_types_up->FindByName(type_name.GetStringRef(), offsets);
|
||||
}
|
||||
|
||||
void AppleDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) {
|
||||
|
|
Loading…
Reference in New Issue