aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChangkun Ou <hi@changkun.us>2020-02-03 14:42:32 +0100
committerIan Lance Taylor <iant@golang.org>2020-02-24 01:50:28 +0000
commit402ea9e4f9ddcd2ed595ac12ce1b4e39f82e128f (patch)
tree7013229276d72fc24079c310be3a20c6bde100e9 /src
parent0f2a1574b02de3fec6937e65b1bdc21106bef15c (diff)
downloadgo-402ea9e4f9ddcd2ed595ac12ce1b4e39f82e128f.tar.xz
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 <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src')
-rw-r--r--src/runtime/time.go8
-rw-r--r--src/time/sleep.go1
-rw-r--r--src/time/tick.go9
-rw-r--r--src/time/tick_test.go36
4 files changed, 50 insertions, 4 deletions
diff --git a/src/runtime/time.go b/src/runtime/time.go
index af5db4cc58..9e1129537a 100644
--- a/src/runtime/time.go
+++ b/src/runtime/time.go
@@ -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.
@@ -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
diff --git a/src/time/sleep.go b/src/time/sleep.go
index 37de846b11..bd0ed9aaba 100644
--- a/src/time/sleep.go
+++ b/src/time/sleep.go
@@ -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,
diff --git a/src/time/tick.go b/src/time/tick.go
index e4cd43aa82..152d5a706b 100644
--- a/src/time/tick.go
+++ b/src/time/tick.go
@@ -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
diff --git a/src/time/tick_test.go b/src/time/tick_test.go
index 71ea3672b8..c0c6e76b53 100644
--- a/src/time/tick_test.go
+++ b/src/time/tick_test.go
@@ -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
}
@@ -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))
@@ -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()
+ })
+}