Bucket received frames by their mac receive stamp and read one bucket back
This commit is contained in:
@@ -15,6 +15,52 @@ type rxStats struct {
|
||||
badLen atomic.Uint64
|
||||
crcErr atomic.Uint64
|
||||
rxErrs atomic.Uint64
|
||||
|
||||
// Frames counted into the interval their mac receive stamp falls in, rather
|
||||
// than the interval a worker got round to draining them in.
|
||||
newest atomic.Int64
|
||||
buckets [rateBuckets]rxBucket
|
||||
}
|
||||
|
||||
// One sample interval of arrivals, keyed by the mac's clock, with enough of them
|
||||
// kept that a bucket is read long before its slot comes round again.
|
||||
const (
|
||||
rateBucketNs = int64(sampleInterval)
|
||||
rateBuckets = 64
|
||||
rateBucketSecs = float64(rateBucketNs) / 1e9
|
||||
)
|
||||
|
||||
type rxBucket struct {
|
||||
epoch atomic.Int64
|
||||
frames atomic.Uint64
|
||||
bytes atomic.Uint64
|
||||
}
|
||||
|
||||
// Only the owning worker writes its own buckets, so a slot coming round again is
|
||||
// simply zeroed before it is claimed for the new epoch.
|
||||
func (s *rxStats) observe(stamp int64, n uint64) {
|
||||
e := stamp / rateBucketNs
|
||||
b := &s.buckets[e&(rateBuckets-1)]
|
||||
if b.epoch.Load() != e {
|
||||
b.frames.Store(0)
|
||||
b.bytes.Store(0)
|
||||
b.epoch.Store(e)
|
||||
}
|
||||
b.frames.Add(1)
|
||||
b.bytes.Add(n)
|
||||
if e > s.newest.Load() {
|
||||
s.newest.Store(e)
|
||||
}
|
||||
}
|
||||
|
||||
// What this worker counted into one epoch, or nothing if that epoch has already
|
||||
// fallen out of the ring.
|
||||
func (s *rxStats) bucket(e int64) (frames, bytes uint64) {
|
||||
b := &s.buckets[e&(rateBuckets-1)]
|
||||
if b.epoch.Load() != e {
|
||||
return 0, 0
|
||||
}
|
||||
return b.frames.Load(), b.bytes.Load()
|
||||
}
|
||||
|
||||
type rxWorker struct {
|
||||
@@ -34,11 +80,16 @@ func (w *rxWorker) run(done *atomic.Bool) {
|
||||
bufs[i][j] = 0
|
||||
}
|
||||
}
|
||||
hdrs, _ := newMmsghdrs(bufs)
|
||||
hdrs, oob := newRxMmsghdrs(bufs)
|
||||
|
||||
w.ready.Done()
|
||||
|
||||
for !done.Load() {
|
||||
// The kernel overwrites each Controllen with what it wrote, so they are
|
||||
// reset before every call.
|
||||
for i := range hdrs {
|
||||
hdrs[i].hdr.Controllen = cmsgLen
|
||||
}
|
||||
n, err := recvmmsg(w.fd, hdrs, unix.MSG_WAITFORONE)
|
||||
if n <= 0 {
|
||||
if err != nil && err != unix.EAGAIN && err != unix.EINTR {
|
||||
@@ -55,6 +106,9 @@ func (w *rxWorker) run(done *atomic.Bool) {
|
||||
}
|
||||
w.stats.frames.Add(1)
|
||||
w.stats.bytes.Add(uint64(len(buf)))
|
||||
if ts, ok := hwTimestamp(oob[i][:hdrs[i].hdr.Controllen]); ok {
|
||||
w.stats.observe(ts, uint64(len(buf)))
|
||||
}
|
||||
|
||||
if int(p.stream) < len(w.streams) {
|
||||
w.streams[p.stream].observe(p.seq)
|
||||
|
||||
Reference in New Issue
Block a user