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() {}