github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/timer.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package libkb 5 6 import ( 7 "time" 8 ) 9 10 // SimpleTimer keeps track of how long something is taking, like a network 11 // API call. Meant to be very simple. It is not meant to be goroutine safe 12 // and should only be called from one Goroutine. 13 type SimpleTimer struct { 14 total time.Duration 15 start *time.Time 16 } 17 18 // Start the timer running, if it's not already started. 19 func (s *SimpleTimer) Start() { 20 if s.start == nil { 21 tmp := time.Now() 22 s.start = &tmp 23 } 24 } 25 26 // Stop the timer; panic if it hasn't been previously started. Return 27 // the total duration spent in the timer. 28 func (s *SimpleTimer) Stop() time.Duration { 29 if s.start != nil { 30 s.total += time.Since(*s.start) 31 } else { 32 panic("SimpleTimer Stop()'ed without being started") 33 } 34 return s.GetTotal() 35 } 36 37 // GetTotal gets the total duration spent in the timer. 38 func (s *SimpleTimer) GetTotal() time.Duration { 39 return s.total 40 } 41 42 // Reset the internal duration counter. 43 func (s *SimpleTimer) Reset() { 44 s.total = 0 45 } 46 47 // ReportingTimer is an interface shared between ReportingTimerReal 48 // and ReportingTimerDummy, to allow for convenient disabling of timer features. 49 type ReportingTimer interface { 50 Report(prefix string) 51 } 52 53 // ReportingTimerReal is a SimpleTimer that reports after the timing measurement 54 // is done. 55 type ReportingTimerReal struct { 56 SimpleTimer 57 Contextified 58 } 59 60 // NewReportingTimerReal returns an initialized reporting timer that 61 // actually reports timing information. 62 func NewReportingTimerReal(ctx Contextified) *ReportingTimerReal { 63 return &ReportingTimerReal{Contextified: ctx} 64 } 65 66 // Report stops and resets the timer, then logs to Info what the duration was. 67 func (r *ReportingTimerReal) Report(prefix string) { 68 dur := r.Stop() 69 r.Reset() 70 r.G().Log.Info("timer: %s [%d ms]", prefix, dur/time.Millisecond) 71 } 72 73 // ReportingTimerDummy fulfills the ReportingTimer interface but doesn't 74 // do anything when done. 75 type ReportingTimerDummy struct{} 76 77 // Report is a noop. 78 func (r ReportingTimerDummy) Report(prefix string) {} 79 80 // TimerSelector allows us to select which timers we want on. 81 type TimerSelector int 82 83 const ( 84 // TimerNone means Timers Disabled 85 TimerNone TimerSelector = 0 86 // TimerAPI enables API timers 87 TimerAPI TimerSelector = 1 << iota 88 // TimerXAPI enables External API timers 89 TimerXAPI 90 // TimerRPC enables RPC timers 91 TimerRPC 92 ) 93 94 // TimerSet is the set of currently active timers 95 type TimerSet struct { 96 sel TimerSelector 97 Contextified 98 } 99 100 // NewTimerSet looks into the given context for configuration information 101 // about how to set up timers. It then returns the corresponding TimerSet. 102 func NewTimerSet(g *GlobalContext) *TimerSet { 103 s := g.Env.GetTimers() 104 sel := TimerNone 105 for _, c := range s { 106 switch c { 107 case 'a': 108 sel |= TimerAPI 109 case 'x': 110 sel |= TimerXAPI 111 case 'r': 112 sel |= TimerRPC 113 114 } 115 } 116 return &TimerSet{sel: sel, Contextified: Contextified{g}} 117 } 118 119 // Start allocates and starts a new timer if the passed TimerSelector 120 // is currently enabled. Otherwise, it just returns a Dummy timer. 121 func (s TimerSet) Start(sel TimerSelector) ReportingTimer { 122 var ret ReportingTimer 123 if s.sel&sel == sel { 124 tmp := NewReportingTimerReal(s.Contextified) 125 tmp.Start() 126 ret = tmp 127 } else { 128 ret = ReportingTimerDummy{} 129 } 130 return ret 131 }