Skip to content

Commit 402ea9e

Browse files
changkunianlancetaylor
authored andcommitted
time: add Ticker.Reset
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 0f2a157 commit 402ea9e

File tree

6 files changed

+61
-4
lines changed

6 files changed

+61
-4
lines changed

Diff for: api/next.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
pkg testing, method (*T) Deadline() (time.Time, bool)
2+
pkg time, method (*Ticker) Reset(Duration)

Diff for: doc/go1.15.html

+10
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,13 @@ <h3 id="minor_library_changes">Minor changes to the library</h3>
8080
<p>
8181
TODO
8282
</p>
83+
84+
<dl id="time"><dt><a href="/pkg/time/">time</a></dt>
85+
<dd>
86+
<p><!-- golang.org/issue/33184 -->
87+
The new method
88+
<a href="/pkg/time#Ticker.Reset"><code>Ticker.Reset</code></a>
89+
supports changing the duration of a ticker.
90+
</p>
91+
</dd>
92+
</dl><!-- time -->

Diff for: src/runtime/time.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,12 @@ func resetTimer(t *timer, when int64) {
233233
resettimer(t, when)
234234
}
235235

236+
// modTimer modifies an existing timer.
237+
//go:linkname modTimer time.modTimer
238+
func modTimer(t *timer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr) {
239+
modtimer(t, when, period, f, arg, seq)
240+
}
241+
236242
// Go runtime.
237243

238244
// Ready the goroutine arg.
@@ -402,7 +408,7 @@ func dodeltimer0(pp *p) bool {
402408
}
403409

404410
// modtimer modifies an existing timer.
405-
// This is called by the netpoll code.
411+
// This is called by the netpoll code or time.Ticker.Reset.
406412
func modtimer(t *timer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr) {
407413
if when < 0 {
408414
when = maxWhen

Diff for: src/time/sleep.go

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ func when(d Duration) int64 {
3939
func startTimer(*runtimeTimer)
4040
func stopTimer(*runtimeTimer) bool
4141
func resetTimer(*runtimeTimer, int64)
42+
func modTimer(t *runtimeTimer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr)
4243

4344
// The Timer type represents a single event.
4445
// When the Timer expires, the current time will be sent on C,

Diff for: src/time/tick.go

+9
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@ func (t *Ticker) Stop() {
4646
stopTimer(&t.r)
4747
}
4848

49+
// Reset stops a ticker and resets its period to the specified duration.
50+
// The next tick will arrive after the new period elapses.
51+
func (t *Ticker) Reset(d Duration) {
52+
if t.r.f == nil {
53+
panic("time: Reset called on uninitialized Ticker")
54+
}
55+
modTimer(&t.r, when(d), int64(d), t.r.f, t.r.arg, t.r.seq)
56+
}
57+
4958
// Tick is a convenience wrapper for NewTicker providing access to the ticking
5059
// channel only. While Tick is useful for clients that have no need to shut down
5160
// the Ticker, be aware that without a way to shut it down the underlying

Diff for: src/time/tick_test.go

+33-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ func TestTicker(t *testing.T) {
2222

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

@@ -36,13 +41,17 @@ func TestTicker(t *testing.T) {
3641
for i := 0; i < 5; i++ {
3742
ticker := NewTicker(delta)
3843
t0 := Now()
39-
for i := 0; i < count; i++ {
44+
for i := 0; i < count/2; i++ {
45+
<-ticker.C
46+
}
47+
ticker.Reset(delta * 2)
48+
for i := count / 2; i < count; i++ {
4049
<-ticker.C
4150
}
4251
ticker.Stop()
4352
t1 := Now()
4453
dt := t1.Sub(t0)
45-
target := delta * Duration(count)
54+
target := 3 * delta * Duration(count/2)
4655
slop := target * 2 / 10
4756
if dt < target-slop || dt > target+slop {
4857
errs = append(errs, fmt.Sprintf("%d %s ticks took %s, expected [%s,%s]", count, delta, dt, target-slop, target+slop))
@@ -118,3 +127,24 @@ func BenchmarkTicker(b *testing.B) {
118127
ticker.Stop()
119128
})
120129
}
130+
131+
func BenchmarkTickerReset(b *testing.B) {
132+
benchmark(b, func(n int) {
133+
ticker := NewTicker(Nanosecond)
134+
for i := 0; i < n; i++ {
135+
ticker.Reset(Nanosecond * 2)
136+
}
137+
ticker.Stop()
138+
})
139+
}
140+
141+
func BenchmarkTickerResetNaive(b *testing.B) {
142+
benchmark(b, func(n int) {
143+
ticker := NewTicker(Nanosecond)
144+
for i := 0; i < n; i++ {
145+
ticker.Stop()
146+
ticker = NewTicker(Nanosecond * 2)
147+
}
148+
ticker.Stop()
149+
})
150+
}

0 commit comments

Comments
 (0)