Skip to content

Commit

Permalink
use a sync.Pool to avoid allocations of ackhandler.Packet
Browse files Browse the repository at this point in the history
  • Loading branch information
marten-seemann committed Aug 29, 2022
1 parent fd38fe4 commit 3207222
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 29 deletions.
20 changes: 0 additions & 20 deletions internal/ackhandler/interfaces.go
Expand Up @@ -7,26 +7,6 @@ import (
"github.com/lucas-clemente/quic-go/internal/wire"
)

// A Packet is a packet
type Packet struct {
PacketNumber protocol.PacketNumber
Frames []Frame
LargestAcked protocol.PacketNumber // InvalidPacketNumber if the packet doesn't contain an ACK
Length protocol.ByteCount
EncryptionLevel protocol.EncryptionLevel
SendTime time.Time

IsPathMTUProbePacket bool // We don't report the loss of Path MTU probe packets to the congestion controller.

includedInBytesInFlight bool
declaredLost bool
skippedPacket bool
}

func (p *Packet) outstanding() bool {
return !p.declaredLost && !p.skippedPacket && !p.IsPathMTUProbePacket
}

// SentPacketHandler handles ACKs received for outgoing packets
type SentPacketHandler interface {
// SentPacket may modify the packet
Expand Down
49 changes: 49 additions & 0 deletions internal/ackhandler/packet.go
@@ -0,0 +1,49 @@
package ackhandler

import (
"sync"
"time"

"github.com/lucas-clemente/quic-go/internal/protocol"
)

// A Packet is a packet
type Packet struct {
PacketNumber protocol.PacketNumber
Frames []Frame
LargestAcked protocol.PacketNumber // InvalidPacketNumber if the packet doesn't contain an ACK
Length protocol.ByteCount
EncryptionLevel protocol.EncryptionLevel
SendTime time.Time

IsPathMTUProbePacket bool // We don't report the loss of Path MTU probe packets to the congestion controller.

includedInBytesInFlight bool
declaredLost bool
skippedPacket bool
}

func (p *Packet) outstanding() bool {
return !p.declaredLost && !p.skippedPacket && !p.IsPathMTUProbePacket
}

var packetPool = sync.Pool{New: func() any { return &Packet{} }}

func GetPacket() *Packet {
p := packetPool.Get().(*Packet)
p.PacketNumber = 0
p.Frames = nil
p.LargestAcked = 0
p.Length = 0
p.EncryptionLevel = protocol.EncryptionLevel(0)
p.SendTime = time.Time{}
p.IsPathMTUProbePacket = false
p.includedInBytesInFlight = false
p.declaredLost = false
p.skippedPacket = false
return p
}

// We currently only return Packets back into the pool when they're acknowledged (not when they're lost).
// This simplifies the code, and gives the vast majority of the performance benefit we can gain from using the pool.
func putPacket(p *Packet) { packetPool.Put(p) }
4 changes: 4 additions & 0 deletions internal/ackhandler/sent_packet_handler.go
Expand Up @@ -334,7 +334,11 @@ func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.En
acked1RTTPacket = true
}
h.removeFromBytesInFlight(p)
putPacket(p)
}
// After this point, we must not use ackedPackets any longer!
// We've already returned the buffers.
ackedPackets = nil

// Reset the pto_count unless the client is unsure if the server has validated the client's address.
if h.peerCompletedAddressValidation {
Expand Down
19 changes: 10 additions & 9 deletions packet_packer.go
Expand Up @@ -100,15 +100,16 @@ func (p *packetContents) ToAckHandlerPacket(now time.Time, q *retransmissionQueu
p.frames[i].OnLost = q.AddAppData
}
}
return &ackhandler.Packet{
PacketNumber: p.header.PacketNumber,
LargestAcked: largestAcked,
Frames: p.frames,
Length: p.length,
EncryptionLevel: encLevel,
SendTime: now,
IsPathMTUProbePacket: p.isMTUProbePacket,
}

ap := ackhandler.GetPacket()
ap.PacketNumber = p.header.PacketNumber
ap.LargestAcked = largestAcked
ap.Frames = p.frames
ap.Length = p.length
ap.EncryptionLevel = encLevel
ap.SendTime = now
ap.IsPathMTUProbePacket = p.isMTUProbePacket
return ap
}

func getMaxPacketSize(addr net.Addr) protocol.ByteCount {
Expand Down

0 comments on commit 3207222

Please sign in to comment.