From 3d3d72edac5ff0ffb1a21eac50866cb65c2fba73 Mon Sep 17 00:00:00 2001 From: Lorenz Bauer Date: Fri, 3 Nov 2023 15:32:04 +0000 Subject: [PATCH 1/2] btf: remove unused stringTable.Marshal The library now uses stringTableBuilder instead. Signed-off-by: Lorenz Bauer --- btf/strings.go | 14 -------------- btf/strings_test.go | 9 --------- 2 files changed, 23 deletions(-) diff --git a/btf/strings.go b/btf/strings.go index 0ddf1d24f..7c375b9ee 100644 --- a/btf/strings.go +++ b/btf/strings.go @@ -92,20 +92,6 @@ func (st *stringTable) lookup(offset uint32) (string, error) { return st.strings[i], nil } -func (st *stringTable) Marshal(w io.Writer) error { - for _, str := range st.strings { - _, err := io.WriteString(w, str) - if err != nil { - return err - } - _, err = w.Write([]byte{0}) - if err != nil { - return err - } - } - return nil -} - // Num returns the number of strings in the table. func (st *stringTable) Num() int { return len(st.strings) diff --git a/btf/strings_test.go b/btf/strings_test.go index 6f2bc4d84..179be666b 100644 --- a/btf/strings_test.go +++ b/btf/strings_test.go @@ -17,15 +17,6 @@ func TestStringTable(t *testing.T) { t.Fatal(err) } - var buf bytes.Buffer - if err := st.Marshal(&buf); err != nil { - t.Fatal("Can't marshal string table:", err) - } - - if !bytes.Equal([]byte(in), buf.Bytes()) { - t.Error("String table doesn't match input") - } - // Parse string table of split BTF split, err := readStringTable(strings.NewReader(splitIn), st) if err != nil { From c93440617ee409536708077a63977cfb7e38bd6b Mon Sep 17 00:00:00 2001 From: Lorenz Bauer Date: Fri, 3 Nov 2023 16:10:53 +0000 Subject: [PATCH 2/2] btf: add fast path for string table offset 0 lookup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It turns out that the vast majority of string table lookups are for offset zero, which is always defined to be the empty string. This gives a good 14% speedup on my machine: goos: linux goarch: amd64 pkg: github.com/cilium/ebpf/btf cpu: 12th Gen Intel(R) Core(TM) i7-1260P │ base.txt │ zero.txt │ │ sec/op │ sec/op vs base │ ParseVmlinux-16 50.14m ± 7% 43.07m ± 3% -14.10% (p=0.002 n=6) │ base.txt │ zero.txt │ │ B/op │ B/op vs base │ ParseVmlinux-16 31.45Mi ± 0% 31.45Mi ± 0% ~ (p=0.485 n=6) │ base.txt │ zero.txt │ │ allocs/op │ allocs/op vs base │ ParseVmlinux-16 534.1k ± 0% 534.1k ± 0% ~ (p=0.461 n=6) Signed-off-by: Lorenz Bauer --- btf/strings.go | 4 ++++ btf/strings_test.go | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/btf/strings.go b/btf/strings.go index 7c375b9ee..f8ae08cfb 100644 --- a/btf/strings.go +++ b/btf/strings.go @@ -84,6 +84,10 @@ func (st *stringTable) Lookup(offset uint32) (string, error) { } func (st *stringTable) lookup(offset uint32) (string, error) { + if offset == 0 && st.base == nil { + return "", nil + } + i, found := slices.BinarySearch(st.offsets, offset) if !found { return "", fmt.Errorf("offset %d isn't start of a string", offset) diff --git a/btf/strings_test.go b/btf/strings_test.go index 179be666b..d34726d49 100644 --- a/btf/strings_test.go +++ b/btf/strings_test.go @@ -88,6 +88,21 @@ func TestStringTableBuilder(t *testing.T) { qt.Assert(t, err, qt.IsNil, qt.Commentf("Can't parse string table")) } +func BenchmarkStringTableZeroLookup(b *testing.B) { + strings := vmlinuxTestdataSpec(b).strings + + b.ResetTimer() + for i := 0; i < b.N; i++ { + s, err := strings.Lookup(0) + if err != nil { + b.Fatal(err) + } + if s != "" { + b.Fatal("0 is not the empty string") + } + } +} + func newStringTable(strings ...string) *stringTable { offsets := make([]uint32, len(strings))