Prefer binary search over tree lookup for FDEs

FDEs previously were loaded into a red/black tree and searched. This is
significantly more expensive than a binary search over a slice. Not sure
what I was thinking using a red/black tree - this binary search
implementation is significantly more efficient.
This commit is contained in:
Derek Parker
2015-02-04 18:14:08 -06:00
parent 49c0d61515
commit 4d88d9ed8d
4 changed files with 44 additions and 46 deletions

View File

@ -1,10 +1,6 @@
package frame
import (
"fmt"
"github.com/derekparker/rbtree"
)
import "fmt"
// Represents a Common Information Entry in
// the Dwarf .debug_frame section.
@ -23,7 +19,6 @@ func (fde *FrameDescriptionEntry) Cover(addr uint64) bool {
if (addr - fde.begin) < fde.end {
return true
}
return false
}
@ -53,39 +48,42 @@ func (fde *FrameDescriptionEntry) ReturnAddressOffset(pc uint64) int64 {
return frame.cfa.offset + frame.regs[fde.CIE.ReturnAddressRegister].offset
}
type FrameDescriptionEntries struct {
*rbtree.RedBlackTree
type FrameDescriptionEntries []*FrameDescriptionEntry
func NewFrameIndex() FrameDescriptionEntries {
return make(FrameDescriptionEntries, 0, 1000)
}
func NewFrameIndex() *FrameDescriptionEntries {
return &FrameDescriptionEntries{rbtree.New()}
}
func (fdes *FrameDescriptionEntries) FDEForPC(pc uint64) (*FrameDescriptionEntry, error) {
node, ok := fdes.Find(Addr(pc))
if !ok {
return nil, fmt.Errorf("Could not find FDE for %#v", pc)
func (fdes FrameDescriptionEntries) FDEForPC(pc uint64) (*FrameDescriptionEntry, error) {
frame := find(fdes, pc)
if frame == nil {
return nil, fmt.Errorf("could not find FDE for %#v", pc)
}
return node.(*FrameDescriptionEntry), nil
return frame, nil
}
func (frame *FrameDescriptionEntry) Less(item rbtree.Item) bool {
return frame.Begin() < item.(*FrameDescriptionEntry).Begin()
func find(fdes FrameDescriptionEntries, pc uint64) *FrameDescriptionEntry {
if len(fdes) == 0 {
return nil
}
idx := len(fdes) / 2
frame := fdes[idx]
if frame.Cover(pc) {
return frame
}
if frame.Less(pc) {
return find(fdes[:idx], pc)
}
if frame.More(pc) {
return find(fdes[idx:], pc)
}
return nil
}
func (frame *FrameDescriptionEntry) More(item rbtree.Item) bool {
f := item.(*FrameDescriptionEntry)
return frame.End() > f.End()
func (frame *FrameDescriptionEntry) Less(pc uint64) bool {
return frame.Begin() > pc
}
type Addr uint64
func (a Addr) Less(item rbtree.Item) bool {
return uint64(a) < item.(*FrameDescriptionEntry).Begin()
}
func (a Addr) More(item rbtree.Item) bool {
f := item.(*FrameDescriptionEntry)
return uint64(a) > f.End()
func (frame *FrameDescriptionEntry) More(pc uint64) bool {
return frame.End() < pc
}

View File

@ -7,23 +7,23 @@ import (
)
func TestFDEForPC(t *testing.T) {
fde1 := &FrameDescriptionEntry{begin: 100, end: 200}
fde1 := &FrameDescriptionEntry{begin: 0, end: 49}
fde2 := &FrameDescriptionEntry{begin: 50, end: 99}
fde3 := &FrameDescriptionEntry{begin: 0, end: 49}
fde3 := &FrameDescriptionEntry{begin: 100, end: 200}
fde4 := &FrameDescriptionEntry{begin: 201, end: 245}
tree := NewFrameIndex()
tree.Put(fde1)
tree.Put(fde2)
tree.Put(fde3)
tree.Put(fde4)
frames := NewFrameIndex()
frames = append(frames, fde1)
frames = append(frames, fde2)
frames = append(frames, fde3)
frames = append(frames, fde4)
node, ok := tree.Find(Addr(35))
if !ok {
node, err := frames.FDEForPC(35)
if err != nil {
t.Fatal("Could not find FDE")
}
if node != fde3 {
if node != fde1 {
t.Fatal("Got incorrect fde")
}
}

View File

@ -14,7 +14,7 @@ type parsefunc func(*parseContext) parsefunc
type parseContext struct {
Buf *bytes.Buffer
Entries *FrameDescriptionEntries
Entries FrameDescriptionEntries
Common *CommonInformationEntry
Frame *FrameDescriptionEntry
Length uint32
@ -23,7 +23,7 @@ type parseContext struct {
// Parse takes in data (a byte slice) and returns a slice of
// CommonInformationEntry structures. Each CommonInformationEntry
// has a slice of FrameDescriptionEntry structures.
func Parse(data []byte) *FrameDescriptionEntries {
func Parse(data []byte) FrameDescriptionEntries {
var (
buf = bytes.NewBuffer(data)
pctx = &parseContext{Buf: buf, Entries: NewFrameIndex()}
@ -62,7 +62,7 @@ func parseFDE(ctx *parseContext) parsefunc {
// Insert into the tree after setting address range begin
// otherwise compares won't work.
ctx.Entries.Put(ctx.Frame)
ctx.Entries = append(ctx.Entries, ctx.Frame)
// The rest of this entry consists of the instructions
// so we can just grab all of the data from the buffer