diff options
Diffstat (limited to 'pkg/sleep/sleep_test.go')
-rw-r--r-- | pkg/sleep/sleep_test.go | 591 |
1 files changed, 0 insertions, 591 deletions
diff --git a/pkg/sleep/sleep_test.go b/pkg/sleep/sleep_test.go deleted file mode 100644 index f4af9d710..000000000 --- a/pkg/sleep/sleep_test.go +++ /dev/null @@ -1,591 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package sleep - -import ( - "math/rand" - "runtime" - "testing" - "time" -) - -// ZeroWakerNotAsserted tests that a zero-value waker is in non-asserted state. -func ZeroWakerNotAsserted(t *testing.T) { - var w Waker - if w.IsAsserted() { - t.Fatalf("Zero waker is asserted") - } - - if w.Clear() { - t.Fatalf("Zero waker is asserted") - } -} - -// AssertedWakerAfterAssert tests that a waker properly reports its state as -// asserted once its Assert() method is called. -func AssertedWakerAfterAssert(t *testing.T) { - var w Waker - w.Assert() - if !w.IsAsserted() { - t.Fatalf("Asserted waker is not reported as such") - } - - if !w.Clear() { - t.Fatalf("Asserted waker is not reported as such") - } -} - -// AssertedWakerAfterTwoAsserts tests that a waker properly reports its state as -// asserted once its Assert() method is called twice. -func AssertedWakerAfterTwoAsserts(t *testing.T) { - var w Waker - w.Assert() - w.Assert() - if !w.IsAsserted() { - t.Fatalf("Asserted waker is not reported as such") - } - - if !w.Clear() { - t.Fatalf("Asserted waker is not reported as such") - } -} - -// NotAssertedWakerWithSleeper tests that a waker properly reports its state as -// not asserted after a sleeper is associated with it. -func NotAssertedWakerWithSleeper(t *testing.T) { - var w Waker - var s Sleeper - s.AddWaker(&w) - if w.IsAsserted() { - t.Fatalf("Non-asserted waker is reported as asserted") - } - - if w.Clear() { - t.Fatalf("Non-asserted waker is reported as asserted") - } -} - -// NotAssertedWakerAfterWake tests that a waker properly reports its state as -// not asserted after a previous assert is consumed by a sleeper. That is, tests -// the "edge-triggered" behavior. -func NotAssertedWakerAfterWake(t *testing.T) { - var w Waker - var s Sleeper - s.AddWaker(&w) - w.Assert() - s.Fetch(true) - if w.IsAsserted() { - t.Fatalf("Consumed waker is reported as asserted") - } - - if w.Clear() { - t.Fatalf("Consumed waker is reported as asserted") - } -} - -// AssertedWakerBeforeAdd tests that a waker causes a sleeper to not sleep if -// it's already asserted before being added. -func AssertedWakerBeforeAdd(t *testing.T) { - var w Waker - var s Sleeper - w.Assert() - s.AddWaker(&w) - - if s.Fetch(false) != &w { - t.Fatalf("Fetch did not match waker") - } -} - -// ClearedWaker tests that a waker properly reports its state as not asserted -// after it is cleared. -func ClearedWaker(t *testing.T) { - var w Waker - w.Assert() - w.Clear() - if w.IsAsserted() { - t.Fatalf("Cleared waker is reported as asserted") - } - - if w.Clear() { - t.Fatalf("Cleared waker is reported as asserted") - } -} - -// ClearedWakerWithSleeper tests that a waker properly reports its state as -// not asserted when it is cleared while it has a sleeper associated with it. -func ClearedWakerWithSleeper(t *testing.T) { - var w Waker - var s Sleeper - s.AddWaker(&w) - w.Clear() - if w.IsAsserted() { - t.Fatalf("Cleared waker is reported as asserted") - } - - if w.Clear() { - t.Fatalf("Cleared waker is reported as asserted") - } -} - -// ClearedWakerAssertedWithSleeper tests that a waker properly reports its state -// as not asserted when it is cleared while it has a sleeper associated with it -// and has been asserted. -func ClearedWakerAssertedWithSleeper(t *testing.T) { - var w Waker - var s Sleeper - s.AddWaker(&w) - w.Assert() - w.Clear() - if w.IsAsserted() { - t.Fatalf("Cleared waker is reported as asserted") - } - - if w.Clear() { - t.Fatalf("Cleared waker is reported as asserted") - } -} - -// TestBlock tests that a sleeper actually blocks waiting for the waker to -// assert its state. -func TestBlock(t *testing.T) { - var w Waker - var s Sleeper - - s.AddWaker(&w) - - // Assert waker after one second. - before := time.Now() - time.AfterFunc(time.Second, w.Assert) - - // Fetch the result and make sure it took at least 500ms. - if s.Fetch(true) != &w { - t.Fatalf("Fetch did not match waker") - } - if d := time.Now().Sub(before); d < 500*time.Millisecond { - t.Fatalf("Duration was too short: %v", d) - } - - // Check that already-asserted waker completes inline. - w.Assert() - if s.Fetch(true) != &w { - t.Fatalf("Fetch did not match waker") - } - - // Check that fetch sleeps if waker had been asserted but was reset - // before Fetch is called. - w.Assert() - w.Clear() - before = time.Now() - time.AfterFunc(time.Second, w.Assert) - - if s.Fetch(true) != &w { - t.Fatalf("Fetch did not match waker") - } - if d := time.Now().Sub(before); d < 500*time.Millisecond { - t.Fatalf("Duration was too short: %v", d) - } -} - -// TestNonBlock checks that a sleeper won't block if waker isn't asserted. -func TestNonBlock(t *testing.T) { - var w Waker - var s Sleeper - - // Don't block when there's no waker. - if s.Fetch(false) != nil { - t.Fatalf("Fetch succeeded when there is no waker") - } - - // Don't block when waker isn't asserted. - s.AddWaker(&w) - if s.Fetch(false) != nil { - t.Fatalf("Fetch succeeded when waker was not asserted") - } - - // Don't block when waker was asserted, but isn't anymore. - w.Assert() - w.Clear() - if s.Fetch(false) != nil { - t.Fatalf("Fetch succeeded when waker was not asserted anymore") - } - - // Don't block when waker was consumed by previous Fetch(). - w.Assert() - if s.Fetch(false) != &w { - t.Fatalf("Fetch failed even though waker was asserted") - } - - if s.Fetch(false) != nil { - t.Fatalf("Fetch succeeded when waker had been consumed") - } -} - -// TestMultiple checks that a sleeper can wait for and receives notifications -// from multiple wakers. -func TestMultiple(t *testing.T) { - s := Sleeper{} - w1 := Waker{} - w2 := Waker{} - - s.AddWaker(&w1) - s.AddWaker(&w2) - - w1.Assert() - w2.Assert() - - v := s.Fetch(false) - if v == nil { - t.Fatalf("Fetch failed when there are asserted wakers") - } - if v != &w1 && v != &w2 { - t.Fatalf("Unexpected waker: %v", v) - } - - want := &w1 - if v == want { - want = &w2 // Other waiter. - } - v = s.Fetch(false) - if v == nil { - t.Fatalf("Fetch failed when there is an asserted waker") - } - if v != want { - t.Fatalf("Unexpected waker, got %v, want %v", v, want) - } -} - -// TestDoneFunction tests if calling Done() on a sleeper works properly. -func TestDoneFunction(t *testing.T) { - // Trivial case of no waker. - s := Sleeper{} - s.Done() - - // Cases when the sleeper has n wakers, but none are asserted. - for n := 1; n < 20; n++ { - s := Sleeper{} - w := make([]Waker, n) - for j := 0; j < n; j++ { - s.AddWaker(&w[j]) - } - s.Done() - } - - // Cases when the sleeper has n wakers, and only the i-th one is - // asserted. - for n := 1; n < 20; n++ { - for i := 0; i < n; i++ { - s := Sleeper{} - w := make([]Waker, n) - for j := 0; j < n; j++ { - s.AddWaker(&w[j]) - } - w[i].Assert() - s.Done() - } - } - - // Cases when the sleeper has n wakers, and the i-th one is asserted - // and cleared. - for n := 1; n < 20; n++ { - for i := 0; i < n; i++ { - s := Sleeper{} - w := make([]Waker, n) - for j := 0; j < n; j++ { - s.AddWaker(&w[j]) - } - w[i].Assert() - w[i].Clear() - s.Done() - } - } - - // Cases when the sleeper has n wakers, with a random number of them - // asserted. - for n := 1; n < 20; n++ { - for iters := 0; iters < 1000; iters++ { - s := Sleeper{} - w := make([]Waker, n) - for j := 0; j < n; j++ { - s.AddWaker(&w[j]) - } - - // Pick the number of asserted elements, then assert - // random wakers. - asserted := rand.Int() % (n + 1) - for j := 0; j < asserted; j++ { - w[rand.Int()%n].Assert() - } - s.Done() - } - } -} - -// TestRace tests that multiple wakers can continuously send wake requests to -// the sleeper. -func TestRace(t *testing.T) { - const wakers = 100 - const wakeRequests = 10000 - - counts := make(map[*Waker]int, wakers) - s := Sleeper{} - - // Associate each waker and start goroutines that will assert them. - for i := 0; i < wakers; i++ { - var w Waker - s.AddWaker(&w) - go func() { - n := 0 - for n < wakeRequests { - if !w.IsAsserted() { - w.Assert() - n++ - } else { - runtime.Gosched() - } - } - }() - } - - // Wait for all wake up notifications from all wakers. - for i := 0; i < wakers*wakeRequests; i++ { - v := s.Fetch(true) - counts[v]++ - } - - // Check that we got the right number for each. - if got := len(counts); got != wakers { - t.Errorf("Got %d wakers, wanted %d", got, wakers) - } - for _, count := range counts { - if count != wakeRequests { - t.Errorf("Waker only got %d wakes, wanted %d", count, wakeRequests) - } - } -} - -// TestRaceInOrder tests that multiple wakers can continuously send wake requests to -// the sleeper and that the wakers are retrieved in the order asserted. -func TestRaceInOrder(t *testing.T) { - w := make([]Waker, 10000) - s := Sleeper{} - - // Associate each waker and start goroutines that will assert them. - for i := range w { - s.AddWaker(&w[i]) - } - go func() { - for i := range w { - w[i].Assert() - } - }() - - // Wait for all wake up notifications from all wakers. - for i := range w { - got := s.Fetch(true) - if want := &w[i]; got != want { - t.Fatalf("got %v want %v", got, want) - } - } -} - -// BenchmarkSleeperMultiSelect measures how long it takes to fetch a wake up -// from 4 wakers when at least one is already asserted. -func BenchmarkSleeperMultiSelect(b *testing.B) { - const count = 4 - s := Sleeper{} - w := make([]Waker, count) - for i := range w { - s.AddWaker(&w[i]) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - w[count-1].Assert() - s.Fetch(true) - } -} - -// BenchmarkGoMultiSelect measures how long it takes to fetch a zero-length -// struct from one of 4 channels when at least one is ready. -func BenchmarkGoMultiSelect(b *testing.B) { - const count = 4 - ch := make([]chan struct{}, count) - for i := range ch { - ch[i] = make(chan struct{}, 1) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - ch[count-1] <- struct{}{} - select { - case <-ch[0]: - case <-ch[1]: - case <-ch[2]: - case <-ch[3]: - } - } -} - -// BenchmarkSleeperSingleSelect measures how long it takes to fetch a wake up -// from one waker that is already asserted. -func BenchmarkSleeperSingleSelect(b *testing.B) { - s := Sleeper{} - w := Waker{} - s.AddWaker(&w) - - b.ResetTimer() - for i := 0; i < b.N; i++ { - w.Assert() - s.Fetch(true) - } -} - -// BenchmarkGoSingleSelect measures how long it takes to fetch a zero-length -// struct from a channel that already has it buffered. -func BenchmarkGoSingleSelect(b *testing.B) { - ch := make(chan struct{}, 1) - - b.ResetTimer() - for i := 0; i < b.N; i++ { - ch <- struct{}{} - <-ch - } -} - -// BenchmarkSleeperAssertNonWaiting measures how long it takes to assert a -// channel that is already asserted. -func BenchmarkSleeperAssertNonWaiting(b *testing.B) { - w := Waker{} - w.Assert() - for i := 0; i < b.N; i++ { - w.Assert() - } - -} - -// BenchmarkGoAssertNonWaiting measures how long it takes to write to a channel -// that has already something written to it. -func BenchmarkGoAssertNonWaiting(b *testing.B) { - ch := make(chan struct{}, 1) - ch <- struct{}{} - for i := 0; i < b.N; i++ { - select { - case ch <- struct{}{}: - default: - } - } -} - -// BenchmarkSleeperWaitOnSingleSelect measures how long it takes to wait on one -// waker channel while another goroutine wakes up the sleeper. -func BenchmarkSleeperWaitOnSingleSelect(b *testing.B) { - var ( - s Sleeper - w Waker - ns Sleeper - nw Waker - ) - ns.AddWaker(&nw) - s.AddWaker(&w) - go func() { - for i := 0; i < b.N; i++ { - ns.Fetch(true) - w.Assert() - } - }() - for i := 0; i < b.N; i++ { - nw.Assert() - s.Fetch(true) - } -} - -// BenchmarkGoWaitOnSingleSelect measures how long it takes to wait on one -// channel while another goroutine wakes up the sleeper. -func BenchmarkGoWaitOnSingleSelect(b *testing.B) { - ch := make(chan struct{}, 1) - nch := make(chan struct{}, 1) - go func() { - for i := 0; i < b.N; i++ { - <-nch - ch <- struct{}{} - } - }() - for i := 0; i < b.N; i++ { - nch <- struct{}{} - <-ch - } -} - -// BenchmarkSleeperWaitOnMultiSelect measures how long it takes to wait on 4 -// wakers while another goroutine wakes up the sleeper. -func BenchmarkSleeperWaitOnMultiSelect(b *testing.B) { - const count = 4 - var ( - s Sleeper - ns Sleeper - nw Waker - ) - ns.AddWaker(&nw) - w := make([]Waker, count) - for i := range w { - s.AddWaker(&w[i]) - } - - b.ResetTimer() - go func() { - for i := 0; i < b.N; i++ { - ns.Fetch(true) - w[count-1].Assert() - } - }() - for i := 0; i < b.N; i++ { - nw.Assert() - s.Fetch(true) - } -} - -// BenchmarkGoWaitOnMultiSelect measures how long it takes to wait on 4 channels -// while another goroutine wakes up the sleeper. -func BenchmarkGoWaitOnMultiSelect(b *testing.B) { - const count = 4 - ch := make([]chan struct{}, count) - nch := make([]chan struct{}, count) - for i := range ch { - ch[i] = make(chan struct{}, 1) - nch[i] = make(chan struct{}, 1) - } - - b.ResetTimer() - go func() { - for i := 0; i < b.N; i++ { - select { - case <-nch[0]: - case <-nch[1]: - case <-nch[2]: - case <-nch[3]: - } - ch[count-1] <- struct{}{} - } - }() - for i := 0; i < b.N; i++ { - nch[count-1] <- struct{}{} - select { - case <-ch[0]: - case <-ch[1]: - case <-ch[2]: - case <-ch[3]: - } - } -} |