]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: add and use modtimer in netpoll
authorDmitry Vyukov <dvyukov@google.com>
Wed, 31 Oct 2018 16:03:35 +0000 (17:03 +0100)
committerDmitry Vyukov <dvyukov@google.com>
Fri, 2 Nov 2018 12:49:16 +0000 (12:49 +0000)
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>
src/runtime/netpoll.go
src/runtime/time.go

index 00701665f1e35278b632b7e094d5fd5117ef119f..34e7c902ebca1ff13f4e91ff959a9ee41be18160 100644 (file)
@@ -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
index 5e1a925dee6d858cea1b596aeca5692fd8af200f..88fd319a90ba0a1ce4920455afd8df0f867e60b5 100644 (file)
@@ -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.