Skip to content

Commit fed5496

Browse files
author
Patrick Pichler
committed
Load kernel BTF spec once when creating a new collection
When creating a new collection without specifying the `KernelTypes` in the `ProgramOptions`, the kernel BTF is implicitly loaded. For this the `btf.LoadKernelSpec()` helper is used. Even though the spec is only loaded once, this operation cause a lot of memory churn, as the kernel spec is being copied each time the function get called. This becomes an issue when a collection with lots of programs is loaded in a resource limited environment. This commit initializes an missing `KernelTypes` field with the BTF kernel spec, getting rid of the subsequent calls of `BTF.Copy()`. This greatly reduces the number of allocations/op when running the `BenchmarkNewCollectionManyProgs` benchmark. Here are the results: Previous: BenchmarkNewCollectionManyProgs-4 12 98443414 ns/op 116779863 B/op 403964 allocs/op With optimization: BenchmarkNewCollectionManyProgs-4 184 5807742 ns/op 4134444 B/op 17325 allocs/op Signed-off-by: Patrick Pichler <[email protected]>
1 parent 8b4b96a commit fed5496

File tree

1 file changed

+14
-6
lines changed

1 file changed

+14
-6
lines changed

Diff for: collection.go

+14-6
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,11 @@ func (cs *CollectionSpec) Assign(to interface{}) error {
252252
// Returns an error if any of the fields can't be found, or
253253
// if the same Map or Program is assigned multiple times.
254254
func (cs *CollectionSpec) LoadAndAssign(to interface{}, opts *CollectionOptions) error {
255-
loader, err := newCollectionLoader(cs, opts)
255+
if opts == nil {
256+
opts = &CollectionOptions{}
257+
}
258+
259+
loader, err := newCollectionLoader(cs, *opts)
256260
if err != nil {
257261
return err
258262
}
@@ -351,7 +355,7 @@ func NewCollection(spec *CollectionSpec) (*Collection, error) {
351355
// Omitting Collection.Close() during application shutdown is an error.
352356
// See the package documentation for details around Map and Program lifecycle.
353357
func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (*Collection, error) {
354-
loader, err := newCollectionLoader(spec, &opts)
358+
loader, err := newCollectionLoader(spec, opts)
355359
if err != nil {
356360
return nil, err
357361
}
@@ -405,9 +409,13 @@ type collectionLoader struct {
405409
vars map[string]*Variable
406410
}
407411

408-
func newCollectionLoader(coll *CollectionSpec, opts *CollectionOptions) (*collectionLoader, error) {
409-
if opts == nil {
410-
opts = &CollectionOptions{}
412+
func newCollectionLoader(coll *CollectionSpec, opts CollectionOptions) (*collectionLoader, error) {
413+
if opts.Programs.KernelTypes == nil {
414+
kernelSpec, err := btf.LoadKernelSpec()
415+
if err != nil {
416+
return nil, fmt.Errorf("cannot load kernel spec: %w", err)
417+
}
418+
opts.Programs.KernelTypes = kernelSpec
411419
}
412420

413421
// Check for existing MapSpecs in the CollectionSpec for all provided replacement maps.
@@ -423,7 +431,7 @@ func newCollectionLoader(coll *CollectionSpec, opts *CollectionOptions) (*collec
423431

424432
return &collectionLoader{
425433
coll,
426-
opts,
434+
&opts,
427435
make(map[string]*Map),
428436
make(map[string]*Program),
429437
make(map[string]*Variable),

0 commit comments

Comments
 (0)