Debugger: Optimize type lookups.

DwarfImageDebugInfo:
- On initialization, we now walk the list of compilation units and
  build a hash table of all of their contained types. The table is then
  used by GetType() to quickly find the subset of DIEType objects that
  match the requested name, and then compare only those to the
  given constraints to find the best match.

For a more complex image such as libbe or Debugger itself, this reduces
the time for an uncached type lookup from around 50 msec to < 10 usec on
my i7.
This commit is contained in:
Rene Gollent 2015-01-01 17:32:52 -05:00
parent 5b690a810c
commit 492a649b19
2 changed files with 198 additions and 55 deletions

View File

@ -232,6 +232,97 @@ struct DwarfImageDebugInfo::EntryListWrapper {
};
// #pragma mark - DwarfImageDebugInfo::TypeNameKey
struct DwarfImageDebugInfo::TypeNameKey {
BString typeName;
TypeNameKey(const BString& typeName)
:
typeName(typeName)
{
}
uint32 HashValue() const
{
return StringUtils::HashValue(typeName);
}
bool operator==(const TypeNameKey& other) const
{
return typeName == other.typeName;
}
};
// #pragma mark - DwarfImageDebugInfo::TypeNameEntry
struct DwarfImageDebugInfo::TypeNameEntry : TypeNameKey {
TypeNameEntry* next;
TypeEntryList types;
TypeNameEntry(const BString& name)
:
TypeNameKey(name),
types(10, false)
{
}
~TypeNameEntry()
{
}
};
// #pragma mark - DwarfImageDebugInfo::TypeNameEntryHashDefinition
struct DwarfImageDebugInfo::TypeNameEntryHashDefinition {
typedef TypeNameKey KeyType;
typedef TypeNameEntry ValueType;
size_t HashKey(const TypeNameKey& key) const
{
return key.HashValue();
}
size_t Hash(const TypeNameEntry* value) const
{
return value->HashValue();
}
bool Compare(const TypeNameKey& key,
const TypeNameEntry* value) const
{
return key == *value;
}
TypeNameEntry*& GetLink(TypeNameEntry* value) const
{
return value->next;
}
};
// #pragma mark - DwarfImageDebugInfo::TypeEntryInfo
struct DwarfImageDebugInfo::TypeEntryInfo {
DIEType* type;
CompilationUnit* unit;
TypeEntryInfo(DIEType* type, CompilationUnit* unit)
:
type(type),
unit(unit)
{
}
};
// #pragma mark - DwarfImageDebugInfo
@ -247,6 +338,7 @@ DwarfImageDebugInfo::DwarfImageDebugInfo(const ImageInfo& imageInfo,
fFileManager(fileManager),
fTypeLookup(typeLookup),
fTypeCache(typeCache),
fTypeNameTable(NULL),
fFile(file),
fTextSegment(NULL),
fRelocationDelta(0),
@ -266,6 +358,8 @@ DwarfImageDebugInfo::~DwarfImageDebugInfo()
fDebuggerInterface->ReleaseReference();
fFile->ReleaseReference();
fTypeCache->ReleaseReference();
delete fTypeNameTable;
}
@ -294,7 +388,7 @@ DwarfImageDebugInfo::Init()
fPLTSectionEnd = fPLTSectionStart + section->Size();
}
return B_OK;
return _BuildTypeNameTable();
}
@ -426,64 +520,47 @@ DwarfImageDebugInfo::GetFunctions(const BObjectList<SymbolInfo>& symbols,
status_t
DwarfImageDebugInfo::GetType(GlobalTypeCache* cache,
const BString& name, const TypeLookupConstraints& constraints,
Type*& _type)
DwarfImageDebugInfo::GetType(GlobalTypeCache* cache, const BString& name,
const TypeLookupConstraints& constraints, Type*& _type)
{
// iterate through all compilation units
for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i);
i++) {
DwarfTypeContext* typeContext = NULL;
BReference<DwarfTypeContext> typeContextReference;
TypeNameEntry* entry = fTypeNameTable->Lookup(name);
if (entry == NULL)
return B_ENTRY_NOT_FOUND;
// iterate through all types of the compilation unit
for (DebugInfoEntryList::ConstIterator it
= unit->UnitEntry()->Types().GetIterator();
DIEType* typeEntry = dynamic_cast<DIEType*>(it.Next());) {
if (typeEntry->IsDeclaration())
for (int32 i = 0; TypeEntryInfo* info = entry->types.ItemAt(i); i++) {
DIEType* typeEntry = info->type;
if (constraints.HasTypeKind()) {
if (dwarf_tag_to_type_kind(typeEntry->Tag())
!= constraints.TypeKind()) {
continue;
if (constraints.HasTypeKind()) {
if (dwarf_tag_to_type_kind(typeEntry->Tag())
!= constraints.TypeKind())
continue;
if (!_EvaluateBaseTypeConstraints(typeEntry,
constraints))
continue;
}
if (constraints.HasSubtypeKind()
&& dwarf_tag_to_subtype_kind(typeEntry->Tag())
!= constraints.SubtypeKind())
if (!_EvaluateBaseTypeConstraints(typeEntry, constraints))
continue;
BString typeEntryName;
DwarfUtils::GetFullyQualifiedDIEName(typeEntry, typeEntryName);
if (typeEntryName != name)
continue;
// The name matches and the entry is not just a declaration --
// create the type. First create the type context lazily.
if (typeContext == NULL) {
typeContext = new(std::nothrow)
DwarfTypeContext(fArchitecture, fImageInfo.ImageID(), fFile,
unit, NULL, 0, 0, fRelocationDelta, NULL, NULL);
if (typeContext == NULL)
return B_NO_MEMORY;
typeContextReference.SetTo(typeContext, true);
}
// create the type
DwarfType* type;
DwarfTypeFactory typeFactory(typeContext, fTypeLookup, cache);
status_t error = typeFactory.CreateType(typeEntry, type);
if (error != B_OK)
continue;
_type = type;
return B_OK;
}
if (constraints.HasSubtypeKind()
&& dwarf_tag_to_subtype_kind(typeEntry->Tag())
!= constraints.SubtypeKind()) {
continue;
}
DwarfTypeContext* typeContext = new(std::nothrow)
DwarfTypeContext(fArchitecture, fImageInfo.ImageID(), fFile,
info->unit, NULL, 0, 0, fRelocationDelta, NULL, NULL);
if (typeContext == NULL)
return B_NO_MEMORY;
BReference<DwarfTypeContext> typeContextReference(typeContext, true);
// create the type
DwarfType* type;
DwarfTypeFactory typeFactory(typeContext, fTypeLookup, cache);
status_t error = typeFactory.CreateType(typeEntry, type);
if (error != B_OK)
continue;
_type = type;
return B_OK;
}
return B_ENTRY_NOT_FOUND;
@ -1162,7 +1239,7 @@ DwarfImageDebugInfo::_CreateReturnValues(ReturnValueInfoList* returnValueInfos,
bool
DwarfImageDebugInfo::_EvaluateBaseTypeConstraints(DIEType* type,
const TypeLookupConstraints& constraints)
const TypeLookupConstraints& constraints) const
{
if (constraints.HasBaseTypeName()) {
BString baseEntryName;
@ -1204,3 +1281,55 @@ DwarfImageDebugInfo::_EvaluateBaseTypeConstraints(DIEType* type,
return true;
}
status_t
DwarfImageDebugInfo::_BuildTypeNameTable()
{
fTypeNameTable = new(std::nothrow) TypeNameTable;
if (fTypeNameTable == NULL)
return B_NO_MEMORY;
status_t error = fTypeNameTable->Init();
if (error != B_OK)
return error;
// iterate through all compilation units
for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i);
i++) {
// iterate through all types of the compilation unit
for (DebugInfoEntryList::ConstIterator it
= unit->UnitEntry()->Types().GetIterator();
DIEType* typeEntry = dynamic_cast<DIEType*>(it.Next());) {
if (typeEntry->IsDeclaration())
continue;
BString typeEntryName;
DwarfUtils::GetFullyQualifiedDIEName(typeEntry, typeEntryName);
TypeNameEntry* entry = fTypeNameTable->Lookup(typeEntryName);
if (entry == NULL) {
entry = new(std::nothrow) TypeNameEntry(typeEntryName);
if (entry == NULL)
return B_NO_MEMORY;
error = fTypeNameTable->Insert(entry);
if (error != B_OK)
return error;
}
TypeEntryInfo* info = new(std::nothrow) TypeEntryInfo(typeEntry,
unit);
if (info == NULL)
return B_NO_MEMORY;
if (!entry->types.AddItem(info)) {
delete info;
return B_NO_MEMORY;
}
}
}
return B_OK;
}

View File

@ -1,6 +1,6 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2010-2013, Rene Gollent, rene@gollent.com.
* Copyright 2010-2014, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License.
*/
#ifndef DWARF_IMAGE_DEBUG_INFO_H
@ -90,6 +90,16 @@ private:
struct UnwindTargetInterface;
struct EntryListWrapper;
struct TypeNameKey;
struct TypeNameEntry;
struct TypeNameEntryHashDefinition;
typedef BOpenHashTable<TypeNameEntryHashDefinition>
TypeNameTable;
struct TypeEntryInfo;
typedef BObjectList<TypeEntryInfo> TypeEntryList;
private:
status_t _AddSourceCodeInfo(CompilationUnit* unit,
FileSourceCode* sourceCode,
@ -112,7 +122,10 @@ private:
DwarfStackFrameDebugInfo& factory);
bool _EvaluateBaseTypeConstraints(DIEType* type,
const TypeLookupConstraints& constraints);
const TypeLookupConstraints& constraints)
const;
status_t _BuildTypeNameTable();
private:
BLocker fLock;
@ -122,6 +135,7 @@ private:
FileManager* fFileManager;
GlobalTypeLookup* fTypeLookup;
GlobalTypeCache* fTypeCache;
TypeNameTable* fTypeNameTable;
DwarfFile* fFile;
ElfSegment* fTextSegment;
target_addr_t fRelocationDelta;