status-im/status-go

View on GitHub
wakuv2/common/stats.go

Summary

Maintainability
D
1 day
Test Coverage
package common

import (
    "sync"
    "time"

    "github.com/ethereum/go-ethereum/rlp"
    "github.com/status-im/status-go/eth-node/types"
)

type Measure struct {
    Timestamp int64
    Size      uint64
}

type StatsTracker struct {
    Uploads   []Measure
    Downloads []Measure

    statsMutex sync.Mutex
}

const measurementPeriod = 15 * time.Second

func measure(input interface{}) (*Measure, error) {
    b, err := rlp.EncodeToBytes(input)
    if err != nil {
        return nil, err
    }
    return &Measure{
        Timestamp: time.Now().UnixNano(),
        Size:      uint64(len(b)),
    }, nil

}

func (s *StatsTracker) AddUpload(input interface{}) {
    go func(input interface{}) {
        m, err := measure(input)
        if err != nil {
            return
        }

        s.statsMutex.Lock()
        defer s.statsMutex.Unlock()
        s.Uploads = append(s.Uploads, *m)
    }(input)
}

func (s *StatsTracker) AddDownload(input interface{}) {
    go func(input interface{}) {
        m, err := measure(input)
        if err != nil {
            return
        }

        s.statsMutex.Lock()
        defer s.statsMutex.Unlock()
        s.Downloads = append(s.Downloads, *m)
    }(input)
}

func (s *StatsTracker) AddUploadBytes(size uint64) {
    go func(size uint64) {
        m := Measure{
            Timestamp: time.Now().UnixNano(),
            Size:      size,
        }

        s.statsMutex.Lock()
        defer s.statsMutex.Unlock()
        s.Uploads = append(s.Uploads, m)
    }(size)
}

func (s *StatsTracker) AddDownloadBytes(size uint64) {
    go func(size uint64) {
        m := Measure{
            Timestamp: time.Now().UnixNano(),
            Size:      size,
        }

        s.statsMutex.Lock()
        defer s.statsMutex.Unlock()
        s.Downloads = append(s.Downloads, m)
    }(size)
}

func calculateAverage(measures []Measure, minTime int64) (validMeasures []Measure, rate uint64) {
    for _, m := range measures {
        if m.Timestamp > minTime {
            // Only use recent measures
            validMeasures = append(validMeasures, m)
            rate += m.Size
        }
    }

    rate /= (uint64(measurementPeriod) / uint64(1*time.Second))
    return
}

func (s *StatsTracker) GetRatePerSecond() (uploadRate uint64, downloadRate uint64) {
    s.statsMutex.Lock()
    defer s.statsMutex.Unlock()
    minTime := time.Now().Add(-measurementPeriod).UnixNano()
    s.Uploads, uploadRate = calculateAverage(s.Uploads, minTime)
    s.Downloads, downloadRate = calculateAverage(s.Downloads, minTime)
    return
}

func (s *StatsTracker) GetStats() types.StatsSummary {
    uploadRate, downloadRate := s.GetRatePerSecond()
    summary := types.StatsSummary{
        UploadRate:   uploadRate,
        DownloadRate: downloadRate,
    }
    return summary
}