github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/profiling/timetracer.go (about) 1 package profiling 2 3 import ( 4 "context" 5 "fmt" 6 "sync" 7 "time" 8 9 "github.com/keybase/client/go/logger" 10 "github.com/keybase/clockwork" 11 ) 12 13 type TimeTracer interface { 14 Stage(format string, args ...interface{}) 15 Finish() 16 } 17 18 type TimeTracerImpl struct { 19 sync.Mutex 20 ctx context.Context 21 log logger.Logger 22 clock clockwork.Clock 23 label string 24 stage string 25 staged bool // whether any stages were used 26 start time.Time // when the tracer started 27 prev time.Time // when the active stage started 28 } 29 30 func NewTimeTracer(ctx context.Context, log logger.Logger, clock clockwork.Clock, label string) TimeTracer { 31 now := clock.Now() 32 log.CDebugf(ctx, "+ %s", label) 33 return &TimeTracerImpl{ 34 ctx: ctx, 35 log: log, 36 clock: clock, 37 label: label, 38 stage: "init", 39 staged: false, 40 start: now, 41 prev: now, 42 } 43 } 44 45 func (t *TimeTracerImpl) finishStage() { 46 t.log.CDebugf(t.ctx, "| %s:%s [time=%s]", t.label, t.stage, t.clock.Since(t.prev)) 47 } 48 49 func (t *TimeTracerImpl) Stage(format string, args ...interface{}) { 50 t.Lock() 51 defer t.Unlock() 52 t.finishStage() 53 t.stage = fmt.Sprintf(format, args...) 54 t.prev = t.clock.Now() 55 t.staged = true 56 } 57 58 func (t *TimeTracerImpl) Finish() { 59 t.Lock() 60 defer t.Unlock() 61 if t.staged { 62 t.finishStage() 63 } 64 t.log.CDebugf(t.ctx, "- %s [time=%s]", t.label, t.clock.Since(t.start)) 65 } 66 67 type SilentTimeTracer struct{} 68 69 func NewSilentTimeTracer() *SilentTimeTracer { 70 return &SilentTimeTracer{} 71 } 72 73 func (t *SilentTimeTracer) Stage(format string, args ...interface{}) {} 74 75 func (t *SilentTimeTracer) Finish() {}