Skip to content

Commit a86f549

Browse files
committed
runtime: add and use modtimer in netpoll
Currently when netpoll deadline is incrementally prolonged, we delete and re-add timer each time. Add modtimer function that does both and use it when we need to modify an existing netpoll timer to avoid unnecessary lock/unlock. TCP4OneShotTimeout-6 17.2µs ± 0% 17.0µs ± 0% -0.82% (p=0.008 n=5+5) SetReadDeadline-6 274ns ± 2% 261ns ± 0% -4.89% (p=0.008 n=5+5) Update #25729 Change-Id: I08b89dbbc1785dd180e967a37b0aa23b0c4613a8 Reviewed-on: https://go-review.googlesource.com/c/146339 Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 86d3754 commit a86f549

File tree

2 files changed

+51
-26
lines changed

2 files changed

+51
-26
lines changed

src/runtime/netpoll.go

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -211,21 +211,13 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
211211
pd.wd = d
212212
}
213213
combo := pd.rd > 0 && pd.rd == pd.wd
214-
// Reset current timers if necessary.
215-
if pd.rt.f != nil && (pd.rd != rd0 || combo != combo0) {
216-
pd.rseq++ // invalidate current timers
217-
deltimer(&pd.rt)
218-
pd.rt.f = nil
219-
}
220-
if pd.wt.f != nil && (pd.wd != wd0 || combo != combo0) {
221-
pd.wseq++ // invalidate current timers
222-
deltimer(&pd.wt)
223-
pd.wt.f = nil
224-
}
225-
// Setup new timers.
214+
rtf := netpollReadDeadline
226215
if combo {
227-
if pd.rt.f == nil {
228-
pd.rt.f = netpollDeadline
216+
rtf = netpollDeadline
217+
}
218+
if pd.rt.f == nil {
219+
if pd.rd > 0 {
220+
pd.rt.f = rtf
229221
pd.rt.when = pd.rd
230222
// Copy current seq into the timer arg.
231223
// Timer func will check the seq against current descriptor seq,
@@ -234,21 +226,31 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
234226
pd.rt.seq = pd.rseq
235227
addtimer(&pd.rt)
236228
}
237-
} else {
238-
if pd.rd > 0 && pd.rt.f == nil {
239-
pd.rt.f = netpollReadDeadline
240-
pd.rt.when = pd.rd
241-
pd.rt.arg = pd
242-
pd.rt.seq = pd.rseq
243-
addtimer(&pd.rt)
229+
} else if pd.rd != rd0 || combo != combo0 {
230+
pd.rseq++ // invalidate current timers
231+
if pd.rd > 0 {
232+
modtimer(&pd.rt, pd.rd, 0, rtf, pd, pd.rseq)
233+
} else {
234+
deltimer(&pd.rt)
235+
pd.rt.f = nil
244236
}
245-
if pd.wd > 0 && pd.wt.f == nil {
237+
}
238+
if pd.wt.f == nil {
239+
if pd.wd > 0 && !combo {
246240
pd.wt.f = netpollWriteDeadline
247241
pd.wt.when = pd.wd
248242
pd.wt.arg = pd
249243
pd.wt.seq = pd.wseq
250244
addtimer(&pd.wt)
251245
}
246+
} else if pd.wd != wd0 || combo != combo0 {
247+
pd.wseq++ // invalidate current timers
248+
if pd.wd > 0 && !combo {
249+
modtimer(&pd.wt, pd.wd, 0, netpollWriteDeadline, pd, pd.wseq)
250+
} else {
251+
deltimer(&pd.wt)
252+
pd.wt.f = nil
253+
}
252254
}
253255
// If we set the new deadline in the past, unblock currently pending IO if any.
254256
var rg, wg *g

src/runtime/time.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,22 +187,30 @@ func deltimer(t *timer) bool {
187187
tb := t.tb
188188

189189
lock(&tb.lock)
190+
removed, ok := tb.deltimerLocked(t)
191+
unlock(&tb.lock)
192+
if !ok {
193+
badTimer()
194+
}
195+
return removed
196+
}
197+
198+
func (tb *timersBucket) deltimerLocked(t *timer) (removed, ok bool) {
190199
// t may not be registered anymore and may have
191200
// a bogus i (typically 0, if generated by Go).
192201
// Verify it before proceeding.
193202
i := t.i
194203
last := len(tb.t) - 1
195204
if i < 0 || i > last || tb.t[i] != t {
196-
unlock(&tb.lock)
197-
return false
205+
return false, true
198206
}
199207
if i != last {
200208
tb.t[i] = tb.t[last]
201209
tb.t[i].i = i
202210
}
203211
tb.t[last] = nil
204212
tb.t = tb.t[:last]
205-
ok := true
213+
ok = true
206214
if i != last {
207215
if !siftupTimer(tb.t, i) {
208216
ok = false
@@ -211,11 +219,26 @@ func deltimer(t *timer) bool {
211219
ok = false
212220
}
213221
}
222+
return true, ok
223+
}
224+
225+
func modtimer(t *timer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr) {
226+
tb := t.tb
227+
228+
lock(&tb.lock)
229+
_, ok := tb.deltimerLocked(t)
230+
if ok {
231+
t.when = when
232+
t.period = period
233+
t.f = f
234+
t.arg = arg
235+
t.seq = seq
236+
ok = tb.addtimerLocked(t)
237+
}
214238
unlock(&tb.lock)
215239
if !ok {
216240
badTimer()
217241
}
218-
return true
219242
}
220243

221244
// Timerproc runs the time-driven events.

0 commit comments

Comments
 (0)