Skip to content

Commit 1a65b78

Browse files
dylandreimerinklmb
authored andcommitted
btf: Replace binary.Read with manual parsing in readAndInflateTypes
During profiling `binary.Read` uses up a significant amount of CPU time. This seems to be due to it using reflection to calculate the amount of bytes to read at runtime and not caching these results. By doing manual `io.ReadFull` calls, pre-calculating struct sizes and reusing types and buffers where possible, we can reduce the CPU time spent in `readAndInflateTypes` by almost 25%. ``` goos: linux goarch: amd64 pkg: github.com/cilium/ebpf/btf cpu: 11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz │ before.txt │ after.txt │ │ sec/op │ sec/op vs base │ ParseVmlinux-16 46.08m ± 1% 34.59m ± 2% -24.93% (n=100) │ before.txt │ after.txt │ │ B/op │ B/op vs base │ ParseVmlinux-16 26.65Mi ± 0% 23.49Mi ± 0% -11.87% (n=100) │ before.txt │ after.txt │ │ allocs/op │ allocs/op vs base │ ParseVmlinux-16 467.5k ± 0% 267.7k ± 0% -42.73% (n=100) ``` Signed-off-by: Dylan Reimerink <[email protected]>
1 parent 7146ce3 commit 1a65b78

File tree

2 files changed

+221
-41
lines changed

2 files changed

+221
-41
lines changed

btf/btf_types.go

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,19 @@ type btfType struct {
153153
SizeType uint32
154154
}
155155

156+
var btfTypeSize = int(unsafe.Sizeof(btfType{}))
157+
158+
func unmarshalBtfType(bt *btfType, b []byte, bo binary.ByteOrder) (int, error) {
159+
if len(b) < btfTypeSize {
160+
return 0, fmt.Errorf("not enough bytes to unmarshal btfType")
161+
}
162+
163+
bt.NameOff = bo.Uint32(b[0:])
164+
bt.Info = bo.Uint32(b[4:])
165+
bt.SizeType = bo.Uint32(b[8:])
166+
return btfTypeSize, nil
167+
}
168+
156169
func mask(len uint32) uint32 {
157170
return (1 << len) - 1
158171
}
@@ -300,6 +313,17 @@ const (
300313
btfIntBitsShift = 0
301314
)
302315

316+
var btfIntLen = int(unsafe.Sizeof(btfInt{}))
317+
318+
func unmarshalBtfInt(bi *btfInt, b []byte, bo binary.ByteOrder) (int, error) {
319+
if len(b) < btfIntLen {
320+
return 0, fmt.Errorf("not enough bytes to unmarshal btfInt")
321+
}
322+
323+
bi.Raw = bo.Uint32(b[0:])
324+
return btfIntLen, nil
325+
}
326+
303327
func (bi btfInt) Encoding() IntEncoding {
304328
return IntEncoding(readBits(bi.Raw, btfIntEncodingLen, btfIntEncodingShift))
305329
}
@@ -330,38 +354,166 @@ type btfArray struct {
330354
Nelems uint32
331355
}
332356

357+
var btfArrayLen = int(unsafe.Sizeof(btfArray{}))
358+
359+
func unmarshalBtfArray(ba *btfArray, b []byte, bo binary.ByteOrder) (int, error) {
360+
if len(b) < btfArrayLen {
361+
return 0, fmt.Errorf("not enough bytes to unmarshal btfArray")
362+
}
363+
364+
ba.Type = TypeID(bo.Uint32(b[0:]))
365+
ba.IndexType = TypeID(bo.Uint32(b[4:]))
366+
ba.Nelems = bo.Uint32(b[8:])
367+
return btfArrayLen, nil
368+
}
369+
333370
type btfMember struct {
334371
NameOff uint32
335372
Type TypeID
336373
Offset uint32
337374
}
338375

376+
var btfMemberLen = int(unsafe.Sizeof(btfMember{}))
377+
378+
func unmarshalBtfMembers(members []btfMember, b []byte, bo binary.ByteOrder) (int, error) {
379+
off := 0
380+
for i := range members {
381+
if off+btfMemberLen > len(b) {
382+
return 0, fmt.Errorf("not enough bytes to unmarshal btfMember %d", i)
383+
}
384+
385+
members[i].NameOff = bo.Uint32(b[off+0:])
386+
members[i].Type = TypeID(bo.Uint32(b[off+4:]))
387+
members[i].Offset = bo.Uint32(b[off+8:])
388+
389+
off += btfMemberLen
390+
}
391+
392+
return off, nil
393+
}
394+
339395
type btfVarSecinfo struct {
340396
Type TypeID
341397
Offset uint32
342398
Size uint32
343399
}
344400

