Skip to content

refactor: don't fill empty metadata slots #32

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

Merged
merged 1 commit into from
Nov 25, 2023

Conversation

smira
Copy link
Contributor

@smira smira commented Sep 26, 2023

Some metadata arrays are pretty big (e.g. EthernetTypeMetadata has 65536 slots), while only a small subset of the values are filled with actual decoders (e.g. for EthernetTypeMetadata that is 18 entries).

The rest were filled in func init() to return error on access. This leads to noticeable startup time delay, as these mappings are pretty big.

This change simply leaves not used slots unset (zero value), and the request error values are generated on access to the slot.

Comparing time with GODEBUG=inittrace=1 on a simple test program which imports gopacket/layers:

before:

init internal/bytealg @0 ms, 0 ms clock, 0 bytes, 0 allocs
init runtime @0.009 ms, 0.063 ms clock, 0 bytes, 0 allocs
init math @0.18 ms, 0 ms clock, 0 bytes, 0 allocs
init errors @0.19 ms, 0 ms clock, 0 bytes, 0 allocs
init sync @0.20 ms, 0.002 ms clock, 16 bytes, 1 allocs
init internal/godebug @0.21 ms, 0.020 ms clock, 816 bytes, 20 allocs
init internal/intern @0.23 ms, 0.002 ms clock, 408 bytes, 8 allocs
init hash/crc32 @0.24 ms, 0.008 ms clock, 1024 bytes, 1 allocs
init net/netip @0.26 ms, 0 ms clock, 48 bytes, 2 allocs
init syscall @0.26 ms, 0.003 ms clock, 640 bytes, 3 allocs
init time @0.27 ms, 0.002 ms clock, 0 bytes, 0 allocs
init context @0.28 ms, 0 ms clock, 96 bytes, 1 allocs
init io/fs @0.29 ms, 0 ms clock, 0 bytes, 0 allocs
init os @0.30 ms, 0.006 ms clock, 328 bytes, 7 allocs
init unicode @0.31 ms, 0 ms clock, 512 bytes, 4 allocs
init reflect @0.32 ms, 0 ms clock, 0 bytes, 0 allocs
init vendor/golang.org/x/net/dns/dnsmessage @0.32 ms, 0.002 ms clock, 624 bytes, 6 allocs
init net @0.33 ms, 0.002 ms clock, 688 bytes, 13 allocs
init github.com/gopacket/gopacket @0.34 ms, 0.003 ms clock, 720 bytes, 5 allocs
init github.com/gopacket/gopacket/layers @0.35 ms, 1.3 ms clock, 25136 bytes, 63 allocs

after:

init internal/bytealg @0 ms, 0 ms clock, 0 bytes, 0 allocs
init runtime @0.011 ms, 0.070 ms clock, 0 bytes, 0 allocs
init math @0.26 ms, 0 ms clock, 0 bytes, 0 allocs
init errors @0.27 ms, 0 ms clock, 0 bytes, 0 allocs
init sync @0.27 ms, 0.003 ms clock, 16 bytes, 1 allocs
init internal/godebug @0.28 ms, 0.023 ms clock, 816 bytes, 20 allocs
init internal/intern @0.31 ms, 0.002 ms clock, 408 bytes, 8 allocs
init hash/crc32 @0.32 ms, 0.008 ms clock, 1024 bytes, 1 allocs
init net/netip @0.33 ms, 0 ms clock, 48 bytes, 2 allocs
init syscall @0.34 ms, 0.003 ms clock, 640 bytes, 3 allocs
init time @0.35 ms, 0.003 ms clock, 0 bytes, 0 allocs
init context @0.37 ms, 0 ms clock, 96 bytes, 1 allocs
init io/fs @0.38 ms, 0 ms clock, 0 bytes, 0 allocs
init os @0.38 ms, 0.009 ms clock, 328 bytes, 7 allocs
init unicode @0.40 ms, 0 ms clock, 512 bytes, 4 allocs
init reflect @0.41 ms, 0 ms clock, 0 bytes, 0 allocs
init vendor/golang.org/x/net/dns/dnsmessage @0.42 ms, 0.002 ms clock, 624 bytes, 6 allocs
init net @0.43 ms, 0.004 ms clock, 688 bytes, 13 allocs
init github.com/gopacket/gopacket @0.44 ms, 0.003 ms clock, 720 bytes, 5 allocs
init github.com/gopacket/gopacket/layers @0.46 ms, 0.086 ms clock, 25872 bytes, 66 allocs

Some metadata arrays are pretty big (e.g. `EthernetTypeMetadata` has
65536 slots), while only a small subset of the values are filled with
actual decoders (e.g. for `EthernetTypeMetadata` that is 18 entries).

The rest were filled in `func init()` to return error on access. This
leads to noticeable startup time delay, as these mappings are pretty
big.

This change simply leaves not used slots unset (zero value), and the
request error values are generated on access to the slot.

