mirror of
https://github.com/golang/go
synced 2024-11-08 12:46:19 -07:00
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 <iant@golang.org>
This commit is contained in:
parent
86d375498f
commit
a86f549703
@ -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) {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
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 {
|
|||||||
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.
|
||||||
|
Loading…
Reference in New Issue
Block a user