]> Cypherpunks repositories - gostls13.git/commitdiff
time: make timers heap 4-ary
authorSokolov Yura <funny.falcon@gmail.com>
Wed, 21 Aug 2013 14:51:37 +0000 (18:51 +0400)
committerDmitriy Vyukov <dvyukov@google.com>
Wed, 21 Aug 2013 14:51:37 +0000 (18:51 +0400)
This slightly improves performance when a lot of timers are present

$ misc/benchcmp ../old_timers_m.txt ../new_timers_m.txt
benchmark                           old ns/op    new ns/op    delta
BenchmarkAfterFunc                       6884         6605   -4.05%
BenchmarkAfterFunc-2                     4473         4144   -7.36%
BenchmarkAfterFunc-3                     8601         6185  -28.09%
BenchmarkAfterFunc-4                     9378         8773   -6.45%
BenchmarkAfter                           7237         7278   +0.57%
BenchmarkAfter-2                         4638         3923  -15.42%
BenchmarkAfter-3                         8751         6239  -28.71%
BenchmarkAfter-4                         9223         8737   -5.27%
BenchmarkStop                             603          496  -17.74%
BenchmarkStop-2                           795          577  -27.42%
BenchmarkStop-3                           982          680  -30.75%
BenchmarkStop-4                          1164          739  -36.51%
BenchmarkSimultaneousAfterFunc            657          593   -9.74%
BenchmarkSimultaneousAfterFunc-2          816          757   -7.23%
BenchmarkSimultaneousAfterFunc-3          844          830   -1.66%
BenchmarkSimultaneousAfterFunc-4          785          771   -1.78%
BenchmarkStartStop                        238          239   +0.42%
BenchmarkStartStop-2                      249          234   -6.02%
BenchmarkStartStop-3                      271          268   -1.11%
BenchmarkStartStop-4                      293          295   +0.68%

R=golang-dev, dvyukov, bradfitz, r
CC=golang-dev
https://golang.org/cl/13094043

src/pkg/runtime/time.goc
src/pkg/time/sleep_test.go

index 6670b45ba99bcc3cc2289f217d14682652752c8a..1101ad068a0ba235c61f852d00880cabf4b13e1c 100644 (file)
@@ -225,18 +225,20 @@ static void
 siftup(int32 i)
 {
        int32 p;
+       int64 when;
        Timer **t, *tmp;
 
        t = timers.t;
+       when = t[i]->when;
+       tmp = t[i];
        while(i > 0) {
-               p = (i-1)/2;  // parent
-               if(t[i]->when >= t[p]->when)
+               p = (i-1)/4;  // parent
+               if(when >= t[p]->when)
                        break;
-               tmp = t[i];
                t[i] = t[p];
-               t[p] = tmp;
                t[i]->i = i;
-               t[p]->i = p;
+               t[p] = tmp;
+               tmp->i = p;
                i = p;
        }
 }
@@ -244,25 +246,42 @@ siftup(int32 i)
 static void
 siftdown(int32 i)
 {
-       int32 c, len;
+       int32 c, c3, len;
+       int64 when, w, w3;
        Timer **t, *tmp;
 
        t = timers.t;
        len = timers.len;
+       when = t[i]->when;
+       tmp = t[i];
        for(;;) {
-               c = i*2 + 1;  // left child
+               c = i*4 + 1;  // left child
+               c3 = c + 2;  // mid child
                if(c >= len) {
                        break;
                }
-               if(c+1 < len && t[c+1]->when < t[c]->when)
+               w = t[c]->when;
+               if(c+1 < len && t[c+1]->when < w) {
+                       w = t[c+1]->when;
                        c++;
-               if(t[c]->when >= t[i]->when)
+               }
+               if(c3 < len) {
+                       w3 = t[c3]->when;
+                       if(c3+1 < len && t[c3+1]->when < w3) {
+                               w3 = t[c3+1]->when;
+                               c3++;
+                       }
+                       if(w3 < w) {
+                               w = w3;
+                               c = c3;
+                       }
+               }
+               if(w >= when)
                        break;
-               tmp = t[i];
                t[i] = t[c];
-               t[c] = tmp;
                t[i]->i = i;
-               t[c]->i = c;
+               t[c] = tmp;
+               tmp->i = c;
                i = c;
        }
 }
index 603adc9b895894eea9b2319f8e7d7816647a467d..d21b9cca44ad3d9eafee179d213fd4903e33c3d1 100644 (file)
@@ -9,6 +9,7 @@ import (
        "fmt"
        "runtime"
        "sort"
+       "sync"
        "sync/atomic"
        "testing"
        . "time"
@@ -68,33 +69,94 @@ func TestAfterStress(t *testing.T) {
        atomic.StoreUint32(&stop, 1)
 }
 
+func benchmark(b *testing.B, bench func(n int)) {
+       garbage := make([]*Timer, 1<<17)
+       for i := 0; i < len(garbage); i++ {
+               garbage[i] = AfterFunc(Hour, nil)
+       }
+
+       const batch = 1000
+       P := runtime.GOMAXPROCS(-1)
+       N := int32(b.N / batch)
+
+       b.ResetTimer()
+
+       var wg sync.WaitGroup
+       wg.Add(P)
+
+       for p := 0; p < P; p++ {
+               go func() {
+                       for atomic.AddInt32(&N, -1) >= 0 {
+                               bench(batch)
+                       }
+                       wg.Done()
+               }()
+       }
+
+       wg.Wait()
+
+       b.StopTimer()
+       for i := 0; i < len(garbage); i++ {
+               garbage[i].Stop()
+       }
+}
+
 func BenchmarkAfterFunc(b *testing.B) {
-       i := b.N
-       c := make(chan bool)
-       var f func()
-       f = func() {
-               i--
-               if i >= 0 {
-                       AfterFunc(0, f)
-               } else {
-                       c <- true
+       benchmark(b, func(n int) {
+               c := make(chan bool)
+               var f func()
+               f = func() {
+                       n--
+                       if n >= 0 {
+                               AfterFunc(0, f)
+                       } else {
+                               c <- true
+                       }
                }
-       }
 
-       AfterFunc(0, f)
-       <-c
+               AfterFunc(0, f)
+               <-c
+       })
 }
 
 func BenchmarkAfter(b *testing.B) {
-       for i := 0; i < b.N; i++ {
-               <-After(1)
-       }
+       benchmark(b, func(n int) {
+               for i := 0; i < n; i++ {
+                       <-After(1)
+               }
+       })
 }
 
 func BenchmarkStop(b *testing.B) {
-       for i := 0; i < b.N; i++ {
-               NewTimer(1 * Second).Stop()
-       }
+       benchmark(b, func(n int) {
+               for i := 0; i < n; i++ {
+                       NewTimer(1 * Second).Stop()
+               }
+       })
+}
+
+func BenchmarkSimultaneousAfterFunc(b *testing.B) {
+       benchmark(b, func(n int) {
+               var wg sync.WaitGroup
+               wg.Add(n)
+               for i := 0; i < n; i++ {
+                       AfterFunc(0, wg.Done)
+               }
+               wg.Wait()
+       })
+}
+
+func BenchmarkStartStop(b *testing.B) {
+       benchmark(b, func(n int) {
+               timers := make([]*Timer, n)
+               for i := 0; i < n; i++ {
+                       timers[i] = AfterFunc(Hour, nil)
+               }
+
+               for i := 0; i < n; i++ {
+                       timers[i].Stop()
+               }
+       })
 }
 
 func TestAfter(t *testing.T) {