Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

prep work for BTF marshaling #791

Merged
merged 5 commits into from Sep 20, 2022
Merged

prep work for BTF marshaling #791

merged 5 commits into from Sep 20, 2022

Conversation

lmb
Copy link
Collaborator

@lmb lmb commented Sep 9, 2022

This is the first of three PRs to add BTF marshaling to the library, and does some groundwork. The second PR will contain the actual marshaling code, while the third PR has some more memory optimizations.

For the curious, the whole shebang is on my btf-encoder branch.

internal: move Deque

Move Deque from btf into internal and export methods. No other code changes.

btf: make typeDeque generic

Make typeDeque a generic container type so that we can re-use it
for postorderTraversal.

btf: avoid heap allocations when walking types

Type.walk() forces the typeDeque argument to always escape, since the escape analyzer has
to be conservative when dealing with interfaces. We can apply two tricks that reduce
allocations.

First, Type.walk() is replaced with

    children() []*Type

This removes the typeDeque parameter, and for types that don't have any children (like Void) we
never incur an allocation at all. For types that do have children we've unfortunately swapped
heap allocating typeDeque with allocating the []*Type slice instead.

Which brings us to the second trick: by using a type switch we allow the compiler to inline the
children() function for the most important Types, which in turn enables allocating most []*Type on
the stack instead of on the heap.

One notable exception is FuncProto, which allocates the returned slice as such:

    types := make([]*Type, len(fp.Params)+1)

