device: reduce RoutineHandshake allocations
Reduce allocations by eliminating byte reader, hand-rolled decoding and
reusing message structs.
Synthetic benchmark:
var msgSink MessageInitiation
func BenchmarkMessageInitiationUnmarshal(b *testing.B) {
packet := make([]byte, MessageInitiationSize)
reader := bytes.NewReader(packet)
err := binary.Read(reader, binary.LittleEndian, &msgSink)
if err != nil {
b.Fatal(err)
}
b.Run("binary.Read", func(b *testing.B) {
b.ReportAllocs()
for range b.N {
reader := bytes.NewReader(packet)
_ = binary.Read(reader, binary.LittleEndian, &msgSink)
}
})
b.Run("unmarshal", func(b *testing.B) {
b.ReportAllocs()
for range b.N {
_ = msgSink.unmarshal(packet)
}
})
}
Results:
│ - │
│ sec/op │
MessageInitiationUnmarshal/binary.Read-8 1.508µ ± 2%
MessageInitiationUnmarshal/unmarshal-8 12.66n ± 2%
│ - │
│ B/op │
MessageInitiationUnmarshal/binary.Read-8 208.0 ± 0%
MessageInitiationUnmarshal/unmarshal-8 0.000 ± 0%
│ - │
│ allocs/op │
MessageInitiationUnmarshal/binary.Read-8 2.000 ± 0%
MessageInitiationUnmarshal/unmarshal-8 0.000 ± 0%
Signed-off-by: Alexander Yastrebov <yastrebov.alex@gmail.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
committed by
Jason A. Donenfeld
parent
436f7fdc16
commit
9e7529c3d2
@@ -6,6 +6,7 @@
|
|||||||
package device
|
package device
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -115,6 +116,53 @@ type MessageCookieReply struct {
|
|||||||
Cookie [blake2s.Size128 + poly1305.TagSize]byte
|
Cookie [blake2s.Size128 + poly1305.TagSize]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errMessageTooShort = errors.New("message too short")
|
||||||
|
|
||||||
|
func (msg *MessageInitiation) unmarshal(b []byte) error {
|
||||||
|
if len(b) < MessageInitiationSize {
|
||||||
|
return errMessageTooShort
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Type = binary.LittleEndian.Uint32(b)
|
||||||
|
msg.Sender = binary.LittleEndian.Uint32(b[4:])
|
||||||
|
copy(msg.Ephemeral[:], b[8:])
|
||||||
|
copy(msg.Static[:], b[8+len(msg.Ephemeral):])
|
||||||
|
copy(msg.Timestamp[:], b[8+len(msg.Ephemeral)+len(msg.Static):])
|
||||||
|
copy(msg.MAC1[:], b[8+len(msg.Ephemeral)+len(msg.Static)+len(msg.Timestamp):])
|
||||||
|
copy(msg.MAC2[:], b[8+len(msg.Ephemeral)+len(msg.Static)+len(msg.Timestamp)+len(msg.MAC1):])
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *MessageResponse) unmarshal(b []byte) error {
|
||||||
|
if len(b) < MessageResponseSize {
|
||||||
|
return errMessageTooShort
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Type = binary.LittleEndian.Uint32(b)
|
||||||
|
msg.Sender = binary.LittleEndian.Uint32(b[4:])
|
||||||
|
msg.Receiver = binary.LittleEndian.Uint32(b[8:])
|
||||||
|
copy(msg.Ephemeral[:], b[12:])
|
||||||
|
copy(msg.Empty[:], b[12+len(msg.Ephemeral):])
|
||||||
|
copy(msg.MAC1[:], b[12+len(msg.Ephemeral)+len(msg.Empty):])
|
||||||
|
copy(msg.MAC2[:], b[12+len(msg.Ephemeral)+len(msg.Empty)+len(msg.MAC1):])
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *MessageCookieReply) unmarshal(b []byte) error {
|
||||||
|
if len(b) < MessageCookieReplySize {
|
||||||
|
return errMessageTooShort
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Type = binary.LittleEndian.Uint32(b)
|
||||||
|
msg.Receiver = binary.LittleEndian.Uint32(b[4:])
|
||||||
|
copy(msg.Nonce[:], b[8:])
|
||||||
|
copy(msg.Cookie[:], b[8+len(msg.Nonce):])
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type Handshake struct {
|
type Handshake struct {
|
||||||
state handshakeState
|
state handshakeState
|
||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
|
|||||||
+3
-7
@@ -6,7 +6,6 @@
|
|||||||
package device
|
package device
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
@@ -287,8 +286,7 @@ func (device *Device) RoutineHandshake(id int) {
|
|||||||
// unmarshal packet
|
// unmarshal packet
|
||||||
|
|
||||||
var reply MessageCookieReply
|
var reply MessageCookieReply
|
||||||
reader := bytes.NewReader(elem.packet)
|
err := reply.unmarshal(elem.packet)
|
||||||
err := binary.Read(reader, binary.LittleEndian, &reply)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
device.log.Verbosef("Failed to decode cookie reply")
|
device.log.Verbosef("Failed to decode cookie reply")
|
||||||
goto skip
|
goto skip
|
||||||
@@ -353,8 +351,7 @@ func (device *Device) RoutineHandshake(id int) {
|
|||||||
// unmarshal
|
// unmarshal
|
||||||
|
|
||||||
var msg MessageInitiation
|
var msg MessageInitiation
|
||||||
reader := bytes.NewReader(elem.packet)
|
err := msg.unmarshal(elem.packet)
|
||||||
err := binary.Read(reader, binary.LittleEndian, &msg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
device.log.Errorf("Failed to decode initiation message")
|
device.log.Errorf("Failed to decode initiation message")
|
||||||
goto skip
|
goto skip
|
||||||
@@ -386,8 +383,7 @@ func (device *Device) RoutineHandshake(id int) {
|
|||||||
// unmarshal
|
// unmarshal
|
||||||
|
|
||||||
var msg MessageResponse
|
var msg MessageResponse
|
||||||
reader := bytes.NewReader(elem.packet)
|
err := msg.unmarshal(elem.packet)
|
||||||
err := binary.Read(reader, binary.LittleEndian, &msg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
device.log.Errorf("Failed to decode response message")
|
device.log.Errorf("Failed to decode response message")
|
||||||
goto skip
|
goto skip
|
||||||
|
|||||||
Reference in New Issue
Block a user