github.com/nozzle/golangci-lint@v1.49.0-nz3/pkg/timeutils/stopwatch.go (about)

     1  package timeutils
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"strings"
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/golangci/golangci-lint/pkg/logutils"
    11  )
    12  
    13  const noStagesText = "no stages"
    14  
    15  type Stopwatch struct {
    16  	name      string
    17  	startedAt time.Time
    18  	log       logutils.Log
    19  
    20  	stages map[string]time.Duration
    21  	mu     sync.Mutex
    22  }
    23  
    24  func NewStopwatch(name string, log logutils.Log) *Stopwatch {
    25  	return &Stopwatch{
    26  		name:      name,
    27  		startedAt: time.Now(),
    28  		stages:    map[string]time.Duration{},
    29  		log:       log,
    30  	}
    31  }
    32  
    33  type stageDuration struct {
    34  	name string
    35  	d    time.Duration
    36  }
    37  
    38  func (s *Stopwatch) stageDurationsSorted() []stageDuration {
    39  	stageDurations := make([]stageDuration, 0, len(s.stages))
    40  	for n, d := range s.stages {
    41  		stageDurations = append(stageDurations, stageDuration{
    42  			name: n,
    43  			d:    d,
    44  		})
    45  	}
    46  	sort.Slice(stageDurations, func(i, j int) bool {
    47  		return stageDurations[i].d > stageDurations[j].d
    48  	})
    49  	return stageDurations
    50  }
    51  
    52  func (s *Stopwatch) sprintStages() string {
    53  	if len(s.stages) == 0 {
    54  		return noStagesText
    55  	}
    56  
    57  	stageDurations := s.stageDurationsSorted()
    58  
    59  	stagesStrings := make([]string, 0, len(stageDurations))
    60  	for _, s := range stageDurations {
    61  		stagesStrings = append(stagesStrings, fmt.Sprintf("%s: %s", s.name, s.d))
    62  	}
    63  
    64  	return fmt.Sprintf("stages: %s", strings.Join(stagesStrings, ", "))
    65  }
    66  
    67  func (s *Stopwatch) sprintTopStages(n int) string {
    68  	if len(s.stages) == 0 {
    69  		return noStagesText
    70  	}
    71  
    72  	stageDurations := s.stageDurationsSorted()
    73  
    74  	var stagesStrings []string
    75  	for i := 0; i < len(stageDurations) && i < n; i++ {
    76  		s := stageDurations[i]
    77  		stagesStrings = append(stagesStrings, fmt.Sprintf("%s: %s", s.name, s.d))
    78  	}
    79  
    80  	return fmt.Sprintf("top %d stages: %s", n, strings.Join(stagesStrings, ", "))
    81  }
    82  
    83  func (s *Stopwatch) Print() {
    84  	p := fmt.Sprintf("%s took %s", s.name, time.Since(s.startedAt))
    85  	if len(s.stages) == 0 {
    86  		s.log.Infof("%s", p)
    87  		return
    88  	}
    89  
    90  	s.log.Infof("%s with %s", p, s.sprintStages())
    91  }
    92  
    93  func (s *Stopwatch) PrintStages() {
    94  	var stagesDuration time.Duration
    95  	for _, s := range s.stages {
    96  		stagesDuration += s
    97  	}
    98  	s.log.Infof("%s took %s with %s", s.name, stagesDuration, s.sprintStages())
    99  }
   100  
   101  func (s *Stopwatch) PrintTopStages(n int) {
   102  	var stagesDuration time.Duration
   103  	for _, s := range s.stages {
   104  		stagesDuration += s
   105  	}
   106  	s.log.Infof("%s took %s with %s", s.name, stagesDuration, s.sprintTopStages(n))
   107  }
   108  
   109  func (s *Stopwatch) TrackStage(name string, f func()) {
   110  	startedAt := time.Now()
   111  	f()
   112  
   113  	s.mu.Lock()
   114  	s.stages[name] += time.Since(startedAt)
   115  	s.mu.Unlock()
   116  }