It seems like this trips up escape analysis for some reason as the slice is heap allocated.

    name                                      old time/op    new time/op    delta
    Walk/Void-4                                 22.6ns ± 2%     2.8ns ± 2%   -87.40%  (p=0.029 n=4+4)
    Walk/Int[unsigned_size=0]-4                 22.7ns ± 1%     3.2ns ± 1%   -86.09%  (p=0.029 n=4+4)
    Walk/Pointer[target=<nil>]-4                61.3ns ± 1%    38.5ns ± 1%   -37.26%  (p=0.029 n=4+4)
    Walk/Array[index=<nil>_type=<nil>_n=0]-4    63.8ns ± 1%    42.2ns ± 0%   -33.91%  (p=0.029 n=4+4)
    Walk/Struct[fields=2]-4                     64.9ns ± 1%    59.5ns ± 0%    -8.29%  (p=0.029 n=4+4)
    Walk/Union[fields=2]-4                      66.6ns ± 3%    59.3ns ± 0%   -10.84%  (p=0.029 n=4+4)
    Walk/Enum[size=0_values=0]-4                22.5ns ± 4%     2.9ns ± 2%   -87.22%  (p=0.029 n=4+4)
    Walk/Fwd[struct]-4                          22.2ns ± 1%     2.8ns ± 1%   -87.23%  (p=0.029 n=4+4)
    Walk/Typedef[<nil>]-4                       60.8ns ± 1%    38.7ns ± 1%   -36.42%  (p=0.029 n=4+4)
    Walk/Volatile[<nil>]-4                      62.9ns ± 3%    38.4ns ± 2%   -38.89%  (p=0.029 n=4+4)
    Walk/Const[<nil>]-4                         61.9ns ± 1%    39.8ns ± 3%   -35.78%  (p=0.029 n=4+4)
    Walk/Restrict[<nil>]-4                      64.2ns ± 1%    39.2ns ± 1%   -38.91%  (p=0.029 n=4+4)
    Walk/Func[static_proto=<nil>]-4             63.3ns ± 4%    39.5ns ± 2%   -37.57%  (p=0.029 n=4+4)
    Walk/FuncProto[args=2_return=<nil>]-4       67.8ns ± 5%    77.3ns ± 2%   +14.03%  (p=0.029 n=4+4)
    Walk/Var[static]-4                          63.2ns ± 1%    38.5ns ± 0%   -39.03%  (p=0.029 n=4+4)
    Walk/Datasec-4                              67.5ns ± 2%    58.5ns ± 1%   -13.31%  (p=0.029 n=4+4)

    name                                      old alloc/op   new alloc/op   delta
    Walk/Void-4                                  48.0B ± 0%      0.0B       -100.00%  (p=0.029 n=4+4)
    Walk/Int[unsigned_size=0]-4                  48.0B ± 0%      0.0B       -100.00%  (p=0.029 n=4+4)
    Walk/Pointer[target=<nil>]-4                  112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Array[index=<nil>_type=<nil>_n=0]-4      112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Struct[fields=2]-4                       112B ± 0%       80B ± 0%   -28.57%  (p=0.029 n=4+4)
    Walk/Union[fields=2]-4                        112B ± 0%       80B ± 0%   -28.57%  (p=0.029 n=4+4)
    Walk/Enum[size=0_values=0]-4                 48.0B ± 0%      0.0B       -100.00%  (p=0.029 n=4+4)
    Walk/Fwd[struct]-4                           48.0B ± 0%      0.0B       -100.00%  (p=0.029 n=4+4)
    Walk/Typedef[<nil>]-4                         112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Volatile[<nil>]-4                        112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Const[<nil>]-4                           112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Restrict[<nil>]-4                        112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Func[static_proto=<nil>]-4               112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/FuncProto[args=2_return=<nil>]-4         112B ± 0%       88B ± 0%   -21.43%  (p=0.029 n=4+4)
    Walk/Var[static]-4                            112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Datasec-4                                112B ± 0%       80B ± 0%   -28.57%  (p=0.029 n=4+4)

    name                                      old allocs/op  new allocs/op  delta
    Walk/Void-4                                   1.00 ± 0%      0.00       -100.00%  (p=0.029 n=4+4)
    Walk/Int[unsigned_size=0]-4                   1.00 ± 0%      0.00       -100.00%  (p=0.029 n=4+4)
    Walk/Pointer[target=<nil>]-4                  2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Array[index=<nil>_type=<nil>_n=0]-4      2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Struct[fields=2]-4                       2.00 ± 0%      2.00 ± 0%      ~     (all equal)
    Walk/Union[fields=2]-4                        2.00 ± 0%      2.00 ± 0%      ~     (all equal)
    Walk/Enum[size=0_values=0]-4                  1.00 ± 0%      0.00       -100.00%  (p=0.029 n=4+4)
    Walk/Fwd[struct]-4                            1.00 ± 0%      0.00       -100.00%  (p=0.029 n=4+4)
    Walk/Typedef[<nil>]-4                         2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Volatile[<nil>]-4                        2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Const[<nil>]-4                           2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Restrict[<nil>]-4                        2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Func[static_proto=<nil>]-4               2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/FuncProto[args=2_return=<nil>]-4         2.00 ± 0%      2.00 ± 0%      ~     (all equal)
    Walk/Var[static]-4                            2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Datasec-4                                2.00 ± 0%      2.00 ± 0%      ~     (all equal)

btf: add benchmark for Type.Walk

