Skip to content

Commit 6133b48

Browse files
authored
Merge pull request #342 from bobrik/ivan/decoder-cache
Add decoder cache
2 parents 5af4585 + b209828 commit 6133b48

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

decoder/decoder.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type Decoder interface {
2323
type Set struct {
2424
mu sync.Mutex
2525
decoders map[string]Decoder
26+
cache map[string][]string
2627
}
2728

2829
// NewSet creates a Set with all known decoders
@@ -56,6 +57,7 @@ func NewSet() (*Set, error) {
5657
"syscall": &Syscall{},
5758
"uint": &UInt{},
5859
},
60+
cache: map[string][]string{},
5961
}, nil
6062
}
6163

@@ -87,6 +89,24 @@ func (s *Set) Decode(in []byte, label config.Label) ([]byte, error) {
8789
// DecodeLabels transforms eBPF map key bytes into a list of label values
8890
// according to configuration
8991
func (s *Set) DecodeLabels(in []byte, labels []config.Label) ([]string, error) {
92+
// string(in) must not be a variable to avoid allocation:
93+
// * https://github.com/golang/go/commit/f5f5a8b6209f8
94+
if cached, ok := s.cache[string(in)]; ok {
95+
return cached, nil
96+
}
97+
98+
values, err := s.decodeLabels(in, labels)
99+
if err != nil {
100+
return nil, err
101+
}
102+
103+
s.cache[string(in)] = values
104+
105+
return values, nil
106+
}
107+
108+
// decodeLabels is the inner function of DecodeLabels without any caching
109+
func (s *Set) decodeLabels(in []byte, labels []config.Label) ([]string, error) {
90110
values := make([]string, len(labels))
91111

92112
off := uint(0)

decoder/decoder_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,77 @@ func TestDecodeLabels(t *testing.T) {
151151
}
152152
}
153153

154+
func BenchmarkCache(b *testing.B) {
155+
in := []byte{
156+
0x8, 0xab, 0xce, 0xef,
157+
0xde, 0xad,
158+
0xbe, 0xef,
159+
0x8, 0xab, 0xce, 0xef, 0x8, 0xab, 0xce, 0xef,
160+
}
161+
162+
labels := []config.Label{
163+
{
164+
Name: "number1",
165+
Size: 4,
166+
Decoders: []config.Decoder{
167+
{
168+
Name: "uint",
169+
},
170+
},
171+
},
172+
{
173+
Name: "number2",
174+
Size: 2,
175+
Decoders: []config.Decoder{
176+
{
177+
Name: "uint",
178+
},
179+
},
180+
},
181+
{
182+
Name: "number3",
183+
Size: 2,
184+
Decoders: []config.Decoder{
185+
{
186+
Name: "uint",
187+
},
188+
},
189+
},
190+
{
191+
Name: "number4",
192+
Size: 8,
193+
Decoders: []config.Decoder{
194+
{
195+
Name: "uint",
196+
},
197+
},
198+
},
199+
}
200+
201+
s, err := NewSet()
202+
if err != nil {
203+
b.Fatal(err)
204+
}
205+
206+
b.Run("direct", func(b *testing.B) {
207+
for i := 0; i < b.N; i++ {
208+
_, err := s.decodeLabels(in, labels)
209+
if err != nil {
210+
b.Fatal(err)
211+
}
212+
}
213+
})
214+
215+
b.Run("cached", func(b *testing.B) {
216+
for i := 0; i < b.N; i++ {
217+
_, err := s.DecodeLabels(in, labels)
218+
if err != nil {
219+
b.Fatal(err)
220+
}
221+
}
222+
})
223+
}
224+
154225
func zeroPaddedString(in string, size int) []byte {
155226
if len(in) > size {
156227
panic(fmt.Sprintf("string %q is longer than requested size %d", in, size))

0 commit comments

Comments
 (0)