Skip to content

Commit

Permalink
use binary search to optimize performance
Browse files Browse the repository at this point in the history
Signed-off-by: Changsheng Huang <1984737645@qq.com>
  • Loading branch information
Lan-ce-lot authored and jrfastab committed Apr 7, 2023
1 parent 846910a commit 3db9b2a
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 8 deletions.
23 changes: 15 additions & 8 deletions pkg/ksyms/ksyms.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,18 +146,25 @@ func (k *Ksyms) GetFnOffset(addr uint64) (*FnOffset, error) {

// GetFnOffset -- retruns the FnOffset for a given address
func (k *Ksyms) getFnOffset(addr uint64) (*FnOffset, error) {

// TODO: we can do binary search here if we care about performance
i := 0
for k.table[i].addr < addr {
i++
// address is before first symbol
if k.table[0].addr > addr {
return nil, fmt.Errorf("address %d is before first symbol %s@%d", addr, k.table[0].name, k.table[0].addr)
}

if i == 0 {
return nil, fmt.Errorf("address %d is before first sumbol %s@%d", addr, k.table[0].name, k.table[0].addr)
// binary search
l, r := 0, len(k.table)-1

for l < r {
// prevents overflow
m := l + ((r - l + 1) >> 1)
if k.table[m].addr < addr {
l = m
} else {
r = m - 1
}
}

sym := k.table[i-1]
sym := k.table[l]
if !sym.isFunction() {
return nil, fmt.Errorf("Unable to find function for addr 0x%x", addr)
}
Expand Down
88 changes: 88 additions & 0 deletions pkg/ksyms/ksyms_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Tetragon
package ksyms

import (
"testing"
)

func TestGetFnOffset(t *testing.T) {
ksyms := &Ksyms{
table: []ksym{
{addr: 0x100, name: "addr1", ty: "t"},
{addr: 0x200, name: "addr2", ty: "t"},
{addr: 0x300, name: "addr3", ty: "w"},
{addr: 0x400, name: "addr4", ty: "t"},
{addr: 0x500, name: "addr5", ty: "t"},
{addr: 0x600, name: "addr6", ty: "t"},
{addr: 0x700, name: "addr7", ty: "t"},
{addr: 0x800, name: "addr8", ty: "t"},
{addr: 0x900, name: "addr9", ty: "t"},
{addr: 0xa00, name: "addr10", ty: "t"},
},
}

tests := []struct {
name string
addr uint64
wantErr bool
want FnOffset
}{
{
name: "valid first address",
addr: 0x100,
want: FnOffset{SymName: "addr1", Offset: 0},
},
{
name: "addr 0x110",
addr: 0x110,
want: FnOffset{SymName: "addr1", Offset: 0x10},
},
{
name: "addr 0x410",
addr: 0x410,
want: FnOffset{SymName: "addr4", Offset: 0x10},
},
{
name: "addr 0x50f",
addr: 0x50f,
want: FnOffset{SymName: "addr5", Offset: 0xf},
},
{
name: "addr 0x550",
addr: 0x550,
want: FnOffset{SymName: "addr5", Offset: 0x050},
},
{
name: "addr 0x900",
addr: 0x900,
want: FnOffset{SymName: "addr8", Offset: 0x100},
},
{
name: "address is before first symbol",
addr: 0x090,
wantErr: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ksyms.getFnOffset(tt.addr)
if (err != nil) != tt.wantErr {
t.Fatalf("Unexpected error: %v", err)
}
if tt.wantErr {
if err == nil {
t.Fatalf("expected error: %v", err)
}
return
}
if got.SymName != tt.want.SymName {
t.Fatalf("Symbol name (%v) did not match expected value (%v) for %v", got.SymName, tt.want.SymName, tt.name)
}
if got.Offset != tt.want.Offset {
t.Fatalf("Symbol offset (%x) did not match expected value (%x) for %v", got.Offset, tt.want.Offset, tt.name)
}
})
}
}

0 comments on commit 3db9b2a

Please sign in to comment.