Benchmark the cost of adding a type and its children to a typeDeque.

    name                                      time/op
    Walk/Void-4                               22.8ns ± 3%
    Walk/Int[unsigned_size=0]-4               22.3ns ± 1%
    Walk/Pointer[target=<nil>]-4              61.3ns ± 0%
    Walk/Array[index=<nil>_type=<nil>_n=0]-4  62.4ns ± 0%
    Walk/Struct[fields=2]-4                   64.2ns ± 0%
    Walk/Union[fields=2]-4                    64.6ns ± 0%
    Walk/Enum[size=0_values=0]-4              22.1ns ± 0%
    Walk/Fwd[struct]-4                        22.1ns ± 0%
    Walk/Typedef[<nil>]-4                     61.2ns ± 0%
    Walk/Volatile[<nil>]-4                    61.2ns ± 0%
    Walk/Const[<nil>]-4                       61.2ns ± 0%
    Walk/Restrict[<nil>]-4                    61.2ns ± 0%
    Walk/Func[static_proto=<nil>]-4           61.6ns ± 0%
    Walk/FuncProto[args=2_return=<nil>]-4     66.1ns ± 0%
    Walk/Var[static]-4                        61.5ns ± 1%
    Walk/Datasec-4                            64.4ns ± 0%

    name                                      alloc/op
    Walk/Void-4                                48.0B ± 0%
    Walk/Int[unsigned_size=0]-4                48.0B ± 0%
    Walk/Pointer[target=<nil>]-4                112B ± 0%
    Walk/Array[index=<nil>_type=<nil>_n=0]-4    112B ± 0%
    Walk/Struct[fields=2]-4                     112B ± 0%
    Walk/Union[fields=2]-4                      112B ± 0%
    Walk/Enum[size=0_values=0]-4               48.0B ± 0%
    Walk/Fwd[struct]-4                         48.0B ± 0%
    Walk/Typedef[<nil>]-4                       112B ± 0%
    Walk/Volatile[<nil>]-4                      112B ± 0%
    Walk/Const[<nil>]-4                         112B ± 0%
    Walk/Restrict[<nil>]-4                      112B ± 0%
    Walk/Func[static_proto=<nil>]-4             112B ± 0%
    Walk/FuncProto[args=2_return=<nil>]-4       112B ± 0%
    Walk/Var[static]-4                          112B ± 0%
    Walk/Datasec-4                              112B ± 0%

    name                                      allocs/op
    Walk/Void-4                                 1.00 ± 0%
    Walk/Int[unsigned_size=0]-4                 1.00 ± 0%
    Walk/Pointer[target=<nil>]-4                2.00 ± 0%
    Walk/Array[index=<nil>_type=<nil>_n=0]-4    2.00 ± 0%
    Walk/Struct[fields=2]-4                     2.00 ± 0%
    Walk/Union[fields=2]-4                      2.00 ± 0%
    Walk/Enum[size=0_values=0]-4                1.00 ± 0%
    Walk/Fwd[struct]-4                          1.00 ± 0%
    Walk/Typedef[<nil>]-4                       2.00 ± 0%
    Walk/Volatile[<nil>]-4                      2.00 ± 0%
    Walk/Const[<nil>]-4                         2.00 ± 0%
    Walk/Restrict[<nil>]-4                      2.00 ± 0%
    Walk/Func[static_proto=<nil>]-4             2.00 ± 0%
    Walk/FuncProto[args=2_return=<nil>]-4       2.00 ± 0%
    Walk/Var[static]-4                          2.00 ± 0%
    Walk/Datasec-4                              2.00 ± 0%

btf: drop local btf.Spec argument to CORERelocate

CORERelocate currently takes ProgramSpec.BTF as an argument, since a CO-RE relocation
may ask for the local type ID. This is problematic, since we want to get rid of ProgramSpec.BTF.

Instead, cache the type ID when constructing the CORERelocation itself.

@lmb lmb requested a review from ti-mo September 9, 2022 17:59
CORERelocate currently takes ProgramSpec.BTF as an argument, since a CO-RE relocation
may ask for the local type ID. This is problematic, since we want to get rid of ProgramSpec.BTF.

