FpDebug: Speed up fpdebug (GoNamedChild) by creating hashes for symbol names / Create Hash-lookup field for units to skip some CU

git-svn-id: trunk@63808 -
This commit is contained in:
martin 2020-08-22 20:27:10 +00:00
parent 24a3af8855
commit 24d48052e3
2 changed files with 133 additions and 27 deletions

View File

@ -1256,7 +1256,9 @@ begin
while i > 0 do begin while i > 0 do begin
dec(i); dec(i);
CU := FDwarf.CompilationUnits[i]; CU := FDwarf.CompilationUnits[i];
if CU = SkipCompUnit then if (CU = SkipCompUnit) or
(not CU.KnownNameHashes^[ANameInfo.NameHash and KnownNameHashesBitMask])
then
continue; continue;
//DebugLn(FPDBG_DWARF_SEARCH, ['TDbgDwarf.FindIdentifier search UNIT Name=', CU.FileName]); //DebugLn(FPDBG_DWARF_SEARCH, ['TDbgDwarf.FindIdentifier search UNIT Name=', CU.FileName]);
@ -1275,7 +1277,6 @@ begin
break; break;
end; end;
CU.ScanAllEntries;
if InfoEntry.GoNamedChildEx(ANameInfo) then begin if InfoEntry.GoNamedChildEx(ANameInfo) then begin
if InfoEntry.IsAddressInStartScope(FAddress) then begin if InfoEntry.IsAddressInStartScope(FAddress) then begin
// only variables are marked "external", but types not / so we may need all top level // only variables are marked "external", but types not / so we may need all top level
@ -1429,6 +1430,12 @@ begin
//debugln(FPDBG_DWARF_SEARCH, ['TDbgDwarf.FindIdentifier Searching ', dbgs(InfoEntry.FScope, CU)]); //debugln(FPDBG_DWARF_SEARCH, ['TDbgDwarf.FindIdentifier Searching ', dbgs(InfoEntry.FScope, CU)]);
StartScopeIdx := InfoEntry.ScopeIndex; StartScopeIdx := InfoEntry.ScopeIndex;
tg := InfoEntry.AbbrevTag;
if (tg = DW_TAG_compile_unit) and
(not CU.KnownNameHashes^[NameInfo.NameHash and KnownNameHashesBitMask])
then
break;
//if InfoEntry.Abbrev = nil then //if InfoEntry.Abbrev = nil then
// exit; // exit;
@ -1462,7 +1469,6 @@ begin
end; end;
tg := InfoEntry.AbbrevTag;
if (tg = DW_TAG_class_type) or (tg = DW_TAG_structure_type) then begin if (tg = DW_TAG_class_type) or (tg = DW_TAG_structure_type) then begin
if FindSymbolInStructure(AName,NameInfo, InfoEntry, Result) then begin if FindSymbolInStructure(AName,NameInfo, InfoEntry, Result) then begin
exit; // TODO: check error exit; // TODO: check error

View File

