mirror of
https://github.com/go-delve/delve.git
synced 2025-10-30 10:17:03 +08:00
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.
This commit is contained in:
20
proc/proc.go
20
proc/proc.go
@ -58,6 +58,7 @@ type Process struct {
|
|||||||
exited bool
|
exited bool
|
||||||
ptraceChan chan func()
|
ptraceChan chan func()
|
||||||
ptraceDoneChan chan interface{}
|
ptraceDoneChan chan interface{}
|
||||||
|
types map[string]dwarf.Offset
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns an initialized Process struct. Before returning,
|
// New returns an initialized Process struct. Before returning,
|
||||||
@ -149,11 +150,12 @@ func (dbp *Process) LoadInformation(path string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Add(4)
|
wg.Add(5)
|
||||||
go dbp.loadProcessInformation(&wg)
|
go dbp.loadProcessInformation(&wg)
|
||||||
go dbp.parseDebugFrame(exe, &wg)
|
go dbp.parseDebugFrame(exe, &wg)
|
||||||
go dbp.obtainGoSymbols(exe, &wg)
|
go dbp.obtainGoSymbols(exe, &wg)
|
||||||
go dbp.parseDebugLineInfo(exe, &wg)
|
go dbp.parseDebugLineInfo(exe, &wg)
|
||||||
|
go dbp.loadTypeMap(&wg)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -658,19 +660,9 @@ func (dbp *Process) Funcs() []gosym.Func {
|
|||||||
|
|
||||||
// Types returns list of types present in the debugged program.
|
// Types returns list of types present in the debugged program.
|
||||||
func (dbp *Process) Types() ([]string, error) {
|
func (dbp *Process) Types() ([]string, error) {
|
||||||
reader := dbp.DwarfReader()
|
types := make([]string, 0, len(dbp.types))
|
||||||
types := []string{}
|
for k := range dbp.types {
|
||||||
seen := map[string]struct{}{}
|
types = append(types, k)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return types, nil
|
return types, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,21 @@
|
|||||||
package proc
|
package proc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/derekparker/delve/dwarf/reader"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"golang.org/x/debug/dwarf"
|
"golang.org/x/debug/dwarf"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Do not call this function directly it isn't able to deal correctly with package paths
|
// 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) {
|
func (dbp *Process) findType(name string) (dwarf.Type, error) {
|
||||||
reader := dbp.DwarfReader()
|
off, found := dbp.types[name]
|
||||||
typentry, err := reader.SeekToTypeNamed(name)
|
if !found {
|
||||||
if err != nil {
|
return nil, reader.TypeNotFoundErr
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
return dbp.dwarf.Type(typentry.Offset)
|
return dbp.dwarf.Type(off)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbp *Process) pointerTo(typ dwarf.Type) dwarf.Type {
|
func (dbp *Process) pointerTo(typ dwarf.Type) dwarf.Type {
|
||||||
@ -83,6 +84,24 @@ func (dbp *Process) loadPackageMap() error {
|
|||||||
return nil
|
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) {
|
func (dbp *Process) expandPackagesInType(expr ast.Expr) {
|
||||||
switch e := expr.(type) {
|
switch e := expr.(type) {
|
||||||
case *ast.ArrayType:
|
case *ast.ArrayType:
|
||||||
|
|||||||
Reference in New Issue
Block a user