Instead, cache the type ID when constructing the CORERelocation itself.
Benchmark the cost of adding a type and its children to a typeDeque.

    name                                      time/op
    Walk/Void-4                               22.8ns ± 3%
    Walk/Int[unsigned_size=0]-4               22.3ns ± 1%
    Walk/Pointer[target=<nil>]-4              61.3ns ± 0%
    Walk/Array[index=<nil>_type=<nil>_n=0]-4  62.4ns ± 0%
    Walk/Struct[fields=2]-4                   64.2ns ± 0%
    Walk/Union[fields=2]-4                    64.6ns ± 0%
    Walk/Enum[size=0_values=0]-4              22.1ns ± 0%
    Walk/Fwd[struct]-4                        22.1ns ± 0%
    Walk/Typedef[<nil>]-4                     61.2ns ± 0%
    Walk/Volatile[<nil>]-4                    61.2ns ± 0%
    Walk/Const[<nil>]-4                       61.2ns ± 0%
    Walk/Restrict[<nil>]-4                    61.2ns ± 0%
    Walk/Func[static_proto=<nil>]-4           61.6ns ± 0%
    Walk/FuncProto[args=2_return=<nil>]-4     66.1ns ± 0%
    Walk/Var[static]-4                        61.5ns ± 1%
    Walk/Datasec-4                            64.4ns ± 0%

    name                                      alloc/op
    Walk/Void-4                                48.0B ± 0%
    Walk/Int[unsigned_size=0]-4                48.0B ± 0%
    Walk/Pointer[target=<nil>]-4                112B ± 0%
    Walk/Array[index=<nil>_type=<nil>_n=0]-4    112B ± 0%
    Walk/Struct[fields=2]-4                     112B ± 0%
    Walk/Union[fields=2]-4                      112B ± 0%
    Walk/Enum[size=0_values=0]-4               48.0B ± 0%
    Walk/Fwd[struct]-4                         48.0B ± 0%
    Walk/Typedef[<nil>]-4                       112B ± 0%
    Walk/Volatile[<nil>]-4                      112B ± 0%
    Walk/Const[<nil>]-4                         112B ± 0%
    Walk/Restrict[<nil>]-4                      112B ± 0%
    Walk/Func[static_proto=<nil>]-4             112B ± 0%
    Walk/FuncProto[args=2_return=<nil>]-4       112B ± 0%
    Walk/Var[static]-4                          112B ± 0%
    Walk/Datasec-4                              112B ± 0%

    name                                      allocs/op
    Walk/Void-4                                 1.00 ± 0%
    Walk/Int[unsigned_size=0]-4                 1.00 ± 0%
    Walk/Pointer[target=<nil>]-4                2.00 ± 0%
    Walk/Array[index=<nil>_type=<nil>_n=0]-4    2.00 ± 0%
    Walk/Struct[fields=2]-4                     2.00 ± 0%
    Walk/Union[fields=2]-4                      2.00 ± 0%
    Walk/Enum[size=0_values=0]-4                1.00 ± 0%
    Walk/Fwd[struct]-4                          1.00 ± 0%
    Walk/Typedef[<nil>]-4                       2.00 ± 0%
    Walk/Volatile[<nil>]-4                      2.00 ± 0%
    Walk/Const[<nil>]-4                         2.00 ± 0%
    Walk/Restrict[<nil>]-4                      2.00 ± 0%
    Walk/Func[static_proto=<nil>]-4             2.00 ± 0%
    Walk/FuncProto[args=2_return=<nil>]-4       2.00 ± 0%
    Walk/Var[static]-4                          2.00 ± 0%
    Walk/Datasec-4                              2.00 ± 0%
Type.walk() forces the typeDeque argument to always escape, since the escape analyzer has
to be conservative when dealing with interfaces. Replace this with an optimizer friendly
walkType that allows avoiding allocations.

