Rework packetcache loss statistics.
Don't maintain loss, which is too error-prone. Instead, maintain expected and received packet counts, and compute loss from that.
This commit is contained in:
+30
-18
@@ -48,12 +48,13 @@ type frame struct {
|
||||
type Cache struct {
|
||||
mu sync.Mutex
|
||||
//stats
|
||||
last uint16
|
||||
cycle uint16
|
||||
lastValid bool
|
||||
expected uint32
|
||||
lost uint32
|
||||
totalLost uint32
|
||||
last uint16
|
||||
cycle uint16
|
||||
lastValid bool
|
||||
expected uint32
|
||||
totalExpected uint32
|
||||
received uint32
|
||||
totalReceived uint32
|
||||
// bitmap
|
||||
bitmap bitmap
|
||||
// buffered keyframe
|
||||
@@ -259,18 +260,19 @@ func (cache *Cache) Store(seqno uint16, timestamp uint32, keyframe bool, marker
|
||||
cache.last = seqno
|
||||
cache.lastValid = true
|
||||
cache.expected++
|
||||
cache.received++
|
||||
} else {
|
||||
cmp := compare(cache.last, seqno)
|
||||
if cmp < 0 {
|
||||
cache.received++
|
||||
cache.expected += uint32(seqno - cache.last)
|
||||
cache.lost += uint32(seqno - cache.last - 1)
|
||||
if seqno < cache.last {
|
||||
cache.cycle++
|
||||
}
|
||||
cache.last = seqno
|
||||
} else if cmp > 0 {
|
||||
if cache.lost > 0 {
|
||||
cache.lost--
|
||||
if cache.received < cache.expected {
|
||||
cache.received++
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -355,7 +357,6 @@ func (cache *Cache) Expect(n int) {
|
||||
cache.mu.Lock()
|
||||
defer cache.mu.Unlock()
|
||||
cache.expected += uint32(n)
|
||||
cache.lost += uint32(n)
|
||||
}
|
||||
|
||||
// get retrieves a packet from a slice of entries.
|
||||
@@ -510,23 +511,34 @@ func (cache *Cache) ResizeCond(capacity int) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Stats contains cache statistics
|
||||
type Stats struct {
|
||||
Received, TotalReceived uint32
|
||||
Expected, TotalExpected uint32
|
||||
ESeqno uint32
|
||||
}
|
||||
|
||||
// GetStats returns statistics about received packets. If reset is true,
|
||||
// the statistics are reset.
|
||||
func (cache *Cache) GetStats(reset bool) (uint32, uint32, uint32, uint32) {
|
||||
func (cache *Cache) GetStats(reset bool) Stats {
|
||||
cache.mu.Lock()
|
||||
defer cache.mu.Unlock()
|
||||
|
||||
expected := cache.expected
|
||||
lost := cache.lost
|
||||
totalLost := cache.totalLost + cache.lost
|
||||
eseqno := uint32(cache.cycle)<<16 | uint32(cache.last)
|
||||
s := Stats{
|
||||
Received: cache.received,
|
||||
TotalReceived: cache.totalReceived + cache.received,
|
||||
Expected: cache.expected,
|
||||
TotalExpected: cache.totalExpected + cache.expected,
|
||||
ESeqno: uint32(cache.cycle)<<16 | uint32(cache.last),
|
||||
}
|
||||
|
||||
if reset {
|
||||
cache.totalExpected += cache.expected
|
||||
cache.expected = 0
|
||||
cache.totalLost += cache.lost
|
||||
cache.lost = 0
|
||||
cache.totalReceived += cache.received
|
||||
cache.received = 0
|
||||
}
|
||||
return expected, lost, totalLost, eseqno
|
||||
return s
|
||||
}
|
||||
|
||||
// ToBitmap takes a non-empty sorted list of seqnos, and computes a bitmap
|
||||
|
||||
@@ -499,13 +499,13 @@ func TestCacheStatsFull(t *testing.T) {
|
||||
for i := 0; i < 32; i++ {
|
||||
cache.Store(uint16(i), 0, false, false, []byte{uint8(i)})
|
||||
}
|
||||
expected, lost, totalLost, eseqno := cache.GetStats(false)
|
||||
if expected != 32 ||
|
||||
lost != 0 ||
|
||||
totalLost != 0 ||
|
||||
eseqno != 31 {
|
||||
t.Errorf("Expected 32, 0, 0, 31, got %v, %v, %v, %v",
|
||||
expected, lost, totalLost, eseqno)
|
||||
stats := cache.GetStats(false)
|
||||
if stats.Received != 32 ||
|
||||
stats.TotalReceived != 32 ||
|
||||
stats.Expected != 32 ||
|
||||
stats.TotalExpected != 32 ||
|
||||
stats.ESeqno != 31 {
|
||||
t.Errorf("Expected 32, 32, 32, 32, 31, got %v", stats)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,13 +516,13 @@ func TestCacheStatsDrop(t *testing.T) {
|
||||
cache.Store(uint16(i), 0, false, false, []byte{uint8(i)})
|
||||
}
|
||||
}
|
||||
expected, lost, totalLost, eseqno := cache.GetStats(false)
|
||||
if expected != 32 ||
|
||||
lost != 2 ||
|
||||
totalLost != 2 ||
|
||||
eseqno != 31 {
|
||||
t.Errorf("Expected 32, 1, 1, 31, got %v, %v, %v, %v",
|
||||
expected, lost, totalLost, eseqno)
|
||||
stats := cache.GetStats(false)
|
||||
if stats.Received != 30 ||
|
||||
stats.TotalReceived != 30 ||
|
||||
stats.Expected != 32 ||
|
||||
stats.TotalExpected != 32 ||
|
||||
stats.ESeqno != 31 {
|
||||
t.Errorf("Expected 30, 30, 32, 32, 31, got %v", stats)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,13 +535,13 @@ func TestCacheStatsUnordered(t *testing.T) {
|
||||
}
|
||||
cache.Store(uint16(8), 0, false, false, []byte{8})
|
||||
cache.Store(uint16(10), 0, false, false, []byte{10})
|
||||
expected, lost, totalLost, eseqno := cache.GetStats(false)
|
||||
if expected != 32 ||
|
||||
lost != 0 ||
|
||||
totalLost != 0 ||
|
||||
eseqno != 31 {
|
||||
t.Errorf("Expected 32, 0, 0, 31, got %v, %v, %v, %v",
|
||||
expected, lost, totalLost, eseqno)
|
||||
stats := cache.GetStats(false)
|
||||
if stats.Received != 32 ||
|
||||
stats.TotalReceived != 32 ||
|
||||
stats.Expected != 32 ||
|
||||
stats.TotalExpected != 32 ||
|
||||
stats.ESeqno != 31 {
|
||||
t.Errorf("Expected 32, 32, 32, 32, 31, got %v", stats)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,12 +555,12 @@ func TestCacheStatsNack(t *testing.T) {
|
||||
cache.Expect(2)
|
||||
cache.Store(uint16(8), 0, false, false, []byte{8})
|
||||
cache.Store(uint16(10), 0, false, false, []byte{10})
|
||||
expected, lost, totalLost, eseqno := cache.GetStats(false)
|
||||
if expected != 34 ||
|
||||
lost != 2 ||
|
||||
totalLost != 2 ||
|
||||
eseqno != 31 {
|
||||
t.Errorf("Expected 34, 2, 2, 31, got %v, %v, %v, %v",
|
||||
expected, lost, totalLost, eseqno)
|
||||
stats := cache.GetStats(false)
|
||||
if stats.Received != 32 ||
|
||||
stats.TotalReceived != 32 ||
|
||||
stats.Expected != 34 ||
|
||||
stats.TotalExpected != 34 ||
|
||||
stats.ESeqno != 31 {
|
||||
t.Errorf("Expected 32, 32, 34, 34, 31, got %v", stats)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user