Skip to content

Commit

Permalink
time: add Ticker.Reset
Browse files Browse the repository at this point in the history
This CL implements Ticker.Reset method in time package.

Benchmark:
name                 time/op
TickerReset-12       6.41µs ±10%
TickerResetNaive-12  95.7µs ±12%

Fixes #33184

Change-Id: I4cbd31796efa012b2a297bb342158f11a4a31fef
Reviewed-on: https://go-review.googlesource.com/c/go/+/220424
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
  • Loading branch information
changkun authored and ianlancetaylor committed Feb 24, 2020
1 parent 0f2a157 commit 402ea9e
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 4 deletions.
1 change: 1 addition & 0 deletions api/next.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pkg testing, method (*T) Deadline() (time.Time, bool)
pkg time, method (*Ticker) Reset(Duration)
10 changes: 10 additions & 0 deletions doc/go1.15.html
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,13 @@ <h3 id="minor_library_changes">Minor changes to the library</h3>
<p>
TODO
</p>

<dl id="time"><dt><a href="/pkg/time/">time</a></dt>
<dd>
<p><!-- golang.org/issue/33184 -->
The new method
<a href="/pkg/time#Ticker.Reset"><code>Ticker.Reset</code></a>
supports changing the duration of a ticker.
</p>
</dd>
</dl><!-- time -->
8 changes: 7 additions & 1 deletion src/runtime/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,12 @@ func resetTimer(t *timer, when int64) {
resettimer(t, when)
}

// modTimer modifies an existing timer.
//go:linkname modTimer time.modTimer
func modTimer(t *timer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr) {
modtimer(t, when, period, f, arg, seq)
}

// Go runtime.

// Ready the goroutine arg.
Expand Down Expand Up @@ -402,7 +408,7 @@ func dodeltimer0(pp *p) bool {
}

// modtimer modifies an existing timer.
// This is called by the netpoll code.
// This is called by the netpoll code or time.Ticker.Reset.
func modtimer(t *timer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr) {
if when < 0 {
when = maxWhen
Expand Down
1 change: 1 addition & 0 deletions src/time/sleep.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func when(d Duration) int64 {
func startTimer(*runtimeTimer)
func stopTimer(*runtimeTimer) bool
func resetTimer(*runtimeTimer, int64)
func modTimer(t *runtimeTimer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr)

// The Timer type represents a single event.
// When the Timer expires, the current time will be sent on C,
Expand Down
9 changes: 9 additions & 0 deletions src/time/tick.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ func (t *Ticker) Stop() {
stopTimer(&t.r)
}

// Reset stops a ticker and resets its period to the specified duration.
// The next tick will arrive after the new period elapses.
func (t *Ticker) Reset(d Duration) {
if t.r.f == nil {
panic("time: Reset called on uninitialized Ticker")
}
modTimer(&t.r, when(d), int64(d), t.r.f, t.r.arg, t.r.seq)
}

// Tick is a convenience wrapper for NewTicker providing access to the ticking
// channel only. While Tick is useful for clients that have no need to shut down
// the Ticker, be aware that without a way to shut it down the underlying
Expand Down
36 changes: 33 additions & 3 deletions src/time/tick_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ func TestTicker(t *testing.T) {

// On Darwin ARM64 the tick frequency seems limited. Issue 35692.
if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
count = 5
// The following test will run ticker count/2 times then reset
// the ticker to double the duration for the rest of count/2.
// Since tick frequency is limited on Darwin ARM64, use even
// number to give the ticks more time to let the test pass.
// See CL 220638.
count = 6
delta = 100 * Millisecond
}

Expand All @@ -36,13 +41,17 @@ func TestTicker(t *testing.T) {
for i := 0; i < 5; i++ {
ticker := NewTicker(delta)
t0 := Now()
for i := 0; i < count; i++ {
for i := 0; i < count/2; i++ {
<-ticker.C
}
ticker.Reset(delta * 2)
for i := count / 2; i < count; i++ {
<-ticker.C
}
ticker.Stop()
t1 := Now()
dt := t1.Sub(t0)
target := delta * Duration(count)
target := 3 * delta * Duration(count/2)
slop := target * 2 / 10
if dt < target-slop || dt > target+slop {
errs = append(errs, fmt.Sprintf("%d %s ticks took %s, expected [%s,%s]", count, delta, dt, target-slop, target+slop))
Expand Down Expand Up @@ -118,3 +127,24 @@ func BenchmarkTicker(b *testing.B) {
ticker.Stop()
})
}

func BenchmarkTickerReset(b *testing.B) {
benchmark(b, func(n int) {
ticker := NewTicker(Nanosecond)
for i := 0; i < n; i++ {
ticker.Reset(Nanosecond * 2)
}
ticker.Stop()
})
}

func BenchmarkTickerResetNaive(b *testing.B) {
benchmark(b, func(n int) {
ticker := NewTicker(Nanosecond)
for i := 0; i < n; i++ {
ticker.Stop()
ticker = NewTicker(Nanosecond * 2)
}
ticker.Stop()
})
}

0 comments on commit 402ea9e

Please sign in to comment.