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

map: zero-allocation operations for common types #1062

Merged
merged 1 commit into from Sep 14, 2023

Conversation

lmb
Copy link
Collaborator

@lmb lmb commented Jun 14, 2023

map: zero-allocation operations for common types

Map keys and values are currently marshaled into []byte by souped up
versions of binary.Write and binary.Read. This allows users to be blissfully
unaware of compiler inserted padding on the Go side. This is wasteful in
case the Go in-memory representation matches what the kernel expects because
we need additional allocations.

Refactor syscall marshaling into a new package sysenc which encapsulates the
logic we need to determine whether a Go type is safe for zero-allocation /
zero-copy marshaling. The type must be a pointer to or a slice of:

* A primitive type like uint32, ... or
* An array of valid types or
* A struct made up of valid types without any compiler
 inserted padding between fields

Per-CPU maps don't support zero-allocation operations for now, but the new
code already makes things a little bit cheaper.

Structs with trailing padding also don't benefit from the optimization for
now. Consider

    type padded struct { A uint32; B uint16 }

Allowing such a type creates an edge case: make([]padding, 1) uses
zero-allocation marshaling while make([]padding, 2) doesn't, due to interior
padding. It's simpler to skip such types for now.

    goos: linux
   goarch: amd64
   pkg: github.com/cilium/ebpf
   cpu: 12th Gen Intel(R) Core(TM) i7-1260P
                                        │ unsafe.txt  │
                                        │   sec/op    │
   Marshaling/ValueUnmarshalReflect-16    356.1n ± 2%
   Marshaling/KeyMarshalReflect-16        368.6n ± 1%
   Marshaling/ValueBinaryUnmarshaler-16   378.6n ± 2%
   Marshaling/KeyBinaryMarshaler-16       356.2n ± 1%
   Marshaling/KeyValueUnsafe-16           328.0n ± 2%
   PerCPUMarshalling/reflection-16        1.232µ ± 1%

                                         │  unsafe.txt  │
                                        │     B/op     │
   Marshaling/ValueUnmarshalReflect-16    0.000 ± 0%
   Marshaling/KeyMarshalReflect-16        0.000 ± 0%
   Marshaling/ValueBinaryUnmarshaler-16   24.00 ± 0%
   Marshaling/KeyBinaryMarshaler-16       8.000 ± 0%
   Marshaling/KeyValueUnsafe-16           0.000 ± 0%
   PerCPUMarshalling/reflection-16        280.0 ± 0%

                                         │  unsafe.txt  │
                                        │  allocs/op   │
   Marshaling/ValueUnmarshalReflect-16    0.000 ± 0%
   Marshaling/KeyMarshalReflect-16        0.000 ± 0%
   Marshaling/ValueBinaryUnmarshaler-16   1.000 ± 0%
   Marshaling/KeyBinaryMarshaler-16       1.000 ± 0%
   Marshaling/KeyValueUnsafe-16           0.000 ± 0%
   PerCPUMarshalling/reflection-16        3.000 ± 0%

Signed-off-by: Lorenz Bauer <lmb@isovalent.com>

internal/sysenc/marshal.go Outdated Show resolved Hide resolved
@lmb lmb force-pushed the unsafe-marshal branch 3 times, most recently from ec9482c to f81ea58 Compare June 19, 2023 09:46
@lmb lmb force-pushed the unsafe-marshal branch 4 times, most recently from be6a923 to f19814b Compare June 26, 2023 15:05
@lmb
Copy link
Collaborator Author

lmb commented Jun 28, 2023

@mejedi I'll be doing a code walk of this PR tomorrow 9:30 UTC+1, let me know if you'd like to join.

@mejedi
Copy link
Contributor

mejedi commented Jun 29, 2023

@lmb

@mejedi I'll be doing a code walk of this PR tomorrow 9:30 UTC+1, let me know if you'd like to join.

