Files
xtaci 2693fa8e71 perf: reduce heap allocations and fix memory leaks across multiple components
Optimizations:
- ringbuffer: optimize Len(), IsEmpty(), Discard(), Clear() methods with
  branchless arithmetic and simplified logic
- fec: fix memory leak in shardHeap.Pop() by setting element to nil before
  truncating slice, preventing GC from holding stale references
- timedsched: fix memory leak in timedFuncHeap.Pop() with same nil-before-truncate
  pattern; optimize prepend() using slice swap instead of append
- autotune: add sortCache field to Autotuner to reuse slice allocation in
  FindPeriod(), avoiding repeated allocations during period detection
- snmp: replace fmt.Sprint with strconv.FormatUint for better performance
  in Copy() and Reset() methods
- entropy: remove defer overhead in rngAES.Read() and rngChacha8.Read()
  hot paths for reduced function call cost
- bufferpool: pre-allocate ErrBufferPoolSizeExceeded error; reset slice
  length on Put() to allow proper reuse
- sess: remove defer overhead in 6 setter methods (SetWriteDelay,
  SetWindowSize, SetStreamMode, SetACKNoDelay, SetDUP, SetNoDelay)

These changes reduce memory allocations, fix potential memory leaks in
heap-based data structures, and eliminate defer overhead in frequently
called methods.
2026-01-29 12:22:33 +08:00

217 lines
8.0 KiB
Go

