Skip to content

Commit

Permalink
perf(otelstorage): write converted label right to column
Browse files Browse the repository at this point in the history
```
cpu: AMD Ryzen 9 5950X 16-Core Processor
                │   old.txt   │              new.txt               │
                │   sec/op    │   sec/op     vs base               │
InserterLogs-32   7.852m ± 1%   7.479m ± 1%  -4.75% (p=0.000 n=15)

                │   old.txt    │               new.txt               │
                │     B/op     │     B/op      vs base               │
InserterLogs-32   1.501Mi ± 0%   1.359Mi ± 0%  -9.44% (p=0.000 n=15)

                │   old.txt   │               new.txt               │
                │  allocs/op  │  allocs/op   vs base                │
InserterLogs-32   33.24k ± 0%   24.63k ± 0%  -25.91% (p=0.000 n=15)
```
  • Loading branch information
tdakkota committed Jul 19, 2024
1 parent 1364027 commit 34b4988
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 39 deletions.
7 changes: 4 additions & 3 deletions internal/chstorage/columns_logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,14 @@ func (c *logAttrMapColumns) ForEach(f func(name, key string)) {
}

func (c *logAttrMapColumns) AddAttrs(attrs otelstorage.Attrs) {
buf := make([]byte, 0, 128)
attrs.AsMap().Range(func(k string, _ pcommon.Value) bool {
c.AddRow(otelstorage.KeyToLabel(k), k)
c.AddRow(otelstorage.AppendKeyToLabel(buf, k), k)
return true
})
}

func (c *logAttrMapColumns) AddRow(name, key string) {
c.name.Append(name)
func (c *logAttrMapColumns) AddRow(name []byte, key string) {
c.name.AppendBytes(name)
c.key.Append(key)
}
48 changes: 41 additions & 7 deletions internal/otelstorage/attrs.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
package otelstorage

import (
"slices"
"strings"

"go.opentelemetry.io/collector/pdata/pcommon"
)

// KeyToLabel converts key to label name.
func KeyToLabel(key string) string {
isDigit := func(r rune) bool {
return r >= '0' && r <= '9'
}
isAlpha := func(r rune) bool {
return (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z')
}

var label strings.Builder
for i, r := range key {
switch {
Expand Down Expand Up @@ -46,6 +40,46 @@ slow:
return label.String()
}

// AppendKeyToLabel converts key to label name and appends it to given buffer.
func AppendKeyToLabel(buf []byte, key string) []byte {
for i, r := range key {
switch {
case isDigit(r):
// Label could not start with digit.
if i == 0 {
buf = slices.Grow(buf, len(key)+1)
buf = append(buf, '_')
goto slow
}
case r >= 0x80 && r == '_' || isAlpha(r):
default:
buf = slices.Grow(buf, len(key))
buf = append(buf, key[:i]...)
key = key[i:]
goto slow
}
}
return append(buf, key...)
slow:
for _, r := range key {
if r == '_' || isDigit(r) || isAlpha(r) {
buf = append(buf, byte(r))
continue
}
// Replace rune with '_'.
buf = append(buf, '_')
}
return buf
}

func isDigit(r rune) bool {
return r >= '0' && r <= '9'
}

func isAlpha(r rune) bool {
return (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z')
}

// Attrs wraps attributes.
type Attrs pcommon.Map

Expand Down
62 changes: 33 additions & 29 deletions internal/otelstorage/attrs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,62 @@ package otelstorage

import (
"fmt"
"strings"
"testing"

"github.com/stretchr/testify/require"
)

func TestKeyToLabel(t *testing.T) {
tests := []struct {
key string
want string
}{
{"", ""},
{"foo", "foo"},
{"f_oo", "f_oo"},
var keyToLabelTests = []struct {
key string
want string
}{
{"", ""},
{"foo", "foo"},
{"f_oo", "f_oo"},

{"0foo", "_0foo"},
{"foo.bar", "foo_bar"},
{"foo/bar", "foo_bar"},
{"receiver/accepted_spans/0", "receiver_accepted_spans_0"},
{"a🐹/b🐹/0", "a__b__0"},
}
for i, tt := range tests {
{"0foo", "_0foo"},
{"foo.bar", "foo_bar"},
{"foo/bar", "foo_bar"},
{"receiver/accepted_spans/0", "receiver_accepted_spans_0"},
{"a🐹/b🐹/0", "a__b__0"},
}

func TestKeyToLabel(t *testing.T) {
for i, tt := range keyToLabelTests {
tt := tt
t.Run(fmt.Sprintf("Test%d", i+1), func(t *testing.T) {
require.Equal(t, tt.want, KeyToLabel(tt.key))
require.Equal(t, tt.want, string(AppendKeyToLabel(nil, tt.key)))
})
}
}

func TestKeyToLabelAllocs(t *testing.T) {
var sink string
for _, tt := range []struct {
key string
allocs float64
}{
{"", 0},
{"foo", 0},
{"foo.bar", 1},
{"receiver/accepted_spans/0", 1},
{"🐹/🐹/0", 1},
{"_" + strings.Repeat("receiver/accepted_spans/0", 25), 1},
} {
got := testing.AllocsPerRun(1000, func() {
for _, tt := range keyToLabelTests {
gotAllocs := testing.AllocsPerRun(1000, func() {
sink = KeyToLabel(tt.key)
})
require.LessOrEqual(t, tt.allocs, got)
require.LessOrEqual(t, gotAllocs, 1.0)
if tt.key != "" && sink == "" {
t.Fail()
}
}
}

func TestAppendKeyToLabelAllocs(t *testing.T) {
buf := make([]byte, 0, 256)
for _, tt := range keyToLabelTests {
gotAllocs := testing.AllocsPerRun(1000, func() {
buf = AppendKeyToLabel(buf, tt.key)
})
require.Zero(t, gotAllocs)
if tt.key != "" && len(buf) == 0 {
t.Fail()
}
}
}

func BenchmarkKeyToLabel(b *testing.B) {
b.ReportAllocs()

Expand Down

0 comments on commit 34b4988

Please sign in to comment.