pkg/proc: split off rangeParent from function extras (#4173)

The rangeParent calculation was changed 0b74953f0 to address slowness
(due to repeated calculations) when calling PackageVariables. That
changed caused to program to use a lot of memory due to having to
calculate the range bodies of every function. This change reverts
0b74953f0 and splits off rangeBodies calculation from the extras method
of Function, so that it isn't called from PackageVariables.

Fixes #4146
This commit is contained in:
Alessandro Arzilli
2025-10-06 20:28:11 +02:00
committed by GitHub
parent 949bd82138
commit 7b33c542f4
4 changed files with 29 additions and 33 deletions

View File

@ -25,9 +25,6 @@ import (
"sync" "sync"
"time" "time"
"github.com/derekparker/trie/v3"
"github.com/hashicorp/golang-lru/v2"
"github.com/go-delve/delve/pkg/astutil" "github.com/go-delve/delve/pkg/astutil"
pdwarf "github.com/go-delve/delve/pkg/dwarf" pdwarf "github.com/go-delve/delve/pkg/dwarf"
"github.com/go-delve/delve/pkg/dwarf/frame" "github.com/go-delve/delve/pkg/dwarf/frame"
@ -41,6 +38,7 @@ import (
"github.com/go-delve/delve/pkg/logflags" "github.com/go-delve/delve/pkg/logflags"
"github.com/go-delve/delve/pkg/proc/debuginfod" "github.com/go-delve/delve/pkg/proc/debuginfod"
"github.com/go-delve/delve/pkg/proc/evalop" "github.com/go-delve/delve/pkg/proc/evalop"
"github.com/hashicorp/golang-lru/v2"
) )
const ( const (
@ -69,8 +67,6 @@ type BinaryInfo struct {
// lookupGenericFunc maps function names, with their type parameters removed, to functions. // lookupGenericFunc maps function names, with their type parameters removed, to functions.
// Functions that are not generic are not added to this map. // Functions that are not generic are not added to this map.
lookupGenericFunc map[string][]*Function lookupGenericFunc map[string][]*Function
// lookupRangeBodyFunc maps function names to the range body functions.
lookupRangeBodyFunc *trie.Trie[*Function]
// SymNames maps addr to a description *elf.Symbol of this addr. // SymNames maps addr to a description *elf.Symbol of this addr.
SymNames map[uint64]*elf.Symbol SymNames map[uint64]*elf.Symbol
@ -536,19 +532,18 @@ type Function struct {
// extraCache contains information about this function that is only needed for // extraCache contains information about this function that is only needed for
// some operations and is expensive to compute or store for every function. // some operations and is expensive to compute or store for every function.
extraCache *functionExtra extraCache *functionExtra
// rangeBodiesCache caches the list of range-over-func body closures for
// this function. Only one of extraCache.rangeParent and rangeBodiesCache
// should be set at any given time.
rangeBodiesCache []*Function
} }
type functionExtra struct { type functionExtra struct {
// closureStructType is the cached struct type for closures for this function // closureStructType is the cached struct type for closures for this function
closureStructType *godwarf.StructType closureStructType *godwarf.StructType
// rangeParent is set when this function is a range-over-func body closure // rangeParent is set when this function is a range-over-func body closure
// and points to the function that the closure was generated from. // and points to the function that the closure was generated from.
rangeParent *Function rangeParent *Function
// rangeBodies is the list of range-over-func body closures for this
// function. Only one between rangeParent and rangeBodies should be set at
// any given time.
rangeBodies []*Function
} }
// instRange returns the indexes in fn.Name of the type parameter // instRange returns the indexes in fn.Name of the type parameter
@ -776,17 +771,29 @@ func (fn *Function) extra(bi *BinaryInfo) *functionExtra {
fn.extraCache.rangeParent = bi.lookupOneFunc(rangeParentName) fn.extraCache.rangeParent = bi.lookupOneFunc(rangeParentName)
} }
// Find range-over-func bodies of this function return fn.extraCache
if fn.extraCache.rangeParent == nil {
lookupFunc := bi.LookupRangeBodyFunc()
for _, fn2 := range lookupFunc.PrefixSearchIter(fn.Name) {
if fn2.rangeParentName() == fn.Name {
fn.extraCache.rangeBodies = append(fn.extraCache.rangeBodies, fn2)
}
}
} }
return fn.extraCache // rangeBodies returns the list of range-over-func body closures for this
// function.
func (fn *Function) rangeBodies(bi *BinaryInfo) []*Function {
if fn == nil {
return nil
}
if fn.rangeBodiesCache != nil {
return fn.rangeBodiesCache
}
extra := fn.extra(bi)
if extra.rangeParent != nil {
return nil
}
for i := range bi.Functions {
fn2 := &bi.Functions[i]
if strings.HasPrefix(fn2.Name, fn.Name) && fn2.rangeParentName() == fn.Name {
fn.rangeBodiesCache = append(fn.rangeBodiesCache, fn2)
}
}
return fn.rangeBodiesCache
} }
type constantsMap map[dwarfRef]*constantType type constantsMap map[dwarfRef]*constantType
@ -2626,7 +2633,6 @@ func (bi *BinaryInfo) loadDebugInfoMaps(image *Image, debugInfoBytes, debugLineB
bi.lookupFunc = nil bi.lookupFunc = nil
bi.lookupGenericFunc = nil bi.lookupGenericFunc = nil
bi.lookupRangeBodyFunc = nil
for _, cu := range image.compileUnits { for _, cu := range image.compileUnits {
if cu.lineInfo != nil { if cu.lineInfo != nil {
@ -2672,16 +2678,6 @@ func (bi *BinaryInfo) LookupFunc() map[string][]*Function {
return bi.lookupFunc return bi.lookupFunc
} }
func (bi *BinaryInfo) LookupRangeBodyFunc() *trie.Trie[*Function] {
if bi.lookupRangeBodyFunc == nil {
bi.lookupRangeBodyFunc = trie.New[*Function]()
for i := range bi.Functions {
bi.lookupRangeBodyFunc.Add(bi.Functions[i].Name, &bi.Functions[i])
}
}
return bi.lookupRangeBodyFunc
}
func (bi *BinaryInfo) lookupOneFunc(name string) *Function { func (bi *BinaryInfo) lookupOneFunc(name string) *Function {
if name == evalop.DebugPinnerFunctionName && bi.debugPinnerFn != nil { if name == evalop.DebugPinnerFunctionName && bi.debugPinnerFn != nil {
return bi.debugPinnerFn return bi.debugPinnerFn

View File

@ -855,7 +855,7 @@ func next(dbp *Target, stepInto, inlinedStepOut bool) error {
rpoff = rangeFrames[len(rangeFrames)-2].FrameOffset() rpoff = rangeFrames[len(rangeFrames)-2].FrameOffset()
} }
rpc := astutil.And(sameGCond, astutil.Eql(astutil.PkgVar("runtime", "rangeParentOffset"), astutil.Int(rpoff))) rpc := astutil.And(sameGCond, astutil.Eql(astutil.PkgVar("runtime", "rangeParentOffset"), astutil.Int(rpoff)))
for _, fn := range rangeParent.extra(bi).rangeBodies { for _, fn := range rangeParent.rangeBodies(bi) {
if fn.Entry != 0 { if fn.Entry != 0 {
pc, err := FirstPCAfterPrologue(dbp, fn, false) pc, err := FirstPCAfterPrologue(dbp, fn, false)
if err != nil { if err != nil {

View File

@ -149,7 +149,7 @@ func dwarfToRuntimeType(bi *BinaryInfo, mem MemoryReadWriter, typ godwarf.Type)
return 0, false, false, nil return 0, false, false, nil
} }
mds, err := bi.getModuleData(mem) mds, err := LoadModuleData(bi, mem)
if err != nil { if err != nil {
return 0, false, false, err return 0, false, false, err
} }

View File

@ -2141,7 +2141,7 @@ func (v *Variable) loadInterface(recurseLevel int, loadData bool, cfg LoadConfig
return return
} }
mds, err := _type.bi.getModuleData(_type.mem) mds, err := LoadModuleData(_type.bi, _type.mem)
if err != nil { if err != nil {
v.Unreadable = fmt.Errorf("error loading module data: %v", err) v.Unreadable = fmt.Errorf("error loading module data: %v", err)
return return