From c66c6408a5f32e84cc3955fe97302ad6d78df24e Mon Sep 17 00:00:00 2001 From: aarzilli Date: Sat, 5 Mar 2016 13:04:11 +0100 Subject: [PATCH] proc: Caching type offsets Caches the mapping of type names to offset in debug_info to speed up variable evaluation. BEFORE: BenchmarkArray-4 100 13'238'441 ns/op 0.62 MB/s BenchmarkArrayPointer-4 200 10'044'093 ns/op 0.87 MB/s BenchmarkMap-4 1000 1'332'530 ns/op 0.77 MB/s BenchmarkGoroutinesInfo-4 10 114'677'462 ns/op BenchmarkLocalVariables-4 2000 1'223'975 ns/op AFTER: BenchmarkArray-4 200 9'925'686 ns/op 0.83 MB/s BenchmarkArrayPointer-4 100 11'143'930 ns/op 0.78 MB/s BenchmarkMap-4 2000 1'302'520 ns/op 0.79 MB/s BenchmarkGoroutinesInfo-4 30 35'079'549 ns/op BenchmarkLocalVariables-4 1000 1'137'299 ns/op Note in particular the speedup of BenchmarkGoroutinesInfo, since proc.(*Variable).parseG is a function we call a lot. --- proc/proc.go | 20 ++++++-------------- proc/proc_test.go | 2 +- proc/types.go | 29 ++++++++++++++++++++++++----- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/proc/proc.go b/proc/proc.go index bfad0c0e..6bb00dea 100644 --- a/proc/proc.go +++ b/proc/proc.go @@ -58,6 +58,7 @@ type Process struct { exited bool ptraceChan chan func() ptraceDoneChan chan interface{} + types map[string]dwarf.Offset } // New returns an initialized Process struct. Before returning, @@ -149,11 +150,12 @@ func (dbp *Process) LoadInformation(path string) error { return err } - wg.Add(4) + wg.Add(5) go dbp.loadProcessInformation(&wg) go dbp.parseDebugFrame(exe, &wg) go dbp.obtainGoSymbols(exe, &wg) go dbp.parseDebugLineInfo(exe, &wg) + go dbp.loadTypeMap(&wg) wg.Wait() return nil @@ -658,19 +660,9 @@ func (dbp *Process) Funcs() []gosym.Func { // Types returns list of types present in the debugged program. func (dbp *Process) Types() ([]string, error) { - reader := dbp.DwarfReader() - types := []string{} - seen := map[string]struct{}{} - for entry, err := reader.NextType(); entry != nil; entry, err = reader.NextType() { - if err != nil { - return nil, err - } - if n, ok := entry.Val(dwarf.AttrName).(string); ok { - if _, isseen := seen[n]; !isseen { - seen[n] = struct{}{} - types = append(types, n) - } - } + types := make([]string, 0, len(dbp.types)) + for k := range dbp.types { + types = append(types, k) } return types, nil } diff --git a/proc/proc_test.go b/proc/proc_test.go index 2ac84421..a12b58ae 100644 --- a/proc/proc_test.go +++ b/proc/proc_test.go @@ -1626,7 +1626,7 @@ func TestPackageVariables(t *testing.T) { func TestIssue149(t *testing.T) { ver, _ := ParseVersionString(runtime.Version()) - if ver.Major > 0 && !ver.AfterOrEqual(GoVersion{1, 7, 0, 0, 0}) { + if ver.Major > 0 && !ver.AfterOrEqual(GoVersion{1, 7, 0, 0, 0}) { return } // setting breakpoint on break statement diff --git a/proc/types.go b/proc/types.go index 128e6b7d..8970d8c8 100644 --- a/proc/types.go +++ b/proc/types.go @@ -1,20 +1,21 @@ package proc import ( + "github.com/derekparker/delve/dwarf/reader" "go/ast" "golang.org/x/debug/dwarf" "reflect" "strings" + "sync" ) // Do not call this function directly it isn't able to deal correctly with package paths func (dbp *Process) findType(name string) (dwarf.Type, error) { - reader := dbp.DwarfReader() - typentry, err := reader.SeekToTypeNamed(name) - if err != nil { - return nil, err + off, found := dbp.types[name] + if !found { + return nil, reader.TypeNotFoundErr } - return dbp.dwarf.Type(typentry.Offset) + return dbp.dwarf.Type(off) } func (dbp *Process) pointerTo(typ dwarf.Type) dwarf.Type { @@ -83,6 +84,24 @@ func (dbp *Process) loadPackageMap() error { return nil } +func (dbp *Process) loadTypeMap(wg *sync.WaitGroup) { + defer wg.Done() + dbp.types = make(map[string]dwarf.Offset) + reader := dbp.DwarfReader() + for entry, err := reader.NextType(); entry != nil; entry, err = reader.NextType() { + if err != nil { + break + } + name, ok := entry.Val(dwarf.AttrName).(string) + if !ok { + continue + } + if _, exists := dbp.types[name]; !exists { + dbp.types[name] = entry.Offset + } + } +} + func (dbp *Process) expandPackagesInType(expr ast.Expr) { switch e := expr.(type) { case *ast.ArrayType: -- GitLab