401+
var btfVarSecinfoLen = int(unsafe.Sizeof(btfVarSecinfo{}))
402+
403+
func unmarshalBtfVarSecInfos(secinfos []btfVarSecinfo, b []byte, bo binary.ByteOrder) (int, error) {
404+
off := 0
405+
for i := range secinfos {
406+
if off+btfVarSecinfoLen > len(b) {
407+
return 0, fmt.Errorf("not enough bytes to unmarshal btfVarSecinfo %d", i)
408+
}
409+
410+
secinfos[i].Type = TypeID(bo.Uint32(b[off+0:]))
411+
secinfos[i].Offset = bo.Uint32(b[off+4:])
412+
secinfos[i].Size = bo.Uint32(b[off+8:])
413+
414+
off += btfVarSecinfoLen
415+
}
416+
417+
return off, nil
418+
}
419+
345420
type btfVariable struct {
346421
Linkage uint32
347422
}
348423

424+
var btfVariableLen = int(unsafe.Sizeof(btfVariable{}))
425+
426+
func unmarshalBtfVariable(bv *btfVariable, b []byte, bo binary.ByteOrder) (int, error) {
427+
if len(b) < btfVariableLen {
428+
return 0, fmt.Errorf("not enough bytes to unmarshal btfVariable")
429+
}
430+
431+
bv.Linkage = bo.Uint32(b[0:])
432+
return btfVariableLen, nil
433+
}
434+
349435
type btfEnum struct {
350436
NameOff uint32
351437
Val uint32
352438
}
353439

440+
var btfEnumLen = int(unsafe.Sizeof(btfEnum{}))
441+
442+
func unmarshalBtfEnums(enums []btfEnum, b []byte, bo binary.ByteOrder) (int, error) {
443+
off := 0
444+
for i := range enums {
445+
if off+btfEnumLen > len(b) {
446+
return 0, fmt.Errorf("not enough bytes to unmarshal btfEnum %d", i)
447+
}
448+
449+
enums[i].NameOff = bo.Uint32(b[off+0:])
450+
enums[i].Val = bo.Uint32(b[off+4:])
451+
452+
off += btfEnumLen
453+
}
454+
455+
return off, nil
456+
}
457+
354458
type btfEnum64 struct {
355459
NameOff uint32
356460
ValLo32 uint32
357461
ValHi32 uint32
358462
}
359463

464+
var btfEnum64Len = int(unsafe.Sizeof(btfEnum64{}))
465+
466+
func unmarshalBtfEnums64(enums []btfEnum64, b []byte, bo binary.ByteOrder) (int, error) {
467+
off := 0
468+
for i := range enums {
469+
if off+btfEnum64Len > len(b) {
470+
return 0, fmt.Errorf("not enough bytes to unmarshal btfEnum64 %d", i)
471+
}
472+
473+
enums[i].NameOff = bo.Uint32(b[off+0:])
474+
enums[i].ValLo32 = bo.Uint32(b[off+4:])
475+
enums[i].ValHi32 = bo.Uint32(b[off+8:])
476+
477+
off += btfEnum64Len
478+
}
479+
480+
return off, nil
481+
}
482+
360483
type btfParam struct {
361484
NameOff uint32
362485
Type TypeID
363486
}
364487

488+
var btfParamLen = int(unsafe.Sizeof(btfParam{}))
489+
490+
func unmarshalBtfParams(params []btfParam, b []byte, bo binary.ByteOrder) (int, error) {
491+
off := 0
492+
for i := range params {
493+
if off+btfParamLen > len(b) {
494+
return 0, fmt.Errorf("not enough bytes to unmarshal btfParam %d", i)
495+
}
496+
497+
params[i].NameOff = bo.Uint32(b[off+0:])
498+
params[i].Type = TypeID(bo.Uint32(b[off+4:]))
499+
500+
off += btfParamLen
501+
}
502+
503+
return off, nil
504+
}
505+
365506
type btfDeclTag struct {
366507
ComponentIdx uint32
367508
}
509+
510+
var btfDeclTagLen = int(unsafe.Sizeof(btfDeclTag{}))
511+
512+
func unmarshalBtfDeclTag(bdt *btfDeclTag, b []byte, bo binary.ByteOrder) (int, error) {
513+
if len(b) < btfDeclTagLen {
514+
return 0, fmt.Errorf("not enough bytes to unmarshal btfDeclTag")
515+
}
516+
517+
bdt.ComponentIdx = bo.Uint32(b[0:])
518+
return btfDeclTagLen, nil
519+
}

0 commit comments

Comments
 (0)