Commit a86f5497 authored by Dmitry Vyukov's avatar Dmitry Vyukov

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/146339Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent 86d37549
...@@ -211,21 +211,13 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) { ...@@ -211,21 +211,13 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
pd.wd = d pd.wd = d
} }
combo := pd.rd > 0 && pd.rd == pd.wd combo := pd.rd > 0 && pd.rd == pd.wd
// Reset current timers if necessary. rtf := netpollReadDeadline
if pd.rt.f != nil && (pd.rd != rd0 || combo != combo0) {
pd.rseq++ // invalidate current timers
deltimer(&pd.rt)
pd.rt.f = nil
}
if pd.wt.f != nil && (pd.wd != wd0 || combo != combo0) {
pd.wseq++ // invalidate current timers
deltimer(&pd.wt)
pd.wt.f = nil
}
// Setup new timers.
if combo { if combo {
if pd.rt.f == nil { rtf = netpollDeadline
pd.rt.f = netpollDeadline }
if pd.rt.f == nil {
if pd.rd > 0 {
pd.rt.f = rtf
pd.rt.when = pd.rd pd.rt.when = pd.rd
// Copy current seq into the timer arg. // Copy current seq into the timer arg.
// Timer func will check the seq against current descriptor seq, // Timer func will check the seq against current descriptor seq,
...@@ -234,21 +226,31 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) { ...@@ -234,21 +226,31 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
pd.rt.seq = pd.rseq pd.rt.seq = pd.rseq
addtimer(&pd.rt) addtimer(&pd.rt)
} }
} else { } else if pd.rd != rd0 || combo != combo0 {
if pd.rd > 0 && pd.rt.f == nil { pd.rseq++ // invalidate current timers
pd.rt.f = netpollReadDeadline if pd.rd > 0 {
pd.rt.when = pd.rd modtimer(&pd.rt, pd.rd, 0, rtf, pd, pd.rseq)
pd.rt.arg = pd } else {
pd.rt.seq = pd.rseq deltimer(&pd.rt)
addtimer(&pd.rt) pd.rt.f = nil
} }
if pd.wd > 0 && pd.wt.f == nil { }
if pd.wt.f == nil {
if pd.wd > 0 && !combo {
pd.wt.f = netpollWriteDeadline pd.wt.f = netpollWriteDeadline
pd.wt.when = pd.wd pd.wt.when = pd.wd
pd.wt.arg = pd pd.wt.arg = pd
pd.wt.seq = pd.wseq pd.wt.seq = pd.wseq
addtimer(&pd.wt) addtimer(&pd.wt)
} }
} else if pd.wd != wd0 || combo != combo0 {
pd.wseq++ // invalidate current timers
if pd.wd > 0 && !combo {
modtimer(&pd.wt, pd.wd, 0, netpollWriteDeadline, pd, pd.wseq)
} else {
deltimer(&pd.wt)
pd.wt.f = nil
}
} }
// If we set the new deadline in the past, unblock currently pending IO if any. // If we set the new deadline in the past, unblock currently pending IO if any.
var rg, wg *g var rg, wg *g
......
...@@ -187,14 +187,22 @@ func deltimer(t *timer) bool { ...@@ -187,14 +187,22 @@ func deltimer(t *timer) bool {
tb := t.tb tb := t.tb
lock(&tb.lock) lock(&tb.lock)
removed, ok := tb.deltimerLocked(t)
unlock(&tb.lock)
if !ok {
badTimer()
}
return removed
}
func (tb *timersBucket) deltimerLocked(t *timer) (removed, ok bool) {
// t may not be registered anymore and may have // t may not be registered anymore and may have
// a bogus i (typically 0, if generated by Go). // a bogus i (typically 0, if generated by Go).
// Verify it before proceeding. // Verify it before proceeding.
i := t.i i := t.i
last := len(tb.t) - 1 last := len(tb.t) - 1
if i < 0 || i > last || tb.t[i] != t { if i < 0 || i > last || tb.t[i] != t {
unlock(&tb.lock) return false, true
return false
} }
if i != last { if i != last {
tb.t[i] = tb.t[last] tb.t[i] = tb.t[last]
...@@ -202,7 +210,7 @@ func deltimer(t *timer) bool { ...@@ -202,7 +210,7 @@ func deltimer(t *timer) bool {
} }
tb.t[last] = nil tb.t[last] = nil
tb.t = tb.t[:last] tb.t = tb.t[:last]
ok := true ok = true
if i != last { if i != last {
if !siftupTimer(tb.t, i) { if !siftupTimer(tb.t, i) {
ok = false ok = false
...@@ -211,11 +219,26 @@ func deltimer(t *timer) bool { ...@@ -211,11 +219,26 @@ func deltimer(t *timer) bool {
ok = false ok = false
} }
} }
return true, ok
}
func modtimer(t *timer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr) {
tb := t.tb
lock(&tb.lock)
_, ok := tb.deltimerLocked(t)
if ok {
t.when = when
t.period = period
t.f = f
t.arg = arg
t.seq = seq
ok = tb.addtimerLocked(t)
}
unlock(&tb.lock) unlock(&tb.lock)
if !ok { if !ok {
badTimer() badTimer()
} }
return true
} }
// Timerproc runs the time-driven events. // Timerproc runs the time-driven events.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment