proc/eval: optimize variable lookup (#925)

Variable lookup is slow because it requires a full scan of debug_info
to check for package variables, this doesn't matter much in interactive
use but can slow down evaluation of breakpoint conditions
significantly.

Providing benchmark proof for this is hard since this effect doesn't
show for small programs with small debug_info sections.
This commit is contained in:
Alessandro Arzilli 2017-07-18 20:55:24 +02:00 committed by Derek Parker
parent 07e53f7cbb
commit 222cf7fc55
3 changed files with 22 additions and 24 deletions

@ -34,6 +34,7 @@ type BinaryInfo struct {
lineInfo line.DebugLines
goSymTable *gosym.Table
types map[string]dwarf.Offset
packageVars map[string]dwarf.Offset
functions []functionDebugInfo
gStructOffset uint64

@ -132,6 +132,7 @@ func (v sortFunctionsDebugInfoByLowpc) Swap(i, j int) {
func (bi *BinaryInfo) loadDebugInfoMaps(wg *sync.WaitGroup) {
defer wg.Done()
bi.types = make(map[string]dwarf.Offset)
bi.packageVars = make(map[string]dwarf.Offset)
bi.functions = []functionDebugInfo{}
reader := bi.DwarfReader()
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
@ -140,23 +141,23 @@ func (bi *BinaryInfo) loadDebugInfoMaps(wg *sync.WaitGroup) {
}
switch entry.Tag {
case dwarf.TagArrayType, dwarf.TagBaseType, dwarf.TagClassType, dwarf.TagStructType, dwarf.TagUnionType, dwarf.TagConstType, dwarf.TagVolatileType, dwarf.TagRestrictType, dwarf.TagEnumerationType, dwarf.TagPointerType, dwarf.TagSubroutineType, dwarf.TagTypedef, dwarf.TagUnspecifiedType:
name, ok := entry.Val(dwarf.AttrName).(string)
if !ok {
continue
if name, ok := entry.Val(dwarf.AttrName).(string); ok {
if _, exists := bi.types[name]; !exists {
bi.types[name] = entry.Offset
}
}
if _, exists := bi.types[name]; !exists {
bi.types[name] = entry.Offset
reader.SkipChildren()
case dwarf.TagVariable:
if n, ok := entry.Val(dwarf.AttrName).(string); ok {
bi.packageVars[n] = entry.Offset
}
case dwarf.TagSubprogram:
lowpc, ok := entry.Val(dwarf.AttrLowpc).(uint64)
if !ok {
continue
lowpc, ok1 := entry.Val(dwarf.AttrLowpc).(uint64)
highpc, ok2 := entry.Val(dwarf.AttrHighpc).(uint64)
if ok1 && ok2 {
bi.functions = append(bi.functions, functionDebugInfo{lowpc, highpc, entry.Offset})
}
highpc, ok := entry.Val(dwarf.AttrHighpc).(uint64)
if !ok {
continue
}
bi.functions = append(bi.functions, functionDebugInfo{lowpc, highpc, entry.Offset})
reader.SkipChildren()
}
}
sort.Sort(sortFunctionsDebugInfoByLowpc(bi.functions))

@ -650,18 +650,14 @@ func (scope *EvalScope) PackageVariables(cfg LoadConfig) ([]*Variable, error) {
}
func (scope *EvalScope) packageVarAddr(name string) (*Variable, error) {
reader := scope.DwarfReader()
for entry, err := reader.NextPackageVariable(); entry != nil; entry, err = reader.NextPackageVariable() {
if err != nil {
return nil, err
}
n, ok := entry.Val(dwarf.AttrName).(string)
if !ok {
continue
}
for n, off := range scope.BinInfo.packageVars {
if n == name || strings.HasSuffix(n, "/"+name) {
reader := scope.DwarfReader()
reader.Seek(off)
entry, err := reader.Next()
if err != nil {
return nil, err
}
return scope.extractVarInfoFromEntry(entry, reader)
}
}