diff --git a/src/pkg/runtime/time.goc b/src/pkg/runtime/time.goc index 6670b45ba9..1101ad068a 100644 --- a/src/pkg/runtime/time.goc +++ b/src/pkg/runtime/time.goc @@ -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; } } diff --git a/src/pkg/time/sleep_test.go b/src/pkg/time/sleep_test.go index 603adc9b89..d21b9cca44 100644 --- a/src/pkg/time/sleep_test.go +++ b/src/pkg/time/sleep_test.go @@ -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 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 - } +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) } - AfterFunc(0, f) - <-c + 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) { + 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 + }) } 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) {