derp: remove two key.Public allocations

Reading and writing a [32]byte key to a bufio.Reader/bufio.Writer
can easily by done without allocating. Do so.

It is slower; on my machine, it adds about 100ns per read/write.
However, the overall request takes a minimum of several µs,
and it cuts allocations meaningfully, so it is probably worth it.

name                      old time/op    new time/op    delta
SendRecv/msgsize=10-8       9.21µs ± 9%    9.08µs ± 8%     ~     (p=0.250 n=15+15)
SendRecv/msgsize=100-8      6.51µs ± 9%    6.60µs ± 7%     ~     (p=0.259 n=15+13)
SendRecv/msgsize=1000-8     7.24µs ±13%    7.61µs ±36%     ~     (p=1.000 n=11+15)
SendRecv/msgsize=10000-8    19.5µs ±15%    19.9µs ±25%     ~     (p=0.890 n=14+15)

name                      old speed      new speed      delta
SendRecv/msgsize=10-8     1.09MB/s ± 8%  1.10MB/s ± 8%     ~     (p=0.286 n=15+15)
SendRecv/msgsize=100-8    15.4MB/s ± 8%  15.1MB/s ± 6%     ~     (p=0.129 n=15+12)
SendRecv/msgsize=1000-8    139MB/s ±15%   135MB/s ±28%     ~     (p=1.000 n=11+15)
SendRecv/msgsize=10000-8   516MB/s ±17%   506MB/s ±21%     ~     (p=0.880 n=14+15)

name                      old alloc/op   new alloc/op   delta
SendRecv/msgsize=10-8         170B ± 1%      108B ± 1%  -36.63%  (p=0.000 n=15+15)
SendRecv/msgsize=100-8        265B ± 1%      203B ± 1%  -23.34%  (p=0.000 n=15+15)
SendRecv/msgsize=1000-8     1.18kB ± 1%    1.12kB ± 0%   -5.31%  (p=0.000 n=14+14)
SendRecv/msgsize=10000-8    18.8kB ± 2%    18.8kB ± 2%     ~     (p=0.443 n=12+12)

name                      old allocs/op  new allocs/op  delta
SendRecv/msgsize=10-8         4.00 ± 0%      2.00 ± 0%  -50.00%  (p=0.000 n=15+15)
SendRecv/msgsize=100-8        4.00 ± 0%      2.00 ± 0%  -50.00%  (p=0.000 n=15+15)
SendRecv/msgsize=1000-8       4.00 ± 0%      2.00 ± 0%  -50.00%  (p=0.000 n=15+15)
SendRecv/msgsize=10000-8      5.00 ± 0%      3.00 ± 0%  -40.00%  (p=0.000 n=13+14)

Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
reviewable/pr681/r1
Josh Bleecher Snyder 4 years ago
parent b983e5340f
commit 909c165382

@ -746,7 +746,7 @@ func (s *Server) recvPacket(br *bufio.Reader, frameLen uint32) (dstKey key.Publi
if frameLen < keyLen {
return zpub, nil, errors.New("short send packet frame")
}
if _, err := io.ReadFull(br, dstKey[:]); err != nil {
if err := readPublicKey(br, &dstKey); err != nil {
return zpub, nil, err
}
packetLen := frameLen - keyLen
@ -1053,7 +1053,8 @@ func (c *sclient) sendPacket(srcKey key.Public, contents []byte) (err error) {
return err
}
if withKey {
if _, err = c.bw.Write(srcKey[:]); err != nil {
err := writePublicKey(c.bw, &srcKey)
if err != nil {
return err
}
}
@ -1250,3 +1251,34 @@ func (s *Server) ConsistencyCheck() error {
}
return errors.New(strings.Join(errs, ", "))
}
// readPublicKey reads key from br.
// It is ~4x slower than io.ReadFull(br, key),
// but it prevents key from escaping and thus being allocated.
// If io.ReadFull(br, key) does not cause key to escape, use that instead.
func readPublicKey(br *bufio.Reader, key *key.Public) error {
// Do io.ReadFull(br, key), but one byte at a time, to avoid allocation.
for i := range key {
b, err := br.ReadByte()
if err != nil {
return err
}
key[i] = b
}
return nil
}
// writePublicKey writes key to bw.
// It is ~3x slower than bw.Write(key[:]),
// but it prevents key from escaping and thus being allocated.
// If bw.Write(key[:]) does not cause key to escape, use that instead.
func writePublicKey(bw *bufio.Writer, key *key.Public) error {
// Do bw.Write(key[:]), but one byte at a time to avoid allocation.
for _, b := range key {
err := bw.WriteByte(b)
if err != nil {
return err
}
}
return nil
}

Loading…
Cancel
Save