github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/testutil/stress/stats.go (about)

     1  package stress
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  )
     7  
     8  type collectorRequest int
     9  
    10  const (
    11  	collectorRequestStats collectorRequest = iota
    12  	collectorRequestHistogram
    13  )
    14  
    15  type Stats struct {
    16  	TotalCompleted   int64
    17  	TotalErrors      int64
    18  	CurrentCompleted int64
    19  	CurrentInterval  time.Duration
    20  }
    21  
    22  func (s *Stats) String() string {
    23  	return fmt.Sprintf("completed: %d, errors: %d, current rate: %.2f done/second",
    24  		s.TotalCompleted, s.TotalErrors,
    25  		float64(s.CurrentCompleted)/s.CurrentInterval.Seconds())
    26  }
    27  
    28  type ResultCollector struct {
    29  	// Results is the channel workers should write their output to
    30  	Results chan Result
    31  
    32  	// for getting data out using methods
    33  	requests   chan collectorRequest
    34  	stats      chan *Stats
    35  	histograms chan *Histogram
    36  
    37  	// collected stats
    38  	lastFlush        time.Time
    39  	histogram        *Histogram
    40  	totalCompleted   int64
    41  	totalErrors      int64
    42  	currentCompleted int64
    43  }
    44  
    45  func (rc *ResultCollector) flushCurrent() *Stats {
    46  	return &Stats{
    47  		TotalCompleted:   rc.totalCompleted,
    48  		TotalErrors:      rc.totalErrors,
    49  		CurrentCompleted: rc.currentCompleted,
    50  		CurrentInterval:  time.Since(rc.lastFlush),
    51  	}
    52  }
    53  
    54  func (rc *ResultCollector) Stats() *Stats {
    55  	rc.requests <- collectorRequestStats
    56  	return <-rc.stats
    57  }
    58  
    59  func (rc *ResultCollector) Histogram() *Histogram {
    60  	rc.requests <- collectorRequestHistogram
    61  	return <-rc.histograms
    62  }
    63  
    64  func (rc *ResultCollector) Collect() {
    65  	for {
    66  		select {
    67  		case result := <-rc.Results:
    68  			rc.totalCompleted++
    69  			rc.currentCompleted++
    70  			if result.Error != nil {
    71  				rc.totalErrors++
    72  			} else {
    73  				rc.histogram.Add(result.Took.Milliseconds())
    74  			}
    75  		case request := <-rc.requests:
    76  			switch request {
    77  			case collectorRequestHistogram:
    78  				rc.histograms <- rc.histogram.Clone()
    79  			case collectorRequestStats:
    80  				rc.stats <- rc.flushCurrent()
    81  				rc.currentCompleted = 0
    82  				rc.lastFlush = time.Now()
    83  			}
    84  		}
    85  	}
    86  }
    87  
    88  var DefaultHistogramBuckets = []int64{1, 2, 5, 7, 10, 15, 25, 50, 75, 100, 250, 350, 500, 750, 1000, 5000}
    89  
    90  func NewResultCollector(workerResults chan Result) *ResultCollector {
    91  	return &ResultCollector{
    92  		Results:    workerResults,
    93  		requests:   make(chan collectorRequest),
    94  		stats:      make(chan *Stats),
    95  		histograms: make(chan *Histogram),
    96  		lastFlush:  time.Now(),
    97  		histogram:  NewHistogram(DefaultHistogramBuckets),
    98  	}
    99  }