// The MIT License (MIT)
//
// Copyright (c) 2015 xtaci
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package kcp
import (
"strconv"
"sync/atomic"
)
// Snmp defines network statistics indicator
type Snmp struct {
BytesSent uint64 // bytes sent from upper level
BytesReceived uint64 // bytes received to upper level
MaxConn uint64 // max number of connections ever reached
ActiveOpens uint64 // accumulated active open connections
PassiveOpens uint64 // accumulated passive open connections
CurrEstab uint64 // current number of established connections
InErrs uint64 // UDP read errors reported from net.PacketConn
InCsumErrors uint64 // checksum errors from CRC32
KCPInErrors uint64 // packet iput errors reported from KCP
InPkts uint64 // incoming packets count
OutPkts uint64 // outgoing packets count
InSegs uint64 // incoming KCP segments
OutSegs uint64 // outgoing KCP segments
InBytes uint64 // UDP bytes received
OutBytes uint64 // UDP bytes sent
RetransSegs uint64 // accmulated retransmited segments
FastRetransSegs uint64 // accmulated fast retransmitted segments
EarlyRetransSegs uint64 // accmulated early retransmitted segments
LostSegs uint64 // number of segs inferred as lost
RepeatSegs uint64 // number of segs duplicated
FECFullShardSet uint64 // number of FEC segments that are full
FECRecovered uint64 // correct packets recovered from FEC
FECErrs uint64 // incorrect packets recovered from FEC
FECParityShards uint64 // FEC segments received
FECShardSet uint64 // number of parity shards that are not yet received
FECShardMin uint64 // the minimum ID of FEC shards
RingBufferSndQueue uint64 // Len of segments in send queue ring buffer
RingBufferRcvQueue uint64 // Len of segments in receive queue ring buffer
RingBufferSndBuffer uint64 // Len of segments in send buffer ring buffer
OOBPackets uint64 // number of OOB packets received
}
func newSnmp() *Snmp {
return new(Snmp)
}
// Header returns all field names
func (s *Snmp) Header() []string {
return []string{
"BytesSent",
"BytesReceived",
"MaxConn",
"ActiveOpens",
"PassiveOpens",
"CurrEstab",
"InErrs",
"InCsumErrors",
"KCPInErrors",
"InPkts",
"OutPkts",
"InSegs",
"OutSegs",
"InBytes",
"OutBytes",
"RetransSegs",
"FastRetransSegs",
"EarlyRetransSegs",
"LostSegs",
"RepeatSegs",
"FECFullShards",
"FECParityShards",
"FECErrs",
"FECRecovered",
"FECShardSet",
"FECShardMin",
"RingBufferSndQueue",
"RingBufferRcvQueue",
"RingBufferSndBuffer",
"OOBPackets",
}
}
// ToSlice returns current snmp info as slice
func (s *Snmp) ToSlice() []string {
snmp := s.Copy()
return []string{
strconv.FormatUint(snmp.BytesSent, 10),
strconv.FormatUint(snmp.BytesReceived, 10),
strconv.FormatUint(snmp.MaxConn, 10),
strconv.FormatUint(snmp.ActiveOpens, 10),
strconv.FormatUint(snmp.PassiveOpens, 10),
strconv.FormatUint(snmp.CurrEstab, 10),
strconv.FormatUint(snmp.InErrs, 10),
strconv.FormatUint(snmp.InCsumErrors, 10),
strconv.FormatUint(snmp.KCPInErrors, 10),
strconv.FormatUint(snmp.InPkts, 10),
strconv.FormatUint(snmp.OutPkts, 10),
strconv.FormatUint(snmp.InSegs, 10),
strconv.FormatUint(snmp.OutSegs, 10),
strconv.FormatUint(snmp.InBytes, 10),
strconv.FormatUint(snmp.OutBytes, 10),
strconv.FormatUint(snmp.RetransSegs, 10),
strconv.FormatUint(snmp.FastRetransSegs, 10),
strconv.FormatUint(snmp.EarlyRetransSegs, 10),
strconv.FormatUint(snmp.LostSegs, 10),
strconv.FormatUint(snmp.RepeatSegs, 10),
strconv.FormatUint(snmp.FECFullShardSet, 10),
strconv.FormatUint(snmp.FECParityShards, 10),
strconv.FormatUint(snmp.FECErrs, 10),
strconv.FormatUint(snmp.FECRecovered, 10),
strconv.FormatUint(snmp.FECShardSet, 10),
strconv.FormatUint(snmp.FECShardMin, 10),
strconv.FormatUint(snmp.RingBufferSndQueue, 10),
strconv.FormatUint(snmp.RingBufferRcvQueue, 10),
strconv.FormatUint(snmp.RingBufferSndBuffer, 10),
strconv.FormatUint(snmp.OOBPackets, 10),
}
}
// Copy make a copy of current snmp snapshot
func (s *Snmp) Copy() *Snmp {
d := newSnmp()
d.BytesSent = atomic.LoadUint64(&s.BytesSent)
d.BytesReceived = atomic.LoadUint64(&s.BytesReceived)
d.MaxConn = atomic.LoadUint64(&s.MaxConn)
d.ActiveOpens = atomic.LoadUint64(&s.ActiveOpens)
d.PassiveOpens = atomic.LoadUint64(&s.PassiveOpens)
d.CurrEstab = atomic.LoadUint64(&s.CurrEstab)
d.InErrs = atomic.LoadUint64(&s.InErrs)
d.InCsumErrors = atomic.LoadUint64(&s.InCsumErrors)
d.KCPInErrors = atomic.LoadUint64(&s.KCPInErrors)
d.InPkts = atomic.LoadUint64(&s.InPkts)
d.OutPkts = atomic.LoadUint64(&s.OutPkts)
d.InSegs = atomic.LoadUint64(&s.InSegs)
d.OutSegs = atomic.LoadUint64(&s.OutSegs)
d.InBytes = atomic.LoadUint64(&s.InBytes)
d.OutBytes = atomic.LoadUint64(&s.OutBytes)
d.RetransSegs = atomic.LoadUint64(&s.RetransSegs)
d.FastRetransSegs = atomic.LoadUint64(&s.FastRetransSegs)
d.EarlyRetransSegs = atomic.LoadUint64(&s.EarlyRetransSegs)
d.LostSegs = atomic.LoadUint64(&s.LostSegs)
d.RepeatSegs = atomic.LoadUint64(&s.RepeatSegs)
d.FECFullShardSet = atomic.LoadUint64(&s.FECFullShardSet)
d.FECParityShards = atomic.LoadUint64(&s.FECParityShards)
d.FECErrs = atomic.LoadUint64(&s.FECErrs)
d.FECRecovered = atomic.LoadUint64(&s.FECRecovered)
d.FECShardSet = atomic.LoadUint64(&s.FECShardSet)
d.FECShardMin = atomic.LoadUint64(&s.FECShardMin)
d.RingBufferSndQueue = atomic.LoadUint64(&s.RingBufferSndQueue)
d.RingBufferRcvQueue = atomic.LoadUint64(&s.RingBufferRcvQueue)
d.RingBufferSndBuffer = atomic.LoadUint64(&s.RingBufferSndBuffer)
d.OOBPackets = atomic.LoadUint64(&s.OOBPackets)
return d
}
// Reset values to zero
func (s *Snmp) Reset() {
atomic.StoreUint64(&s.BytesSent, 0)
atomic.StoreUint64(&s.BytesReceived, 0)
atomic.StoreUint64(&s.MaxConn, 0)
atomic.StoreUint64(&s.ActiveOpens, 0)
atomic.StoreUint64(&s.PassiveOpens, 0)
atomic.StoreUint64(&s.CurrEstab, 0)
atomic.StoreUint64(&s.InErrs, 0)
atomic.StoreUint64(&s.InCsumErrors, 0)
atomic.StoreUint64(&s.KCPInErrors, 0)
atomic.StoreUint64(&s.InPkts, 0)
atomic.StoreUint64(&s.OutPkts, 0)
atomic.StoreUint64(&s.InSegs, 0)
atomic.StoreUint64(&s.OutSegs, 0)
atomic.StoreUint64(&s.InBytes, 0)
atomic.StoreUint64(&s.OutBytes, 0)
atomic.StoreUint64(&s.RetransSegs, 0)
atomic.StoreUint64(&s.FastRetransSegs, 0)
atomic.StoreUint64(&s.EarlyRetransSegs, 0)
atomic.StoreUint64(&s.LostSegs, 0)
atomic.StoreUint64(&s.RepeatSegs, 0)
atomic.StoreUint64(&s.FECFullShardSet, 0)
atomic.StoreUint64(&s.FECParityShards, 0)
atomic.StoreUint64(&s.FECErrs, 0)
atomic.StoreUint64(&s.FECRecovered, 0)
atomic.StoreUint64(&s.FECShardSet, 0)
atomic.StoreUint64(&s.FECShardMin, 0)
atomic.StoreUint64(&s.RingBufferSndQueue, 0)
atomic.StoreUint64(&s.RingBufferRcvQueue, 0)
atomic.StoreUint64(&s.RingBufferSndBuffer, 0)
atomic.StoreUint64(&s.OOBPackets, 0)
}
// DefaultSnmp is the global KCP connection statistics collector
var DefaultSnmp *Snmp
func init() {
DefaultSnmp = newSnmp()
}