Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

use binary search to optimize performance #820

Merged
merged 1 commit into from
Apr 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}
})
}
}