Comparing time with `GODEBUG=inittrace=1` on a simple test program which
imports `gopacket/layers`:

before:

```
init internal/bytealg @0 ms, 0 ms clock, 0 bytes, 0 allocs
init runtime @0.009 ms, 0.063 ms clock, 0 bytes, 0 allocs
init math @0.18 ms, 0 ms clock, 0 bytes, 0 allocs
init errors @0.19 ms, 0 ms clock, 0 bytes, 0 allocs
init sync @0.20 ms, 0.002 ms clock, 16 bytes, 1 allocs
init internal/godebug @0.21 ms, 0.020 ms clock, 816 bytes, 20 allocs
init internal/intern @0.23 ms, 0.002 ms clock, 408 bytes, 8 allocs
init hash/crc32 @0.24 ms, 0.008 ms clock, 1024 bytes, 1 allocs
init net/netip @0.26 ms, 0 ms clock, 48 bytes, 2 allocs
init syscall @0.26 ms, 0.003 ms clock, 640 bytes, 3 allocs
init time @0.27 ms, 0.002 ms clock, 0 bytes, 0 allocs
init context @0.28 ms, 0 ms clock, 96 bytes, 1 allocs
init io/fs @0.29 ms, 0 ms clock, 0 bytes, 0 allocs
init os @0.30 ms, 0.006 ms clock, 328 bytes, 7 allocs
init unicode @0.31 ms, 0 ms clock, 512 bytes, 4 allocs
init reflect @0.32 ms, 0 ms clock, 0 bytes, 0 allocs
init vendor/golang.org/x/net/dns/dnsmessage @0.32 ms, 0.002 ms clock, 624 bytes, 6 allocs
init net @0.33 ms, 0.002 ms clock, 688 bytes, 13 allocs
init github.com/gopacket/gopacket @0.34 ms, 0.003 ms clock, 720 bytes, 5 allocs
init github.com/gopacket/gopacket/layers @0.35 ms, 1.3 ms clock, 25136 bytes, 63 allocs
```

after:

```
init internal/bytealg @0 ms, 0 ms clock, 0 bytes, 0 allocs
init runtime @0.011 ms, 0.070 ms clock, 0 bytes, 0 allocs
init math @0.26 ms, 0 ms clock, 0 bytes, 0 allocs
init errors @0.27 ms, 0 ms clock, 0 bytes, 0 allocs
init sync @0.27 ms, 0.003 ms clock, 16 bytes, 1 allocs
init internal/godebug @0.28 ms, 0.023 ms clock, 816 bytes, 20 allocs
init internal/intern @0.31 ms, 0.002 ms clock, 408 bytes, 8 allocs
init hash/crc32 @0.32 ms, 0.008 ms clock, 1024 bytes, 1 allocs
init net/netip @0.33 ms, 0 ms clock, 48 bytes, 2 allocs
init syscall @0.34 ms, 0.003 ms clock, 640 bytes, 3 allocs
init time @0.35 ms, 0.003 ms clock, 0 bytes, 0 allocs
init context @0.37 ms, 0 ms clock, 96 bytes, 1 allocs
init io/fs @0.38 ms, 0 ms clock, 0 bytes, 0 allocs
init os @0.38 ms, 0.009 ms clock, 328 bytes, 7 allocs
init unicode @0.40 ms, 0 ms clock, 512 bytes, 4 allocs
init reflect @0.41 ms, 0 ms clock, 0 bytes, 0 allocs
init vendor/golang.org/x/net/dns/dnsmessage @0.42 ms, 0.002 ms clock, 624 bytes, 6 allocs
init net @0.43 ms, 0.004 ms clock, 688 bytes, 13 allocs
init github.com/gopacket/gopacket @0.44 ms, 0.003 ms clock, 720 bytes, 5 allocs
init github.com/gopacket/gopacket/layers @0.46 ms, 0.086 ms clock, 25872 bytes, 66 allocs
```

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
@smira smira force-pushed the refactor/empty-metadata branch from 6147fa5 to 6035c7b Compare September 26, 2023 11:57
@mosajjal mosajjal self-assigned this Oct 14, 2023
@mosajjal
Copy link
Contributor

Hi,

how much optimization are we talking about here? in terms of allocation, doesn't look different at all. and for startup time, we're talking about 0.1ms?

@smira
Copy link
Contributor Author

smira commented Oct 16, 2023

output is confusing, before is 1.3ms:

init github.com/gopacket/gopacket/layers @0.35 ms, 1.3 ms clock, 25136 bytes, 63 allocs

after: 0.086ms

init github.com/gopacket/gopacket/layers @0.46 ms, 0.086 ms clock, 25872 bytes, 66 allocs

So -1.2ms. In other bigger projects this initialization is the worst part of all 100+ libraries imported, and measures at 1-3ms.

@mosajjal mosajjal merged commit 7048c15 into gopacket:master Nov 25, 2023
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.

2 participants