github.com/status-im/status-go@v1.1.0/wakuv2/common/stats.go (about)

     1  package common
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	"github.com/ethereum/go-ethereum/rlp"
     8  	"github.com/status-im/status-go/eth-node/types"
     9  )
    10  
    11  type Measure struct {
    12  	Timestamp int64
    13  	Size      uint64
    14  }
    15  
    16  type StatsTracker struct {
    17  	Uploads   []Measure
    18  	Downloads []Measure
    19  
    20  	statsMutex sync.Mutex
    21  }
    22  
    23  const measurementPeriod = 15 * time.Second
    24  
    25  func measure(input interface{}) (*Measure, error) {
    26  	b, err := rlp.EncodeToBytes(input)
    27  	if err != nil {
    28  		return nil, err
    29  	}
    30  	return &Measure{
    31  		Timestamp: time.Now().UnixNano(),
    32  		Size:      uint64(len(b)),
    33  	}, nil
    34  
    35  }
    36  
    37  func (s *StatsTracker) AddUpload(input interface{}) {
    38  	go func(input interface{}) {
    39  		m, err := measure(input)
    40  		if err != nil {
    41  			return
    42  		}
    43  
    44  		s.statsMutex.Lock()
    45  		defer s.statsMutex.Unlock()
    46  		s.Uploads = append(s.Uploads, *m)
    47  	}(input)
    48  }
    49  
    50  func (s *StatsTracker) AddDownload(input interface{}) {
    51  	go func(input interface{}) {
    52  		m, err := measure(input)
    53  		if err != nil {
    54  			return
    55  		}
    56  
    57  		s.statsMutex.Lock()
    58  		defer s.statsMutex.Unlock()
    59  		s.Downloads = append(s.Downloads, *m)
    60  	}(input)
    61  }
    62  
    63  func (s *StatsTracker) AddUploadBytes(size uint64) {
    64  	go func(size uint64) {
    65  		m := Measure{
    66  			Timestamp: time.Now().UnixNano(),
    67  			Size:      size,
    68  		}
    69  
    70  		s.statsMutex.Lock()
    71  		defer s.statsMutex.Unlock()
    72  		s.Uploads = append(s.Uploads, m)
    73  	}(size)
    74  }
    75  
    76  func (s *StatsTracker) AddDownloadBytes(size uint64) {
    77  	go func(size uint64) {
    78  		m := Measure{
    79  			Timestamp: time.Now().UnixNano(),
    80  			Size:      size,
    81  		}
    82  
    83  		s.statsMutex.Lock()
    84  		defer s.statsMutex.Unlock()
    85  		s.Downloads = append(s.Downloads, m)
    86  	}(size)
    87  }
    88  
    89  func calculateAverage(measures []Measure, minTime int64) (validMeasures []Measure, rate uint64) {
    90  	for _, m := range measures {
    91  		if m.Timestamp > minTime {
    92  			// Only use recent measures
    93  			validMeasures = append(validMeasures, m)
    94  			rate += m.Size
    95  		}
    96  	}
    97  
    98  	rate /= (uint64(measurementPeriod) / uint64(1*time.Second))
    99  	return
   100  }
   101  
   102  func (s *StatsTracker) GetRatePerSecond() (uploadRate uint64, downloadRate uint64) {
   103  	s.statsMutex.Lock()
   104  	defer s.statsMutex.Unlock()
   105  	minTime := time.Now().Add(-measurementPeriod).UnixNano()
   106  	s.Uploads, uploadRate = calculateAverage(s.Uploads, minTime)
   107  	s.Downloads, downloadRate = calculateAverage(s.Downloads, minTime)
   108  	return
   109  }
   110  
   111  func (s *StatsTracker) GetStats() types.StatsSummary {
   112  	uploadRate, downloadRate := s.GetRatePerSecond()
   113  	summary := types.StatsSummary{
   114  		UploadRate:   uploadRate,
   115  		DownloadRate: downloadRate,
   116  	}
   117  	return summary
   118  }