The downside is that it's now possible to implement a Type without updating walkType, which
will obviously blow up. Fortunately we don't do this too often, so hopefully the burden isn't
too high.

    name                                      old time/op    new time/op    delta
    Walk/Void-4                                 22.4ns ± 1%     2.9ns ± 1%   -87.13%  (p=0.029 n=4+4)
    Walk/Int[unsigned_size=0]-4                 22.4ns ± 0%     2.8ns ± 2%   -87.31%  (p=0.029 n=4+4)
    Walk/Pointer[target=<nil>]-4                61.4ns ± 1%    37.1ns ± 1%   -39.59%  (p=0.029 n=4+4)
    Walk/Array[index=<nil>_type=<nil>_n=0]-4    63.0ns ± 0%    39.3ns ± 2%   -37.50%  (p=0.029 n=4+4)
    Walk/Struct[fields=2]-4                     64.8ns ± 1%    40.9ns ± 1%   -36.96%  (p=0.029 n=4+4)
    Walk/Union[fields=2]-4                      64.9ns ± 1%    40.9ns ± 2%   -36.92%  (p=0.029 n=4+4)
    Walk/Enum[size=0_values=0]-4                22.4ns ± 1%     2.8ns ± 2%   -87.45%  (p=0.029 n=4+4)
    Walk/Fwd[struct]-4                          22.3ns ± 1%     2.8ns ± 2%   -87.43%  (p=0.029 n=4+4)
    Walk/Typedef[<nil>]-4                       61.7ns ± 1%    36.5ns ± 2%   -40.83%  (p=0.029 n=4+4)
    Walk/Volatile[<nil>]-4                      61.5ns ± 1%    36.4ns ± 0%   -40.82%  (p=0.029 n=4+4)
    Walk/Const[<nil>]-4                         61.6ns ± 0%    36.8ns ± 1%   -40.26%  (p=0.029 n=4+4)
    Walk/Restrict[<nil>]-4                      61.2ns ± 0%    37.1ns ± 2%   -39.35%  (p=0.029 n=4+4)
    Walk/Func[static_proto=<nil>]-4             61.7ns ± 1%    36.8ns ± 3%   -40.32%  (p=0.029 n=4+4)
    Walk/FuncProto[args=2_return=<nil>]-4       66.8ns ± 1%    43.1ns ± 1%   -35.48%  (p=0.029 n=4+4)
    Walk/Var[static]-4                          61.9ns ± 1%    36.5ns ± 0%   -40.96%  (p=0.029 n=4+4)
    Walk/Datasec-4                              65.5ns ± 5%    40.3ns ± 0%   -38.57%  (p=0.029 n=4+4)

    name                                      old alloc/op   new alloc/op   delta
    Walk/Void-4                                  48.0B ± 0%      0.0B       -100.00%  (p=0.029 n=4+4)
    Walk/Int[unsigned_size=0]-4                  48.0B ± 0%      0.0B       -100.00%  (p=0.029 n=4+4)
    Walk/Pointer[target=<nil>]-4                  112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Array[index=<nil>_type=<nil>_n=0]-4      112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Struct[fields=2]-4                       112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Union[fields=2]-4                        112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Enum[size=0_values=0]-4                 48.0B ± 0%      0.0B       -100.00%  (p=0.029 n=4+4)
    Walk/Fwd[struct]-4                           48.0B ± 0%      0.0B       -100.00%  (p=0.029 n=4+4)
    Walk/Typedef[<nil>]-4                         112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Volatile[<nil>]-4                        112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Const[<nil>]-4                           112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Restrict[<nil>]-4                        112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Func[static_proto=<nil>]-4               112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/FuncProto[args=2_return=<nil>]-4         112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Var[static]-4                            112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)
    Walk/Datasec-4                                112B ± 0%       64B ± 0%   -42.86%  (p=0.029 n=4+4)

    name                                      old allocs/op  new allocs/op  delta
    Walk/Void-4                                   1.00 ± 0%      0.00       -100.00%  (p=0.029 n=4+4)
    Walk/Int[unsigned_size=0]-4                   1.00 ± 0%      0.00       -100.00%  (p=0.029 n=4+4)
    Walk/Pointer[target=<nil>]-4                  2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Array[index=<nil>_type=<nil>_n=0]-4      2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Struct[fields=2]-4                       2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Union[fields=2]-4                        2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Enum[size=0_values=0]-4                  1.00 ± 0%      0.00       -100.00%  (p=0.029 n=4+4)
    Walk/Fwd[struct]-4                            1.00 ± 0%      0.00       -100.00%  (p=0.029 n=4+4)
    Walk/Typedef[<nil>]-4                         2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Volatile[<nil>]-4                        2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Const[<nil>]-4                           2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Restrict[<nil>]-4                        2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Func[static_proto=<nil>]-4               2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/FuncProto[args=2_return=<nil>]-4         2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Var[static]-4                            2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
    Walk/Datasec-4                                2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.029 n=4+4)
Make typeDeque a generic container type so that we can re-use it
for postorderTraversal.
Move Deque from btf into internal and export methods. No other code changes.
@lmb lmb merged commit 713c8dc into cilium:master Sep 20, 2022
@lmb lmb deleted the btf-encoder-step-1 branch September 20, 2022 09:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants