-
Notifications
You must be signed in to change notification settings - Fork 40
Make IPPrefix smaller? #167
Comments
AFAIK Dave is correct: IPv6 zone + prefix doesn't really make sense. |
What should ParseIPPrefix and IPPrefixFrom do when a zone is present? Panic? Strip the zone? I think we should instead intern the (zone, bits) pair, thereby not losing any information, even if misguided. type IPPrefix struct {
addr uint128
zb *intern.Value // of uint8 or struct { string, uint8 }
} uint8s fit in an interface without allocation, so package intern shouldn't need new API for cheap operation when no zone is present. (I figure it's ok to allocate when used with zone, although it does contradict the docs that say that IPPrefixFrom doesn't allocate. We can change those docs.) |
The intern package's global mutex is only tolerable because nobody really uses IPv6 zones. But IPPrefixes are used (a lot), so that global mutex would almost certainly suck. I'd want to make sure that package netaddr
// &internBits[n] is the *intern.Value for an IPPrefix with /n bits.
var internBits [129]intern.Value It takes 1KB; probably fine. Alternatively, that could be a fast path in the intern package. |
We can also store bits in addr if |
I worry about conditional representations complicating a lot of stuff (since we'd need a separate way for IPv6 then), and perhaps making otherwise-inlinable things not. |
An experiment for #167. I'd probably a failed experiment. name old time/op new time/op delta IPSetFuzz-8 7.54µs ± 1% 7.61µs ± 1% +0.87% (p=0.004 n=10+10) BinaryMarshalRoundTrip/ipv4-8 13.8ns ± 1% 14.0ns ± 1% +1.12% (p=0.000 n=10+10) BinaryMarshalRoundTrip/ipv6-8 22.9ns ± 2% 23.1ns ± 1% ~ (p=0.060 n=10+10) BinaryMarshalRoundTrip/ipv6+zone-8 106ns ± 4% 106ns ± 0% ~ (p=0.306 n=9+9) StdIPv4-8 91.6ns ± 2% 91.8ns ± 1% ~ (p=0.182 n=9+10) IPv4-8 85.0ns ± 1% 83.9ns ± 0% -1.35% (p=0.000 n=8+10) IPv4_inline-8 88.7ns ± 2% 88.4ns ± 2% ~ (p=0.497 n=10+9) StdIPv6-8 117ns ± 1% 117ns ± 0% ~ (p=0.304 n=10+10) IPv6-8 108ns ± 1% 108ns ± 1% ~ (p=0.223 n=10+10) IPv4Contains-8 3.15ns ± 1% 11.95ns ± 1% +279.39% (p=0.000 n=10+10) IPv6Contains-8 3.82ns ± 3% 13.03ns ± 2% +241.22% (p=0.000 n=9+10) ParseIP/v4-8 14.0ns ± 1% 13.9ns ± 1% -0.64% (p=0.036 n=10+10) ParseIP/v6-8 69.1ns ± 3% 67.9ns ± 0% -1.75% (p=0.000 n=9+10) ParseIP/v6_ellipsis-8 43.7ns ± 2% 43.6ns ± 2% ~ (p=0.796 n=10+10) ParseIP/v6_v4-8 43.5ns ± 2% 43.4ns ± 2% ~ (p=0.549 n=9+10) ParseIP/v6_zone-8 85.3ns ± 3% 87.5ns ± 4% +2.59% (p=0.033 n=10+9) StdParseIP/v4-8 35.8ns ± 2% 35.8ns ± 1% ~ (p=0.715 n=9+9) StdParseIP/v6-8 82.2ns ± 0% 83.1ns ± 0% +1.02% (p=0.000 n=8+9) StdParseIP/v6_ellipsis-8 53.2ns ± 2% 53.9ns ± 1% +1.29% (p=0.001 n=10+10) StdParseIP/v6_v4-8 75.6ns ± 1% 76.1ns ± 0% +0.73% (p=0.000 n=9+10) StdParseIP/v6_zone-8 64.4ns ± 1% 65.3ns ± 1% +1.43% (p=0.000 n=10+10) IPString/v4-8 22.6ns ± 1% 22.6ns ± 1% ~ (p=0.482 n=9+10) IPString/v6-8 62.2ns ± 0% 62.8ns ± 1% +0.95% (p=0.001 n=10+10) IPString/v6_ellipsis-8 57.1ns ± 0% 57.6ns ± 1% +0.85% (p=0.000 n=9+10) IPString/v6_v4-8 58.7ns ± 1% 59.3ns ± 0% +1.07% (p=0.000 n=10+9) IPString/v6_zone-8 58.5ns ± 0% 59.0ns ± 1% +0.90% (p=0.000 n=10+10) IPMarshalText-8 21.3ns ± 1% 21.5ns ± 1% +0.79% (p=0.000 n=10+10) IPPortString/v4-8 159ns ± 0% 160ns ± 1% +1.00% (p=0.000 n=9+10) IPPortString/v6-8 123ns ± 1% 124ns ± 1% ~ (p=0.147 n=9+10) IPPortString/v6_ellipsis-8 119ns ± 1% 120ns ± 0% +0.70% (p=0.004 n=9+10) IPPortString/v6_v4-8 119ns ± 1% 120ns ± 1% +1.07% (p=0.000 n=10+9) IPPortString/v6_zone-8 121ns ± 1% 122ns ± 1% +0.61% (p=0.024 n=10+10) IPPortMarshalText/v4-8 36.7ns ± 1% 36.8ns ± 1% ~ (p=0.484 n=10+9) IPPortMarshalText/v6-8 74.2ns ± 1% 74.9ns ± 1% +0.92% (p=0.003 n=9+10) IPPortMarshalText/v6_ellipsis-8 71.7ns ± 1% 72.3ns ± 1% +0.89% (p=0.000 n=9+10) IPPortMarshalText/v6_v4-8 73.9ns ± 1% 74.6ns ± 1% +0.91% (p=0.000 n=10+10) IPPortMarshalText/v6_zone-8 73.1ns ± 1% 73.7ns ± 0% +0.78% (p=0.001 n=10+9) IPPrefixMasking/IPv4_/32-8 4.01ns ± 5% 6.25ns ± 1% +55.99% (p=0.000 n=10+8) IPPrefixMasking/IPv4_/17-8 3.94ns ± 0% 6.23ns ± 0% +58.03% (p=0.000 n=10+10) IPPrefixMasking/IPv4_/0-8 3.95ns ± 0% 6.23ns ± 0% +57.81% (p=0.000 n=8+10) IPPrefixMasking/IPv6_/128-8 3.94ns ± 1% 6.25ns ± 0% +58.45% (p=0.000 n=9+10) IPPrefixMasking/IPv6_/65-8 4.01ns ± 4% 6.23ns ± 0% +55.53% (p=0.000 n=10+9) IPPrefixMasking/IPv6_/0-8 3.95ns ± 1% 6.36ns ± 4% +61.09% (p=0.000 n=8+10) IPPrefixMasking/IPv6_zone_/128-8 3.94ns ± 0% 107.53ns ± 2% +2626.16% (p=0.000 n=8+10) IPPrefixMasking/IPv6_zone_/65-8 3.95ns ± 0% 106.50ns ± 0% +2596.05% (p=0.000 n=9+10) IPPrefixMasking/IPv6_zone_/0-8 3.95ns ± 0% 107.22ns ± 0% +2617.08% (p=0.000 n=9+8) IPPrefixMarshalText-8 28.8ns ± 1% 39.4ns ± 1% +36.75% (p=0.000 n=10+10) ParseIPPort/v4-8 27.0ns ± 1% 27.1ns ± 1% +0.53% (p=0.041 n=10+9) ParseIPPort/v6-8 81.7ns ± 1% 81.1ns ± 1% -0.73% (p=0.037 n=10+10) ParseIPPort/v6_ellipsis-8 56.9ns ± 2% 55.8ns ± 1% -1.80% (p=0.000 n=10+9) ParseIPPort/v6_v4-8 55.8ns ± 1% 56.0ns ± 1% ~ (p=0.204 n=10+9) ParseIPPort/v6_zone-8 101ns ± 0% 102ns ± 0% +1.68% (p=0.000 n=8+9) IPRangePrefixes-8 563ns ± 1% 738ns ± 1% +31.05% (p=0.000 n=9+9) IPRangePrefix-8 13.1ns ± 0% 17.1ns ± 1% +30.13% (p=0.000 n=8+10) IPNextPrior-8 135ns ± 1% 135ns ± 1% ~ (p=0.439 n=10+10) name old alloc/op new alloc/op delta IPSetFuzz-8 1.90kB ± 1% 1.90kB ± 1% ~ (p=0.956 n=10+10) StdIPv4-8 16.0B ± 0% 16.0B ± 0% ~ (all equal) IPv4-8 0.00B 0.00B ~ (all equal) IPv4_inline-8 0.00B 0.00B ~ (all equal) StdIPv6-8 16.0B ± 0% 16.0B ± 0% ~ (all equal) IPv6-8 0.00B 0.00B ~ (all equal) IPv4Contains-8 0.00B 0.00B ~ (all equal) IPv6Contains-8 0.00B 0.00B ~ (all equal) ParseIP/v4-8 0.00B 0.00B ~ (all equal) ParseIP/v6-8 0.00B 0.00B ~ (all equal) ParseIP/v6_ellipsis-8 0.00B 0.00B ~ (all equal) ParseIP/v6_v4-8 0.00B 0.00B ~ (all equal) ParseIP/v6_zone-8 0.00B 0.00B ~ (all equal) StdParseIP/v4-8 16.0B ± 0% 16.0B ± 0% ~ (all equal) StdParseIP/v6-8 16.0B ± 0% 16.0B ± 0% ~ (all equal) StdParseIP/v6_ellipsis-8 16.0B ± 0% 16.0B ± 0% ~ (all equal) StdParseIP/v6_v4-8 32.0B ± 0% 32.0B ± 0% ~ (all equal) StdParseIP/v6_zone-8 16.0B ± 0% 16.0B ± 0% ~ (all equal) IPString/v4-8 16.0B ± 0% 16.0B ± 0% ~ (all equal) IPString/v6-8 48.0B ± 0% 48.0B ± 0% ~ (all equal) IPString/v6_ellipsis-8 24.0B ± 0% 24.0B ± 0% ~ (all equal) IPString/v6_v4-8 16.0B ± 0% 16.0B ± 0% ~ (all equal) IPString/v6_zone-8 24.0B ± 0% 24.0B ± 0% ~ (all equal) IPMarshalText-8 16.0B ± 0% 16.0B ± 0% ~ (all equal) IPPortString/v4-8 26.0B ± 0% 26.0B ± 0% ~ (all equal) IPPortString/v6-8 101B ± 0% 101B ± 0% ~ (all equal) IPPortString/v6_ellipsis-8 61.0B ± 0% 61.0B ± 0% ~ (all equal) IPPortString/v6_v4-8 45.0B ± 0% 45.0B ± 0% ~ (all equal) IPPortString/v6_zone-8 61.0B ± 0% 61.0B ± 0% ~ (all equal) IPPortMarshalText/v4-8 24.0B ± 0% 24.0B ± 0% ~ (all equal) IPPortMarshalText/v6-8 64.0B ± 0% 64.0B ± 0% ~ (all equal) IPPortMarshalText/v6_ellipsis-8 64.0B ± 0% 64.0B ± 0% ~ (all equal) IPPortMarshalText/v6_v4-8 64.0B ± 0% 64.0B ± 0% ~ (all equal) IPPortMarshalText/v6_zone-8 64.0B ± 0% 64.0B ± 0% ~ (all equal) IPPrefixMasking/IPv4_/32-8 0.00B 0.00B ~ (all equal) IPPrefixMasking/IPv4_/17-8 0.00B 0.00B ~ (all equal) IPPrefixMasking/IPv4_/0-8 0.00B 0.00B ~ (all equal) IPPrefixMasking/IPv6_/128-8 0.00B 0.00B ~ (all equal) IPPrefixMasking/IPv6_/65-8 0.00B 0.00B ~ (all equal) IPPrefixMasking/IPv6_/0-8 0.00B 0.00B ~ (all equal) IPPrefixMasking/IPv6_zone_/128-8 0.00B 24.00B ± 0% +Inf% (p=0.000 n=10+10) IPPrefixMasking/IPv6_zone_/65-8 0.00B 24.00B ± 0% +Inf% (p=0.000 n=10+10) IPPrefixMasking/IPv6_zone_/0-8 0.00B 24.00B ± 0% +Inf% (p=0.000 n=10+10) IPPrefixMarshalText-8 24.0B ± 0% 24.0B ± 0% ~ (all equal) ParseIPPort/v4-8 0.00B 0.00B ~ (all equal) ParseIPPort/v6-8 0.00B 0.00B ~ (all equal) ParseIPPort/v6_ellipsis-8 0.00B 0.00B ~ (all equal) ParseIPPort/v6_v4-8 0.00B 0.00B ~ (all equal) ParseIPPort/v6_zone-8 0.00B 0.00B ~ (all equal) IPRangePrefixes-8 0.00B 0.00B ~ (all equal) IPRangePrefix-8 0.00B 0.00B ~ (all equal) name old allocs/op new allocs/op delta IPSetFuzz-8 30.0 ± 0% 30.0 ± 0% ~ (all equal) StdIPv4-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) IPv4-8 0.00 0.00 ~ (all equal) IPv4_inline-8 0.00 0.00 ~ (all equal) StdIPv6-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) IPv6-8 0.00 0.00 ~ (all equal) IPv4Contains-8 0.00 0.00 ~ (all equal) IPv6Contains-8 0.00 0.00 ~ (all equal) ParseIP/v4-8 0.00 0.00 ~ (all equal) ParseIP/v6-8 0.00 0.00 ~ (all equal) ParseIP/v6_ellipsis-8 0.00 0.00 ~ (all equal) ParseIP/v6_v4-8 0.00 0.00 ~ (all equal) ParseIP/v6_zone-8 0.00 0.00 ~ (all equal) StdParseIP/v4-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) StdParseIP/v6-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) StdParseIP/v6_ellipsis-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) StdParseIP/v6_v4-8 2.00 ± 0% 2.00 ± 0% ~ (all equal) StdParseIP/v6_zone-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) IPString/v4-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) IPString/v6-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) IPString/v6_ellipsis-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) IPString/v6_v4-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) IPString/v6_zone-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) IPMarshalText-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) IPPortString/v4-8 2.00 ± 0% 2.00 ± 0% ~ (all equal) IPPortString/v6-8 3.00 ± 0% 3.00 ± 0% ~ (all equal) IPPortString/v6_ellipsis-8 3.00 ± 0% 3.00 ± 0% ~ (all equal) IPPortString/v6_v4-8 3.00 ± 0% 3.00 ± 0% ~ (all equal) IPPortString/v6_zone-8 3.00 ± 0% 3.00 ± 0% ~ (all equal) IPPortMarshalText/v4-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) IPPortMarshalText/v6-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) IPPortMarshalText/v6_ellipsis-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) IPPortMarshalText/v6_v4-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) IPPortMarshalText/v6_zone-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) IPPrefixMasking/IPv4_/32-8 0.00 0.00 ~ (all equal) IPPrefixMasking/IPv4_/17-8 0.00 0.00 ~ (all equal) IPPrefixMasking/IPv4_/0-8 0.00 0.00 ~ (all equal) IPPrefixMasking/IPv6_/128-8 0.00 0.00 ~ (all equal) IPPrefixMasking/IPv6_/65-8 0.00 0.00 ~ (all equal) IPPrefixMasking/IPv6_/0-8 0.00 0.00 ~ (all equal) IPPrefixMasking/IPv6_zone_/128-8 0.00 1.00 ± 0% +Inf% (p=0.000 n=10+10) IPPrefixMasking/IPv6_zone_/65-8 0.00 1.00 ± 0% +Inf% (p=0.000 n=10+10) IPPrefixMasking/IPv6_zone_/0-8 0.00 1.00 ± 0% +Inf% (p=0.000 n=10+10) IPPrefixMarshalText-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) ParseIPPort/v4-8 0.00 0.00 ~ (all equal) ParseIPPort/v6-8 0.00 0.00 ~ (all equal) ParseIPPort/v6_ellipsis-8 0.00 0.00 ~ (all equal) ParseIPPort/v6_v4-8 0.00 0.00 ~ (all equal) ParseIPPort/v6_zone-8 0.00 0.00 ~ (all equal) IPRangePrefixes-8 0.00 0.00 ~ (all equal) IPRangePrefix-8 0.00 0.00 ~ (all equal) Signed-off-by: Josh Bleecher Snyder <[email protected]>
I tried out combining bits and zone in #175. It...got ugly. Among other things we still need a way to distinguish IPv4 from IPv6, so we ended up needing two internBits arrays. And we ended up with a bunch of type switches and goo, making otherwise-inlinable things not. So I guess we're back to the API question: What should ParseIPPrefix and IPPrefixFrom do when a zone is present? Panic? Strip the zone? And then we should run an experiment to see how the code actually looks. There's something delightfully lightweight about having two fields each of which is itself already in the desired form. I'm leaning towards not doing anything here. |
So, it seems our prime question is whether zones ever make sense in a prefix, and we still don't know. The closest piece of software that might care is CoreRAD, but since @mdlayher hasn't screamed yet I assume it doesn't need prefix+zone. I can't think of another piece of software that would care about scoped addrs at all, let alone scoped prefixes. Given that, the question I have would be: how hard would it be to re-add zone support later if it turns out we were wrong? If it's not an API change (aside from documenting that ParseIPPrefix now accepts zones), then we can cut out zones for now, make everything more optimized, and still have an out if it turns out prefix+zone is in fact important. The main thing to answer there is what our current error-less functions (i.e. IPPrefixFrom, pfx.WithIP if we ever implement that) do when handed a zoned IP? We can:
Given the options, I lean slightly towards silently (but documentedly) stripping the zone when constructing prefixes. We can add an additional API to allow zoned prefixes down the road (or accept a very small semantic change for programs that passed zoned IPs into prefix construction), and it avoids both rude panics and verbose error paths. |
SGTM (slightly drop zone, documented, and we can always add more API later if a need arises) |
Do we want UnmarshalText and ParseIPPrefix to drop zone or return an error? An error seems nicer, but it makes the behavior slightly inconsistent. (ParseIP + Atoi + IPPrefixFrom != ParseIPPrefix) |
Enabler for #167. Signed-off-by: David Anderson <[email protected]>
Enabler for #167. Signed-off-by: David Anderson <[email protected]>
(Re-filing #154, which was closed when half of it was done)
An IPPrefix is currently an IP + a uint16, 32 bytes.
Now that IPPrefix is opaque, we can make it smaller:
We could instead do:
And we'd be at 24 bytes after padding: https://play.golang.org/p/opWXptWj6jQ
This all assumes an IPPrefix of an IPv6 zone doesn't make sense. Is that correct?
To which @danderson said:
The text was updated successfully, but these errors were encountered: