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) {
pd.wd = d
}
combo := pd.rd > 0 && pd.rd == pd.wd
// Reset current timers if necessary.
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.
rtf := netpollReadDeadline
if combo {
if pd.rt.f == nil {
pd.rt.f = netpollDeadline
rtf = netpollDeadline
}
if pd.rt.f == nil {
if pd.rd > 0 {
pd.rt.f = rtf
pd.rt.when = pd.rd
// Copy current seq into the timer arg.
// Timer func will check the seq against current descriptor seq,
......@@ -234,21 +226,31 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
pd.rt.seq = pd.rseq
addtimer(&pd.rt)
}
} else {
if pd.rd > 0 && pd.rt.f == nil {
pd.rt.f = netpollReadDeadline
pd.rt.when = pd.rd
pd.rt.arg = pd
pd.rt.seq = pd.rseq
addtimer(&pd.rt)
} else if pd.rd != rd0 || combo != combo0 {
pd.rseq++ // invalidate current timers
if pd.rd > 0 {
modtimer(&pd.rt, pd.rd, 0, rtf, pd, pd.rseq)
} else {
deltimer(&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.when = pd.wd
pd.wt.arg = pd
pd.wt.seq = pd.wseq
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.
var rg, wg *g
......
......@@ -187,14 +187,22 @@ func deltimer(t *timer) bool {
tb := t.tb
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
// a bogus i (typically 0, if generated by Go).
// Verify it before proceeding.
i := t.i
last := len(tb.t) - 1
if i < 0 || i > last || tb.t[i] != t {
unlock(&tb.lock)
return false
return false, true
}
if i != last {
tb.t[i] = tb.t[last]
......@@ -202,7 +210,7 @@ func deltimer(t *timer) bool {
}
tb.t[last] = nil
tb.t = tb.t[:last]
ok := true
ok = true
if i != last {
if !siftupTimer(tb.t, i) {
ok = false
......@@ -211,11 +219,26 @@ func deltimer(t *timer) bool {
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)
if !ok {
badTimer()
}
return true
}
// 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