@ -113,6 +113,12 @@ type
{$PACKRECORDS C} {$PACKRECORDS C}
{%endregion Dwarf Header Structures } {%endregion Dwarf Header Structures }
const
KnownNameHashesBitMask = $7FF; // 256 bytes
type
TKnownNameHashesArray = bitpacked array [0..KnownNameHashesBitMask] of Boolean;
PKnownNameHashesArray = ^TKnownNameHashesArray;
{%region Abbreviation Data / Section "debug_abbrev"} {%region Abbreviation Data / Section "debug_abbrev"}
{ TDwarfAbbrev } { TDwarfAbbrev }
TDwarfAbbrevFlag = ( TDwarfAbbrevFlag = (
@ -200,6 +206,7 @@ type
TNameSearchInfo = record TNameSearchInfo = record
NameUpper, NameLower: String; NameUpper, NameLower: String;
NameHash: Word;
end; end;
{%region Information Entry / Section "debug_info"} {%region Information Entry / Section "debug_info"}
@ -222,6 +229,7 @@ type
TDwarfScopeInfoRec = record TDwarfScopeInfoRec = record
Link: Integer; Link: Integer;
Entry: Pointer; Entry: Pointer;
NameHash: Word;
end; end;
PDwarfScopeInfoRec = ^TDwarfScopeInfoRec; PDwarfScopeInfoRec = ^TDwarfScopeInfoRec;
@ -240,6 +248,7 @@ type
FIndex: Integer; FIndex: Integer;
function GetChild: TDwarfScopeInfo; inline; function GetChild: TDwarfScopeInfo; inline;
function GetChildIndex: Integer; inline; function GetChildIndex: Integer; inline;
function GetCurrent: PDwarfScopeInfoRec;
function GetEntry: Pointer; inline; function GetEntry: Pointer; inline;
function GetNext: TDwarfScopeInfo; inline; function GetNext: TDwarfScopeInfo; inline;
function GetNextIndex: Integer; inline; function GetNextIndex: Integer; inline;
@ -255,6 +264,7 @@ type
function IsValid: Boolean; inline; function IsValid: Boolean; inline;
property Index: Integer read FIndex write SetIndex; property Index: Integer read FIndex write SetIndex;
property Entry: Pointer read GetEntry; property Entry: Pointer read GetEntry;
property Current: PDwarfScopeInfoRec read GetCurrent;
function HasParent: Boolean; inline; function HasParent: Boolean; inline;
function HasNext: Boolean; inline; function HasNext: Boolean; inline;
@ -317,6 +327,8 @@ type
function HasAttrib(AnAttrib: Cardinal): Boolean; inline; function HasAttrib(AnAttrib: Cardinal): Boolean; inline;
property AttribForm[AnIdx: Integer]: Cardinal read GetAttribForm; property AttribForm[AnIdx: Integer]: Cardinal read GetAttribForm;
procedure ComputeKnownHashes(AKNownHashes: PKnownNameHashesArray);
function GoNamedChild(AName: String): Boolean; function GoNamedChild(AName: String): Boolean;
// find in enum too // TODO: control search with a flags param, if needed // find in enum too // TODO: control search with a flags param, if needed
function GoNamedChildEx(const ANameInfo: TNameSearchInfo): Boolean; function GoNamedChildEx(const ANameInfo: TNameSearchInfo): Boolean;
@ -581,9 +593,11 @@ type
FScope: TDwarfScopeInfo; FScope: TDwarfScopeInfo;
FScopeList: TDwarfScopeList; FScopeList: TDwarfScopeList;
FScannedToEnd: Boolean; FScannedToEnd: Boolean;
FKnownNameHashes: TKnownNameHashesArray;
procedure BuildAddressMap; procedure BuildAddressMap;
function GetAddressMap: TMap; function GetAddressMap: TMap;
function GetKnownNameHashes: PKnownNameHashesArray; inline;
function GetUnitName: String; function GetUnitName: String;
function ReadTargetAddressFromDwarfSection(var AData: Pointer; AIncPointer: Boolean = False): TFpDbgMemLocation; function ReadTargetAddressFromDwarfSection(var AData: Pointer; AIncPointer: Boolean = False): TFpDbgMemLocation;
function ReadDwarfSectionOffsetOrLenFromDwarfSection(var AData: Pointer; AIncPointer: Boolean = False): TFpDbgMemLocation; function ReadDwarfSectionOffsetOrLenFromDwarfSection(var AData: Pointer; AIncPointer: Boolean = False): TFpDbgMemLocation;
@ -604,7 +618,6 @@ type
function ReadValue(AAttribute: Pointer; AForm: Cardinal; out AValue: TByteDynArray; AnFormString: Boolean = False): Boolean; function ReadValue(AAttribute: Pointer; AForm: Cardinal; out AValue: TByteDynArray; AnFormString: Boolean = False): Boolean;
// Read a value that contains an address. The address is evaluated using MapAddressToNewValue // Read a value that contains an address. The address is evaluated using MapAddressToNewValue
function ReadAddressValue(AAttribute: Pointer; AForm: Cardinal; out AValue: QWord): Boolean; function ReadAddressValue(AAttribute: Pointer; AForm: Cardinal; out AValue: QWord): Boolean;
public public
constructor Create(AOwner: TFpDwarfInfo; ADebugFile: PDwarfDebugFile; ADataOffset: QWord; ALength: QWord; AVersion: Word; AAbbrevOffset: QWord; AAddressSize: Byte; AIsDwarf64: Boolean); virtual; constructor Create(AOwner: TFpDwarfInfo; ADebugFile: PDwarfDebugFile; ADataOffset: QWord; ALength: QWord; AVersion: Word; AAbbrevOffset: QWord; AAddressSize: Byte; AIsDwarf64: Boolean); virtual;
destructor Destroy; override; destructor Destroy; override;
@ -647,7 +660,7 @@ type
property InfoDataLength: QWord read FLength; // length of info property InfoDataLength: QWord read FLength; // length of info
property AddressMap: TMap read GetAddressMap; property AddressMap: TMap read GetAddressMap;
property AbbrevList: TDwarfAbbrevList read FAbbrevList; property AbbrevList: TDwarfAbbrevList read FAbbrevList;
property KnownNameHashes: PKnownNameHashesArray read GetKnownNameHashes; // Only for TOP-LEVEL entries
end; end;
{ TFpDwarfInfo } { TFpDwarfInfo }
@ -772,6 +785,7 @@ function NameInfoForSearch(const AName: String): TNameSearchInfo;
begin begin
Result.NameLower := UTF8LowerCase(AName); Result.NameLower := UTF8LowerCase(AName);
Result.NameUpper := UTF8UpperCase(AName); Result.NameUpper := UTF8UpperCase(AName);
Result.NameHash := objpas.Hash(Result.NameUpper) and $7fff or $8000;
end; end;
function Dbgs(AInfoData: Pointer; ACompUnit: TDwarfCompilationUnit): String; function Dbgs(AInfoData: Pointer; ACompUnit: TDwarfCompilationUnit): String;
@ -1632,6 +1646,13 @@ begin
Result := -1; Result := -1;
end; end;
function TDwarfScopeInfo.GetCurrent: PDwarfScopeInfoRec;
begin
Result := nil;
if IsValid then
Result := @FScopeList^.List[FIndex];
end;
function TDwarfScopeInfo.GetParent: TDwarfScopeInfo; function TDwarfScopeInfo.GetParent: TDwarfScopeInfo;
var var
l: Integer; l: Integer;
@ -2520,6 +2541,55 @@ begin
end; end;
end; end;
procedure TDwarfInformationEntry.ComputeKnownHashes(
AKNownHashes: PKnownNameHashesArray);
var
EntryName: PChar;
NextTopLevel: Integer;
h: LongWord;
InEnum: Boolean;
begin
InEnum := False;
if not HasValidScope then
exit;
NextTopLevel := 0;
dec(FScope.FIndex);
while (FScope.Index < FScope.FScopeList^.HighestKnown) do begin
inc(FScope.FIndex);
ScopeChanged;
PrepareAbbrev;
if not (dafHasName in FAbbrev^.flags) then begin
if FScope.Index >= NextTopLevel then
NextTopLevel := FScope.GetNextIndex;
Continue;
end;
if not ReadValue(DW_AT_name, EntryName) then begin
if FScope.Index >= NextTopLevel then
NextTopLevel := FScope.GetNextIndex;
Continue;
end;
h := objpas.Hash(UTF8UpperCase(EntryName)) and $7fff or $8000;
FScope.Current^.NameHash := h;
if (FScope.Index >= NextTopLevel) or InEnum then
AKNownHashes^[h and KnownNameHashesBitMask] := True;
if FScope.Index >= NextTopLevel then begin
InEnum := False;
if FAbbrev^.tag = DW_TAG_enumeration_type then begin
InEnum := True;
NextTopLevel := FScope.GetNextIndex;
Continue;
end;
end;
if FScope.Index >= NextTopLevel then
NextTopLevel := FScope.GetNextIndex;
end;
end;
function TDwarfInformationEntry.GetScopeIndex: Integer; function TDwarfInformationEntry.GetScopeIndex: Integer;
begin begin
Result := FScope.Index; Result := FScope.Index;
@ -2573,6 +2643,7 @@ var
EntryName: PChar; EntryName: PChar;
InEnum: Boolean; InEnum: Boolean;
ParentScopIdx: Integer; ParentScopIdx: Integer;
sc: PDwarfScopeInfoRec;
begin begin
Result := False; Result := False;
InEnum := False; InEnum := False;
@ -2583,22 +2654,31 @@ begin
exit; exit;
while true do begin while true do begin
while HasValidScope do begin while HasValidScope do begin
sc := FScope.Current;
if sc^.NameHash = 0 then begin
GoNext;
Continue;
end;
PrepareAbbrev; PrepareAbbrev;
if not (dafHasName in FAbbrev^.flags) then begin if not (dafHasName in FAbbrev^.flags) then begin
assert(false);
GoNext; GoNext;
Continue; Continue;
end; end;
if not ReadValue(DW_AT_name, EntryName) then begin if (sc^.NameHash = ANameInfo.NameHash) then begin
GoNext; if not ReadValue(DW_AT_name, EntryName) then begin
Continue; GoNext;
end; Continue;
end;
if CompareUtf8BothCase(PChar(ANameInfo.NameUpper), PChar(ANameInfo.nameLower), EntryName) then begin if CompareUtf8BothCase(PChar(ANameInfo.NameUpper), PChar(ANameInfo.nameLower), EntryName) then begin
// TODO: check DW_AT_start_scope; // TODO: check DW_AT_start_scope;
DebugLn(FPDBG_DWARF_SEARCH, ['GoNamedChildEX found ', dbgs(FScope, FCompUnit), ' Result=', DbgSName(Self), ' FOR ', ANameInfo.nameLower]); DebugLn(FPDBG_DWARF_SEARCH, ['GoNamedChildEX found ', dbgs(FScope, FCompUnit), ' Result=', DbgSName(Self), ' FOR ', ANameInfo.nameLower]);
Result := True; Result := True;
exit; exit;
end;
end; end;
if FAbbrev^.tag = DW_TAG_enumeration_type then begin if FAbbrev^.tag = DW_TAG_enumeration_type then begin
@ -2626,6 +2706,7 @@ function TDwarfInformationEntry.GoNamedChildMatchCaseEx(
const ANameInfo: TNameSearchInfo): Boolean; const ANameInfo: TNameSearchInfo): Boolean;
var var
EntryName: PChar; EntryName: PChar;
sc: PDwarfScopeInfoRec;
begin begin
Result := False; Result := False;
if ANameInfo.NameUpper = '' then if ANameInfo.NameUpper = '' then
@ -2635,25 +2716,34 @@ begin
exit; exit;
while HasValidScope do begin while HasValidScope do begin
sc := FScope.Current;
if sc^.NameHash = 0 then begin
GoNext;
Continue;
end;
PrepareAbbrev; PrepareAbbrev;
if not (dafHasName in FAbbrev^.flags) then begin if not (dafHasName in FAbbrev^.flags) then begin
Assert(false);
GoNext; GoNext;
Continue; Continue;
end; end;
if not ReadValue(DW_AT_name, EntryName) then begin if (sc^.NameHash = ANameInfo.NameHash) then begin
GoNext; if not ReadValue(DW_AT_name, EntryName) then begin
Continue; GoNext;
Continue;
end;
if CompareMem(PChar(ANameInfo.nameLower), @EntryName, Length(EntryName)) then begin
// TODO: check DW_AT_start_scope;
DebugLn(FPDBG_DWARF_SEARCH, ['GoNamedChildEX found ', dbgs(FScope, FCompUnit), ' Result=', DbgSName(Self), ' FOR ', ANameInfo.nameLower]);
Result := True;
exit;
end;
end; end;
if CompareMem(PChar(ANameInfo.nameLower), @EntryName, Length(EntryName)) then begin GoNext;
// TODO: check DW_AT_start_scope;
DebugLn(FPDBG_DWARF_SEARCH, ['GoNamedChildEX found ', dbgs(FScope, FCompUnit), ' Result=', DbgSName(Self), ' FOR ', ANameInfo.nameLower]);
Result := True;
exit;
end;
GoNext;
end; end;
end; end;
@ -3827,6 +3917,11 @@ begin
Result := FAddressMap; Result := FAddressMap;
end; end;
function TDwarfCompilationUnit.GetKnownNameHashes: PKnownNameHashesArray;
begin
Result := @FKnownNameHashes;
end;
function TDwarfCompilationUnit.FullFileName(const AFileName: string): String; function TDwarfCompilationUnit.FullFileName(const AFileName: string): String;
begin begin
Result := AFileName; Result := AFileName;
@ -3870,8 +3965,6 @@ var
begin begin
if FAddressMapBuild then Exit; if FAddressMapBuild then Exit;
ScanAllEntries;
Scope := FScope; Scope := FScope;
ScopeIdx := Scope.Index; ScopeIdx := Scope.Index;
@ -4015,6 +4108,7 @@ var
Form: Cardinal; Form: Cardinal;
StatementListOffs, Offs: QWord; StatementListOffs, Offs: QWord;
Scope: TDwarfScopeInfo; Scope: TDwarfScopeInfo;
InfoEntry: TDwarfInformationEntry;
begin begin
//DebugLn(FPDBG_DWARF_VERBOSE, ['-- compilation unit --']); //DebugLn(FPDBG_DWARF_VERBOSE, ['-- compilation unit --']);
//DebugLn(FPDBG_DWARF_VERBOSE, [' data offset: ', ADataOffset]); //DebugLn(FPDBG_DWARF_VERBOSE, [' data offset: ', ADataOffset]);
@ -4069,6 +4163,12 @@ begin
end; end;
FValid := True; FValid := True;
ScanAllEntries;
InfoEntry := TDwarfInformationEntry.Create(Self, nil);
InfoEntry.ScopeIndex := FirstScope.Index;
InfoEntry.ComputeKnownHashes(@FKnownNameHashes);
InfoEntry.ReleaseReference;
AttribList.EvalCount := 0; AttribList.EvalCount := 0;
/// TODO: (dafHasName in Abbrev.flags) /// TODO: (dafHasName in Abbrev.flags)
if LocateAttribute(Scope.Entry, DW_AT_name, AttribList, Attrib, Form) if LocateAttribute(Scope.Entry, DW_AT_name, AttribList, Attrib, Form)