-
Notifications
You must be signed in to change notification settings - Fork 18k
net/netip: Addr.AsSlice should be inlineable #56136
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
Comments
Wasn't there talks about upping the inliner's budget at one point? whatever happened to that? I can't find it anymore. |
I recently tried to remove this allocation in CL428855, but I abandoned it because, in case when the slice is forced to be heap allocated it caused an 16B allocation of ipv4 addresses instead of 4B. |
I thought about it again and found a solution to make it non-allocating. // AsSlice returns an IPv4 or IPv6 address in its respective 4-byte or 16-byte representation.
func (ip Addr) AsSlice() []byte {
var ret []byte
if ip.z == z4 {
ret = make([]byte, 4)
} else {
ret = make([]byte, 16)
}
return ip.asSlice(ret)
}
func (ip Addr) asSlice(ret []byte) []byte {
switch ip.z {
case z0:
return nil
case z4:
bePutUint32(ret[:], uint32(ip.addr.lo))
return ret
default:
bePutUint64(ret[:8], ip.addr.hi)
bePutUint64(ret[8:], ip.addr.lo)
return ret
}
} This method will fix the issue from comment above and allocate only 4B when ipv4.
commit. If we want this I will push a CL. |
Problem seems to lie with As16(). If importing binary pkg is an option, using binary.BigEndian.PutUint64() will considerably lower the cost. func (ip Addr) As16() (a16 [16]byte) {
binary.BigEndian.PutUint64(a16[:8], ip.addr.hi)
binary.BigEndian.PutUint64(a16[8:], ip.addr.lo)
return a16
} // AsSlice returns an IPv4 or IPv6 address in its respective 4-byte or 16-byte representation.
func (ip Addr) AsSlice() []byte {
ret := ip.As16()
switch ip.z {
case z0:
return nil
case z4:
return ret[12:]
}
return ret[:]
} Has a cost of 47.
|
@renthraysk I think we should do something like that, to only allocate 4B for ipv4. // AsSlice returns an IPv4 or IPv6 address in its respective 4-byte or 16-byte representation.
func (ip Addr) AsSlice() []byte {
switch ip.z {
case z0:
return nil
case z4:
buf := make([]byte, 4)
binary.BigEndian.PutUint32(buf, uint32(ip.addr.lo))
return buf
}
buf := make([]byte, 16)
binary.BigEndian.PutUint64(buf[:8], ip.addr.hi)
binary.BigEndian.PutUint64(buf[8:], ip.addr.lo)
return buf
} |
We should avoid the dependency on the "binary" package unless we can resolve #54097. |
@dsnet so #56136 (comment) seems to be best option for now. |
Could take the package path check out of the inliner or replace it with a check the code is within the standard library, and then local package versions could benefit from the cheap cost. go/src/cmd/compile/internal/inline/inl.go Lines 315 to 323 in 4a0ce46
|
This also as a side effect fixes golang#56136 because internal/netip-use-byteorder package has a special treatment in the inliner. Fixes golang#56136 Change-Id: I113185207186c3fa780240de009192096d3c77a6
Change https://go.dev/cl/584995 mentions this issue: |
Change https://go.dev/cl/585057 mentions this issue: |
CL 584995 made Addr.AsSlice inlineable as a side effect. Make sure we don't regress. Updates #56136 Change-Id: Ib5f77a430db66ffe45c4cbb264da7a401945fec9 Reviewed-on: https://go-review.googlesource.com/c/go/+/585057 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Auto-Submit: Tobias Klauser <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
This method always allocates because it returns a slice that escapes to the return value.
If the method were inlineable, the compiler may prove in some cases that the return value does not escape and can be stack allocated.
Currently, the method is a cost of 222; way over the budget of 80.
One attempt to optimize this was:
However, this is a function cost of 83. Just slightly over the budget.
The text was updated successfully, but these errors were encountered: