From 2b57eb82e055a4f992815f7d38cca54b1683f58c Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Mon, 2 Jan 2017 08:29:58 +0100 Subject: [PATCH 1/2] Partial workaround for timer during a clock jump `time.Now()` uses the wall-clock and therefore calling it twice, one second apart, can produce quite different results (negative results but also a difference greater than one second). Go doesn't expose a monotonic clock, therefore, it's difficult to properly fix (but there is https://github.com/gavv/monotime if we want a proper fix for `timer.Time()`). This workaround just discard any negative duration. --- timer.go | 16 ++++++++-------- timer_test.go | 1 + 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/timer.go b/timer.go index 17db8f8..3eb1225 100644 --- a/timer.go +++ b/timer.go @@ -215,18 +215,18 @@ func (t *StandardTimer) Time(f func()) { // Record the duration of an event. func (t *StandardTimer) Update(d time.Duration) { - t.mutex.Lock() - defer t.mutex.Unlock() - t.histogram.Update(int64(d)) - t.meter.Mark(1) + // Partial workaround for detecting a clock change + if d >= 0 { + t.mutex.Lock() + defer t.mutex.Unlock() + t.histogram.Update(int64(d)) + t.meter.Mark(1) + } } // Record the duration of an event that started at a time and ends now. func (t *StandardTimer) UpdateSince(ts time.Time) { - t.mutex.Lock() - defer t.mutex.Unlock() - t.histogram.Update(int64(time.Since(ts))) - t.meter.Mark(1) + t.Update(time.Since(ts)) } // Variance returns the variance of the values in the sample. diff --git a/timer_test.go b/timer_test.go index 313d691..f908da3 100644 --- a/timer_test.go +++ b/timer_test.go @@ -27,6 +27,7 @@ func TestTimerExtremes(t *testing.T) { tm := NewTimer() tm.Update(math.MaxInt64) tm.Update(0) + tm.Update(math.MinInt64) if stdDev := tm.StdDev(); 4.611686018427388e+18 != stdDev { t.Errorf("tm.StdDev(): 4.611686018427388e+18 != %v\n", stdDev) } From 0d432c4e7738db326ea5d2e546dc28ec28fef164 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Mon, 2 Jan 2017 08:41:32 +0100 Subject: [PATCH 2/2] Partial workaround for meter during a clock jump --- meter.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/meter.go b/meter.go index 0389ab0..9adce5a 100644 --- a/meter.go +++ b/meter.go @@ -190,10 +190,13 @@ func (m *StandardMeter) Snapshot() Meter { func (m *StandardMeter) updateSnapshot() { // should run with write lock held on m.lock snapshot := m.snapshot - snapshot.rate1 = m.a1.Rate() - snapshot.rate5 = m.a5.Rate() - snapshot.rate15 = m.a15.Rate() - snapshot.rateMean = float64(snapshot.count) / time.Since(m.startTime).Seconds() + elapsed := time.Since(m.startTime).Seconds() + if elapsed >= 0 { + snapshot.rate1 = m.a1.Rate() + snapshot.rate5 = m.a5.Rate() + snapshot.rate15 = m.a15.Rate() + snapshot.rateMean = float64(snapshot.count) / elapsed + } } func (m *StandardMeter) tick() {