proc: avoid constructing unnecessary strings when evaluating variables
Avoids constructing: 1. name of runtime.curg fields while executing parseG 2. the location expression while evaluating any variable. Benchmark before: BenchmarkConditionalBreakpoints-4 1 4953889884 ns/op Benchmark after: BenchmarkConditionalBreakpoints-4 1 4419775128 ns/op Updates #1549
This commit is contained in:
parent
431dea7ee6
commit
a61b6c0d7c
@ -809,29 +809,51 @@ func (bi *BinaryInfo) LoadImageFromData(dwdata *dwarf.Data, debugFrameBytes, deb
|
|||||||
bi.Images = append(bi.Images, image)
|
bi.Images = append(bi.Images, image)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bi *BinaryInfo) locationExpr(entry godwarf.Entry, attr dwarf.Attr, pc uint64) ([]byte, string, error) {
|
func (bi *BinaryInfo) locationExpr(entry godwarf.Entry, attr dwarf.Attr, pc uint64) ([]byte, *locationExpr, error) {
|
||||||
a := entry.Val(attr)
|
a := entry.Val(attr)
|
||||||
if a == nil {
|
if a == nil {
|
||||||
return nil, "", fmt.Errorf("no location attribute %s", attr)
|
return nil, nil, fmt.Errorf("no location attribute %s", attr)
|
||||||
}
|
}
|
||||||
if instr, ok := a.([]byte); ok {
|
if instr, ok := a.([]byte); ok {
|
||||||
var descr bytes.Buffer
|
return instr, &locationExpr{isBlock: true, instr: instr}, nil
|
||||||
fmt.Fprintf(&descr, "[block] ")
|
|
||||||
op.PrettyPrint(&descr, instr)
|
|
||||||
return instr, descr.String(), nil
|
|
||||||
}
|
}
|
||||||
off, ok := a.(int64)
|
off, ok := a.(int64)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, "", fmt.Errorf("could not interpret location attribute %s", attr)
|
return nil, nil, fmt.Errorf("could not interpret location attribute %s", attr)
|
||||||
}
|
}
|
||||||
instr := bi.loclistEntry(off, pc)
|
instr := bi.loclistEntry(off, pc)
|
||||||
if instr == nil {
|
if instr == nil {
|
||||||
return nil, "", fmt.Errorf("could not find loclist entry at %#x for address %#x", off, pc)
|
return nil, nil, fmt.Errorf("could not find loclist entry at %#x for address %#x", off, pc)
|
||||||
|
}
|
||||||
|
return instr, &locationExpr{pc: pc, off: off, instr: instr}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type locationExpr struct {
|
||||||
|
isBlock bool
|
||||||
|
isEscaped bool
|
||||||
|
off int64
|
||||||
|
pc uint64
|
||||||
|
instr []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (le *locationExpr) String() string {
|
||||||
|
if le == nil {
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
var descr bytes.Buffer
|
var descr bytes.Buffer
|
||||||
fmt.Fprintf(&descr, "[%#x:%#x] ", off, pc)
|
|
||||||
op.PrettyPrint(&descr, instr)
|
if le.isBlock {
|
||||||
return instr, descr.String(), nil
|
fmt.Fprintf(&descr, "[block] ")
|
||||||
|
op.PrettyPrint(&descr, le.instr)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(&descr, "[%#x:%#x] ", le.off, le.pc)
|
||||||
|
op.PrettyPrint(&descr, le.instr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if le.isEscaped {
|
||||||
|
fmt.Fprintf(&descr, " (escaped)")
|
||||||
|
}
|
||||||
|
return descr.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocationCovers returns the list of PC addresses that is covered by the
|
// LocationCovers returns the list of PC addresses that is covered by the
|
||||||
@ -877,10 +899,10 @@ func (bi *BinaryInfo) LocationCovers(entry *dwarf.Entry, attr dwarf.Attr) ([][2]
|
|||||||
// This will either be an int64 address or a slice of Pieces for locations
|
// This will either be an int64 address or a slice of Pieces for locations
|
||||||
// that don't correspond to a single memory address (registers, composite
|
// that don't correspond to a single memory address (registers, composite
|
||||||
// locations).
|
// locations).
|
||||||
func (bi *BinaryInfo) Location(entry godwarf.Entry, attr dwarf.Attr, pc uint64, regs op.DwarfRegisters) (int64, []op.Piece, string, error) {
|
func (bi *BinaryInfo) Location(entry godwarf.Entry, attr dwarf.Attr, pc uint64, regs op.DwarfRegisters) (int64, []op.Piece, *locationExpr, error) {
|
||||||
instr, descr, err := bi.locationExpr(entry, attr, pc)
|
instr, descr, err := bi.locationExpr(entry, attr, pc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, "", err
|
return 0, nil, nil, err
|
||||||
}
|
}
|
||||||
addr, pieces, err := op.ExecuteStackProgram(regs, instr, bi.Arch.PtrSize())
|
addr, pieces, err := op.ExecuteStackProgram(regs, instr, bi.Arch.PtrSize())
|
||||||
return addr, pieces, descr, err
|
return addr, pieces, descr, err
|
||||||
|
|||||||
@ -266,7 +266,8 @@ func (scope *EvalScope) Locals() ([]*Variable, error) {
|
|||||||
}
|
}
|
||||||
v.Name = name[1:]
|
v.Name = name[1:]
|
||||||
v.Flags |= VariableEscaped
|
v.Flags |= VariableEscaped
|
||||||
v.LocationExpr = locationExpr + " (escaped)"
|
locationExpr.isEscaped = true
|
||||||
|
v.LocationExpr = locationExpr
|
||||||
v.DeclLine = declLine
|
v.DeclLine = declLine
|
||||||
vars[i] = v
|
vars[i] = v
|
||||||
}
|
}
|
||||||
|
|||||||
@ -118,7 +118,7 @@ type Variable struct {
|
|||||||
loaded bool
|
loaded bool
|
||||||
Unreadable error
|
Unreadable error
|
||||||
|
|
||||||
LocationExpr string // location expression
|
LocationExpr *locationExpr // location expression
|
||||||
DeclLine int64 // line number of this variable's declaration
|
DeclLine int64 // line number of this variable's declaration
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,8 +441,6 @@ func newGVariable(thread Thread, gaddr uintptr, deref bool) (*Variable, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
name := ""
|
|
||||||
|
|
||||||
if deref {
|
if deref {
|
||||||
typ = &godwarf.PtrType{
|
typ = &godwarf.PtrType{
|
||||||
CommonType: godwarf.CommonType{
|
CommonType: godwarf.CommonType{
|
||||||
@ -453,11 +451,9 @@ func newGVariable(thread Thread, gaddr uintptr, deref bool) (*Variable, error) {
|
|||||||
},
|
},
|
||||||
Type: typ,
|
Type: typ,
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
name = "runtime.curg"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return newVariableFromThread(thread, name, gaddr, typ), nil
|
return newVariableFromThread(thread, "", gaddr, typ), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defer returns the top-most defer of the goroutine.
|
// Defer returns the top-most defer of the goroutine.
|
||||||
@ -851,6 +847,8 @@ func (v *Variable) parseG() (*G, error) {
|
|||||||
|
|
||||||
f, l, fn := v.bi.PCToLine(uint64(pc))
|
f, l, fn := v.bi.PCToLine(uint64(pc))
|
||||||
|
|
||||||
|
v.Name = "runtime.curg"
|
||||||
|
|
||||||
g := &G{
|
g := &G{
|
||||||
ID: int(id),
|
ID: int(id),
|
||||||
GoPC: uint64(gopc),
|
GoPC: uint64(gopc),
|
||||||
|
|||||||
@ -148,7 +148,7 @@ func ConvertVar(v *proc.Variable) *Variable {
|
|||||||
Flags: VariableFlags(v.Flags),
|
Flags: VariableFlags(v.Flags),
|
||||||
Base: v.Base,
|
Base: v.Base,
|
||||||
|
|
||||||
LocationExpr: v.LocationExpr,
|
LocationExpr: v.LocationExpr.String(),
|
||||||
DeclLine: v.DeclLine,
|
DeclLine: v.DeclLine,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user