improve Stats performance (#839)

Build aggregated statistics by using already-available data.
This commit is contained in:
Alessandro Ros
2025-07-26 14:01:17 +02:00
committed by GitHub
parent c36d441583
commit 63f7ffc3e3
3 changed files with 259 additions and 263 deletions

187
client.go
View File

@@ -2311,101 +2311,7 @@ func (c *Client) PacketNTP(medi *description.Media, pkt *rtp.Packet) (time.Time,
// Stats returns client statistics. // Stats returns client statistics.
func (c *Client) Stats() *ClientStats { func (c *Client) Stats() *ClientStats {
return &ClientStats{ mediaStats := func() map[*description.Media]StatsSessionMedia { //nolint:dupl
Conn: StatsConn{
BytesReceived: atomic.LoadUint64(c.bytesReceived),
BytesSent: atomic.LoadUint64(c.bytesSent),
},
Session: StatsSession{
BytesReceived: func() uint64 {
v := uint64(0)
for _, sm := range c.setuppedMedias {
v += atomic.LoadUint64(sm.bytesReceived)
}
return v
}(),
BytesSent: func() uint64 {
v := uint64(0)
for _, sm := range c.setuppedMedias {
v += atomic.LoadUint64(sm.bytesSent)
}
return v
}(),
RTPPacketsReceived: func() uint64 {
v := uint64(0)
for _, sm := range c.setuppedMedias {
for _, f := range sm.formats {
v += atomic.LoadUint64(f.rtpPacketsReceived)
}
}
return v
}(),
RTPPacketsSent: func() uint64 {
v := uint64(0)
for _, sm := range c.setuppedMedias {
for _, f := range sm.formats {
v += atomic.LoadUint64(f.rtpPacketsSent)
}
}
return v
}(),
RTPPacketsLost: func() uint64 {
v := uint64(0)
for _, sm := range c.setuppedMedias {
for _, f := range sm.formats {
v += atomic.LoadUint64(f.rtpPacketsLost)
}
}
return v
}(),
RTPPacketsInError: func() uint64 {
v := uint64(0)
for _, sm := range c.setuppedMedias {
v += atomic.LoadUint64(sm.rtpPacketsInError)
}
return v
}(),
RTPPacketsJitter: func() float64 {
v := float64(0)
n := float64(0)
for _, sm := range c.setuppedMedias {
for _, fo := range sm.formats {
if fo.rtcpReceiver != nil {
stats := fo.rtcpReceiver.Stats()
if stats != nil {
v += stats.Jitter
n++
}
}
}
}
if n != 0 {
return v / n
}
return 0
}(),
RTCPPacketsReceived: func() uint64 {
v := uint64(0)
for _, sm := range c.setuppedMedias {
v += atomic.LoadUint64(sm.rtcpPacketsReceived)
}
return v
}(),
RTCPPacketsSent: func() uint64 {
v := uint64(0)
for _, sm := range c.setuppedMedias {
v += atomic.LoadUint64(sm.rtcpPacketsSent)
}
return v
}(),
RTCPPacketsInError: func() uint64 {
v := uint64(0)
for _, sm := range c.setuppedMedias {
v += atomic.LoadUint64(sm.rtcpPacketsInError)
}
return v
}(),
Medias: func() map[*description.Media]StatsSessionMedia { //nolint:dupl
ret := make(map[*description.Media]StatsSessionMedia, len(c.setuppedMedias)) ret := make(map[*description.Media]StatsSessionMedia, len(c.setuppedMedias))
for med, sm := range c.setuppedMedias { for med, sm := range c.setuppedMedias {
@@ -2486,7 +2392,98 @@ func (c *Client) Stats() *ClientStats {
} }
return ret return ret
}()
return &ClientStats{
Conn: StatsConn{
BytesReceived: atomic.LoadUint64(c.bytesReceived),
BytesSent: atomic.LoadUint64(c.bytesSent),
},
Session: StatsSession{ //nolint:dupl
BytesReceived: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.BytesReceived
}
return v
}(), }(),
BytesSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.BytesSent
}
return v
}(),
RTPPacketsReceived: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsReceived
}
}
return v
}(),
RTPPacketsSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsSent
}
}
return v
}(),
RTPPacketsLost: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsLost
}
}
return v
}(),
RTPPacketsInError: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTPPacketsInError
}
return v
}(),
RTPPacketsJitter: func() float64 {
v := float64(0)
n := float64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsJitter
n++
}
}
if n != 0 {
return v / n
}
return 0
}(),
RTCPPacketsReceived: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTCPPacketsReceived
}
return v
}(),
RTCPPacketsSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTCPPacketsSent
}
return v
}(),
RTCPPacketsInError: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTCPPacketsInError
}
return v
}(),
Medias: mediaStats,
}, },
} }
} }

View File

