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 }