Thank you for the invitation! I can’t join, I’m afraid. I’m pretty much preoccupied with moving apartments this week :(

internal/sysenc/layout.go Outdated Show resolved Hide resolved
internal/sysenc/layout.go Outdated Show resolved Hide resolved
internal/sysenc/layout.go Outdated Show resolved Hide resolved
internal/sysenc/layout.go Outdated Show resolved Hide resolved
@lmb lmb force-pushed the unsafe-marshal branch 2 times, most recently from 4913e0f to fcdc2f3 Compare July 4, 2023 16:54
@lmb
Copy link
Collaborator Author

lmb commented Jul 4, 2023

I removed the custom layout code after discussing it with Robin and Timo.

@lmb lmb marked this pull request as ready for review July 12, 2023 09:44
@lmb lmb requested review from ti-mo, rgo3 and mejedi July 12, 2023 09:44
Copy link
Collaborator

@ti-mo ti-mo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for leaving this unattended for so long. I have a few questions and left a few comments. Thanks! 🙏

marshalers.go Outdated Show resolved Hide resolved
internal/sysenc/buffer.go Outdated Show resolved Hide resolved
internal/sysenc/layout.go Show resolved Hide resolved
internal/sysenc/marshal.go Outdated Show resolved Hide resolved
internal/sysenc/marshal.go Show resolved Hide resolved
internal/sysenc/marshal.go Show resolved Hide resolved
internal/sysenc/marshal.go Show resolved Hide resolved
internal/sysenc/marshal.go Show resolved Hide resolved
marshalers.go Outdated Show resolved Hide resolved
marshalers.go Outdated Show resolved Hide resolved
@lmb lmb force-pushed the unsafe-marshal branch 2 times, most recently from 4d3b987 to aa57513 Compare September 12, 2023 15:57
@lmb lmb requested a review from ti-mo September 12, 2023 16:19
Map keys and values are currently marshaled into []byte by souped
up versions of binary.Write and binary.Read. This allows users to
be blissfully unaware of compiler inserted padding on the Go side.
This is wasteful in case the Go in-memory representation matches
what the kernel expects because we need additional allocations.

Refactor syscall marshaling into a new package sysenc which
encapsulates the logic we need to determine whether a Go type
is safe for zero-allocation / zero-copy marshaling. The type
must be a pointer to or a slice of:

* A primitive type like uint32, ... or
* An array of valid types or
* A struct made up of valid types without any compiler
  inserted padding between fields

Per-CPU maps don't support zero-allocation operations for now,
but the new code already makes things a little bit cheaper.

Structs with trailing padding also don't benefit from the
optimization for now. Consider

    type padded struct { A uint32; B uint16 }

Allowing such a type creates an edge case: make([]padding, 1)
uses zero-allocation marshaling while make([]padding, 2)
doesn't, due to interior padding. It's simpler to skip such
types for now.

    goos: linux
    goarch: amd64
    pkg: github.com/cilium/ebpf
    cpu: 12th Gen Intel(R) Core(TM) i7-1260P
                                         │ unsafe.txt  │
                                         │   sec/op    │
    Marshaling/ValueUnmarshalReflect-16    356.1n ± 2%
    Marshaling/KeyMarshalReflect-16        368.6n ± 1%
    Marshaling/ValueBinaryUnmarshaler-16   378.6n ± 2%
    Marshaling/KeyBinaryMarshaler-16       356.2n ± 1%
    Marshaling/KeyValueUnsafe-16           328.0n ± 2%
    PerCPUMarshalling/reflection-16        1.232µ ± 1%

                                         │  unsafe.txt  │
                                         │     B/op     │
    Marshaling/ValueUnmarshalReflect-16    0.000 ± 0%
    Marshaling/KeyMarshalReflect-16        0.000 ± 0%
    Marshaling/ValueBinaryUnmarshaler-16   24.00 ± 0%
    Marshaling/KeyBinaryMarshaler-16       8.000 ± 0%
    Marshaling/KeyValueUnsafe-16           0.000 ± 0%
    PerCPUMarshalling/reflection-16        280.0 ± 0%

                                         │  unsafe.txt  │
                                         │  allocs/op   │
    Marshaling/ValueUnmarshalReflect-16    0.000 ± 0%
    Marshaling/KeyMarshalReflect-16        0.000 ± 0%
    Marshaling/ValueBinaryUnmarshaler-16   1.000 ± 0%
    Marshaling/KeyBinaryMarshaler-16       1.000 ± 0%
    Marshaling/KeyValueUnsafe-16           0.000 ± 0%
    PerCPUMarshalling/reflection-16        3.000 ± 0%

Signed-off-by: Lorenz Bauer <lmb@isovalent.com>
@lmb
Copy link
Collaborator Author

lmb commented Sep 14, 2023

@ti-mo this is good to go.

@ti-mo ti-mo merged commit 4609dc7 into cilium:main Sep 14, 2023
2 checks passed
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

4 participants