@@ -561,96 +561,7 @@ func (ss *ServerSession) UserData() interface{} {
// Stats returns server session statistics. // Stats returns server session statistics.
func (ss *ServerSession) Stats() *StatsSession { func (ss *ServerSession) Stats() *StatsSession {
return &StatsSession{ mediaStats := func() map[*description.Media]StatsSessionMedia { //nolint:dupl
BytesReceived: func() uint64 {
v := uint64(0)
for _, sm := range ss.setuppedMedias {
v += atomic.LoadUint64(sm.bytesReceived)
}
return v
}(),
BytesSent: func() uint64 {
v := uint64(0)
for _, sm := range ss.setuppedMedias {
v += atomic.LoadUint64(sm.bytesSent)
}
return v
}(),
RTPPacketsReceived: func() uint64 {
v := uint64(0)
for _, sm := range ss.setuppedMedias {
for _, f := range sm.formats {
v += atomic.LoadUint64(f.rtpPacketsReceived)
}
}
return v
}(),
RTPPacketsSent: func() uint64 {
v := uint64(0)
for _, sm := range ss.setuppedMedias {
for _, f := range sm.formats {
v += atomic.LoadUint64(f.rtpPacketsSent)
}
}
return v
}(),
RTPPacketsLost: func() uint64 {
v := uint64(0)
for _, sm := range ss.setuppedMedias {
for _, f := range sm.formats {
v += atomic.LoadUint64(f.rtpPacketsLost)
}
}
return v
}(),
RTPPacketsInError: func() uint64 {
v := uint64(0)
for _, sm := range ss.setuppedMedias {
v += atomic.LoadUint64(sm.rtpPacketsInError)
}
return v
}(),
RTPPacketsJitter: func() float64 {
v := float64(0)
n := float64(0)
for _, sm := range ss.setuppedMedias {
for _, fo := range sm.formats {
if fo.rtcpReceiver != nil {
stats := fo.rtcpReceiver.Stats()
if stats != nil {
v += stats.Jitter
n++
}
}
}
}
if n != 0 {
return v / n
}
return 0
}(),
RTCPPacketsReceived: func() uint64 {
v := uint64(0)
for _, sm := range ss.setuppedMedias {
v += atomic.LoadUint64(sm.rtcpPacketsReceived)
}
return v
}(),
RTCPPacketsSent: func() uint64 {
v := uint64(0)
for _, sm := range ss.setuppedMedias {
v += atomic.LoadUint64(sm.rtcpPacketsSent)
}
return v
}(),
RTCPPacketsInError: func() uint64 {
v := uint64(0)
for _, sm := range ss.setuppedMedias {
v += atomic.LoadUint64(sm.rtcpPacketsInError)
}
return v
}(),
Medias: func() map[*description.Media]StatsSessionMedia { //nolint:dupl
ret := make(map[*description.Media]StatsSessionMedia, len(ss.setuppedMedias)) ret := make(map[*description.Media]StatsSessionMedia, len(ss.setuppedMedias))
for med, sm := range ss.setuppedMedias { for med, sm := range ss.setuppedMedias {
@@ -737,7 +648,93 @@ func (ss *ServerSession) Stats() *StatsSession {
} }
return ret return ret
}()
return &StatsSession{ //nolint:dupl
BytesReceived: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.BytesReceived
}
return v
}(), }(),
BytesSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.BytesSent
}
return v
}(),
RTPPacketsReceived: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsReceived
}
}
return v
}(),
RTPPacketsSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsSent
}
}
return v
}(),
RTPPacketsLost: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsLost
}
}
return v
}(),
RTPPacketsInError: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTPPacketsInError
}
return v
}(),
RTPPacketsJitter: func() float64 {
v := float64(0)
n := float64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsJitter
n++
}
}
if n != 0 {
return v / n
}
return 0
}(),
RTCPPacketsReceived: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTCPPacketsReceived
}
return v
}(),
RTCPPacketsSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTCPPacketsSent
}
return v
}(),
RTCPPacketsInError: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTCPPacketsInError
}
return v
}(),
Medias: mediaStats,
} }
} }

View File

@@ -111,31 +111,7 @@ func (st *ServerStream) Description() *description.Session {
// Stats returns stream statistics. // Stats returns stream statistics.
func (st *ServerStream) Stats() *ServerStreamStats { func (st *ServerStream) Stats() *ServerStreamStats {
return &ServerStreamStats{ mediaStats := func() map[*description.Media]ServerStreamStatsMedia {
BytesSent: func() uint64 {
v := uint64(0)
for _, me := range st.medias {
v += atomic.LoadUint64(me.bytesSent)
}
return v
}(),
RTPPacketsSent: func() uint64 {
v := uint64(0)
for _, me := range st.medias {
for _, f := range me.formats {
v += atomic.LoadUint64(f.rtpPacketsSent)
}
}
return v
}(),
RTCPPacketsSent: func() uint64 {
v := uint64(0)
for _, me := range st.medias {
v += atomic.LoadUint64(me.rtcpPacketsSent)
}
return v
}(),
Medias: func() map[*description.Media]ServerStreamStatsMedia {
ret := make(map[*description.Media]ServerStreamStatsMedia, len(st.medias)) ret := make(map[*description.Media]ServerStreamStatsMedia, len(st.medias))
for med, sm := range st.medias { for med, sm := range st.medias {
@@ -158,7 +134,33 @@ func (st *ServerStream) Stats() *ServerStreamStats {
} }
return ret return ret
}()
return &ServerStreamStats{
BytesSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.BytesSent
}
return v
}(), }(),
RTPPacketsSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsSent
}
}
return v
}(),
RTCPPacketsSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTCPPacketsSent
}
return v
}(),
Medias: mediaStats,
} }
} }