gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sleep/sleep_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package sleep
    16  
    17  import (
    18  	"math/rand"
    19  	"runtime"
    20  	"sync"
    21  	"testing"
    22  	"time"
    23  
    24  	"gvisor.dev/gvisor/pkg/atomicbitops"
    25  )
    26  
    27  // ZeroWakerNotAsserted tests that a zero-value waker is in non-asserted state.
    28  func ZeroWakerNotAsserted(t *testing.T) {
    29  	var w Waker
    30  	if w.IsAsserted() {
    31  		t.Fatalf("Zero waker is asserted")
    32  	}
    33  
    34  	if w.Clear() {
    35  		t.Fatalf("Zero waker is asserted")
    36  	}
    37  }
    38  
    39  // AssertedWakerAfterAssert tests that a waker properly reports its state as
    40  // asserted once its Assert() method is called.
    41  func AssertedWakerAfterAssert(t *testing.T) {
    42  	var w Waker
    43  	w.Assert()
    44  	if !w.IsAsserted() {
    45  		t.Fatalf("Asserted waker is not reported as such")
    46  	}
    47  
    48  	if !w.Clear() {
    49  		t.Fatalf("Asserted waker is not reported as such")
    50  	}
    51  }
    52  
    53  // AssertedWakerAfterTwoAsserts tests that a waker properly reports its state as
    54  // asserted once its Assert() method is called twice.
    55  func AssertedWakerAfterTwoAsserts(t *testing.T) {
    56  	var w Waker
    57  	w.Assert()
    58  	w.Assert()
    59  	if !w.IsAsserted() {
    60  		t.Fatalf("Asserted waker is not reported as such")
    61  	}
    62  
    63  	if !w.Clear() {
    64  		t.Fatalf("Asserted waker is not reported as such")
    65  	}
    66  }
    67  
    68  // NotAssertedWakerWithSleeper tests that a waker properly reports its state as
    69  // not asserted after a sleeper is associated with it.
    70  func NotAssertedWakerWithSleeper(t *testing.T) {
    71  	var w Waker
    72  	var s Sleeper
    73  	s.AddWaker(&w)
    74  	if w.IsAsserted() {
    75  		t.Fatalf("Non-asserted waker is reported as asserted")
    76  	}
    77  
    78  	if w.Clear() {
    79  		t.Fatalf("Non-asserted waker is reported as asserted")
    80  	}
    81  }
    82  
    83  // NotAssertedWakerAfterWake tests that a waker properly reports its state as
    84  // not asserted after a previous assert is consumed by a sleeper. That is, tests
    85  // the "edge-triggered" behavior.
    86  func NotAssertedWakerAfterWake(t *testing.T) {
    87  	var w Waker
    88  	var s Sleeper
    89  	s.AddWaker(&w)
    90  	w.Assert()
    91  	s.Fetch(true)
    92  	if w.IsAsserted() {
    93  		t.Fatalf("Consumed waker is reported as asserted")
    94  	}
    95  
    96  	if w.Clear() {
    97  		t.Fatalf("Consumed waker is reported as asserted")
    98  	}
    99  }
   100  
   101  // AssertedWakerBeforeAdd tests that a waker causes a sleeper to not sleep if
   102  // it's already asserted before being added.
   103  func AssertedWakerBeforeAdd(t *testing.T) {
   104  	var w Waker
   105  	var s Sleeper
   106  	w.Assert()
   107  	s.AddWaker(&w)
   108  
   109  	if s.Fetch(false) != &w {
   110  		t.Fatalf("Fetch did not match waker")
   111  	}
   112  }
   113  
   114  // ClearedWaker tests that a waker properly reports its state as not asserted
   115  // after it is cleared.
   116  func ClearedWaker(t *testing.T) {
   117  	var w Waker
   118  	w.Assert()
   119  	w.Clear()
   120  	if w.IsAsserted() {
   121  		t.Fatalf("Cleared waker is reported as asserted")
   122  	}
   123  
   124  	if w.Clear() {
   125  		t.Fatalf("Cleared waker is reported as asserted")
   126  	}
   127  }
   128  
   129  // ClearedWakerWithSleeper tests that a waker properly reports its state as
   130  // not asserted when it is cleared while it has a sleeper associated with it.
   131  func ClearedWakerWithSleeper(t *testing.T) {
   132  	var w Waker
   133  	var s Sleeper
   134  	s.AddWaker(&w)
   135  	w.Clear()
   136  	if w.IsAsserted() {
   137  		t.Fatalf("Cleared waker is reported as asserted")
   138  	}
   139  
   140  	if w.Clear() {
   141  		t.Fatalf("Cleared waker is reported as asserted")
   142  	}
   143  }
   144  
   145  // ClearedWakerAssertedWithSleeper tests that a waker properly reports its state
   146  // as not asserted when it is cleared while it has a sleeper associated with it
   147  // and has been asserted.
   148  func ClearedWakerAssertedWithSleeper(t *testing.T) {
   149  	var w Waker
   150  	var s Sleeper
   151  	s.AddWaker(&w)
   152  	w.Assert()
   153  	w.Clear()
   154  	if w.IsAsserted() {
   155  		t.Fatalf("Cleared waker is reported as asserted")
   156  	}
   157  
   158  	if w.Clear() {
   159  		t.Fatalf("Cleared waker is reported as asserted")
   160  	}
   161  }
   162  
   163  // TestBlock tests that a sleeper actually blocks waiting for the waker to
   164  // assert its state.
   165  func TestBlock(t *testing.T) {
   166  	var w Waker
   167  	var s Sleeper
   168  
   169  	s.AddWaker(&w)
   170  
   171  	// Assert waker after one second.
   172  	before := time.Now()
   173  	time.AfterFunc(time.Second, w.Assert)
   174  
   175  	// Fetch the result and make sure it took at least 500ms.
   176  	if s.Fetch(true) != &w {
   177  		t.Fatalf("Fetch did not match waker")
   178  	}
   179  	if d := time.Now().Sub(before); d < 500*time.Millisecond {
   180  		t.Fatalf("Duration was too short: %v", d)
   181  	}
   182  
   183  	// Check that already-asserted waker completes inline.
   184  	w.Assert()
   185  	if s.Fetch(true) != &w {
   186  		t.Fatalf("Fetch did not match waker")
   187  	}
   188  
   189  	// Check that fetch sleeps if waker had been asserted but was reset
   190  	// before Fetch is called.
   191  	w.Assert()
   192  	w.Clear()
   193  	before = time.Now()
   194  	time.AfterFunc(time.Second, w.Assert)
   195  
   196  	if s.Fetch(true) != &w {
   197  		t.Fatalf("Fetch did not match waker")
   198  	}
   199  	if d := time.Now().Sub(before); d < 500*time.Millisecond {
   200  		t.Fatalf("Duration was too short: %v", d)
   201  	}
   202  }
   203  
   204  // TestNonBlock checks that a sleeper won't block if waker isn't asserted.
   205  func TestNonBlock(t *testing.T) {
   206  	var w Waker
   207  	var s Sleeper
   208  
   209  	// Don't block when there's no waker.
   210  	if s.Fetch(false) != nil {
   211  		t.Fatalf("Fetch succeeded when there is no waker")
   212  	}
   213  
   214  	// Don't block when waker isn't asserted.
   215  	s.AddWaker(&w)
   216  	if s.Fetch(false) != nil {
   217  		t.Fatalf("Fetch succeeded when waker was not asserted")
   218  	}
   219  
   220  	// Don't block when waker was asserted, but isn't anymore.
   221  	w.Assert()
   222  	w.Clear()
   223  	if s.Fetch(false) != nil {
   224  		t.Fatalf("Fetch succeeded when waker was not asserted anymore")
   225  	}
   226  
   227  	// Don't block when waker was consumed by previous Fetch().
   228  	w.Assert()
   229  	if s.Fetch(false) != &w {
   230  		t.Fatalf("Fetch failed even though waker was asserted")
   231  	}
   232  
   233  	if s.Fetch(false) != nil {
   234  		t.Fatalf("Fetch succeeded when waker had been consumed")
   235  	}
   236  }
   237  
   238  // TestMultiple checks that a sleeper can wait for and receives notifications
   239  // from multiple wakers.
   240  func TestMultiple(t *testing.T) {
   241  	s := Sleeper{}
   242  	w1 := Waker{}
   243  	w2 := Waker{}
   244  
   245  	s.AddWaker(&w1)
   246  	s.AddWaker(&w2)
   247  
   248  	w1.Assert()
   249  	w2.Assert()
   250  
   251  	v := s.Fetch(false)
   252  	if v == nil {
   253  		t.Fatalf("Fetch failed when there are asserted wakers")
   254  	}
   255  	if v != &w1 && v != &w2 {
   256  		t.Fatalf("Unexpected waker: %v", v)
   257  	}
   258  
   259  	want := &w1
   260  	if v == want {
   261  		want = &w2 // Other waiter.
   262  	}
   263  	v = s.Fetch(false)
   264  	if v == nil {
   265  		t.Fatalf("Fetch failed when there is an asserted waker")
   266  	}
   267  	if v != want {
   268  		t.Fatalf("Unexpected waker, got %v, want %v", v, want)
   269  	}
   270  }
   271  
   272  // TestDoneFunction tests if calling Done() on a sleeper works properly.
   273  func TestDoneFunction(t *testing.T) {
   274  	// Trivial case of no waker.
   275  	s := Sleeper{}
   276  	s.Done()
   277  
   278  	// Cases when the sleeper has n wakers, but none are asserted.
   279  	for n := 1; n < 20; n++ {
   280  		s := Sleeper{}
   281  		w := make([]Waker, n)
   282  		for j := 0; j < n; j++ {
   283  			s.AddWaker(&w[j])
   284  		}
   285  		s.Done()
   286  	}
   287  
   288  	// Cases when the sleeper has n wakers, and only the i-th one is
   289  	// asserted.
   290  	for n := 1; n < 20; n++ {
   291  		for i := 0; i < n; i++ {
   292  			s := Sleeper{}
   293  			w := make([]Waker, n)
   294  			for j := 0; j < n; j++ {
   295  				s.AddWaker(&w[j])
   296  			}
   297  			w[i].Assert()
   298  			s.Done()
   299  		}
   300  	}
   301  
   302  	// Cases when the sleeper has n wakers, and the i-th one is asserted
   303  	// and cleared.
   304  	for n := 1; n < 20; n++ {
   305  		for i := 0; i < n; i++ {
   306  			s := Sleeper{}
   307  			w := make([]Waker, n)
   308  			for j := 0; j < n; j++ {
   309  				s.AddWaker(&w[j])
   310  			}
   311  			w[i].Assert()
   312  			w[i].Clear()
   313  			s.Done()
   314  		}
   315  	}
   316  
   317  	// Cases when the sleeper has n wakers, with a random number of them
   318  	// asserted.
   319  	for n := 1; n < 20; n++ {
   320  		for iters := 0; iters < 1000; iters++ {
   321  			s := Sleeper{}
   322  			w := make([]Waker, n)
   323  			for j := 0; j < n; j++ {
   324  				s.AddWaker(&w[j])
   325  			}
   326  
   327  			// Pick the number of asserted elements, then assert
   328  			// random wakers.
   329  			asserted := rand.Int() % (n + 1)
   330  			for j := 0; j < asserted; j++ {
   331  				w[rand.Int()%n].Assert()
   332  			}
   333  			s.Done()
   334  		}
   335  	}
   336  }
   337  
   338  // TestAssertFetch tests basic assert fetch functionality.
   339  func TestAssertFetch(t *testing.T) {
   340  	const sleeperWakers = 100
   341  	const wakeRequests = 1000
   342  	const seedAsserts = 10
   343  
   344  	ws := make([]Waker, sleeperWakers)
   345  	ss := make([]Sleeper, sleeperWakers)
   346  	for i := 0; i < sleeperWakers; i++ {
   347  		ss[i].AddWaker(&ws[i])
   348  	}
   349  	defer func() {
   350  		for i := 0; i < sleeperWakers; i++ {
   351  			defer ss[i].Done()
   352  		}
   353  	}()
   354  	var (
   355  		count atomicbitops.Int32
   356  		wg    sync.WaitGroup
   357  	)
   358  	for i := 0; i < sleeperWakers; i++ {
   359  		wg.Add(1)
   360  		go func(i int) {
   361  			defer wg.Done()
   362  			ss[i].Fetch(true /* block */)
   363  			w := &ws[(i+1)%sleeperWakers]
   364  			for n := 0; n < wakeRequests; n++ {
   365  				count.Add(1)
   366  				ss[i].AssertAndFetch(w)
   367  			}
   368  			w.Assert() // Final wake-up.
   369  		}(i)
   370  	}
   371  
   372  	// Fire the first assertion.
   373  	ws[0].Assert()
   374  	wg.Wait()
   375  
   376  	// Check what we got.
   377  	if got, want := count.Load(), int32(sleeperWakers*wakeRequests); got != want {
   378  		t.Errorf("unexpected count: got %d, wanted %d", got, want)
   379  	}
   380  }
   381  
   382  // TestRace tests that multiple wakers can continuously send wake requests to
   383  // the sleeper.
   384  func TestRace(t *testing.T) {
   385  	const wakers = 100
   386  	const wakeRequests = 10000
   387  
   388  	counts := make(map[*Waker]int, wakers)
   389  	s := Sleeper{}
   390  
   391  	// Associate each waker and start goroutines that will assert them.
   392  	for i := 0; i < wakers; i++ {
   393  		var w Waker
   394  		s.AddWaker(&w)
   395  		go func() {
   396  			n := 0
   397  			for n < wakeRequests {
   398  				if !w.IsAsserted() {
   399  					w.Assert()
   400  					n++
   401  				} else {
   402  					runtime.Gosched()
   403  				}
   404  			}
   405  		}()
   406  	}
   407  
   408  	// Wait for all wake up notifications from all wakers.
   409  	for i := 0; i < wakers*wakeRequests; i++ {
   410  		v := s.Fetch(true)
   411  		counts[v]++
   412  	}
   413  
   414  	// Check that we got the right number for each.
   415  	if got := len(counts); got != wakers {
   416  		t.Errorf("Got %d wakers, wanted %d", got, wakers)
   417  	}
   418  	for _, count := range counts {
   419  		if count != wakeRequests {
   420  			t.Errorf("Waker only got %d wakes, wanted %d", count, wakeRequests)
   421  		}
   422  	}
   423  }
   424  
   425  // TestRaceInOrder tests that multiple wakers can continuously send wake requests to
   426  // the sleeper and that the wakers are retrieved in the order asserted.
   427  func TestRaceInOrder(t *testing.T) {
   428  	w := make([]Waker, 10000)
   429  	s := Sleeper{}
   430  
   431  	// Associate each waker and start goroutines that will assert them.
   432  	for i := range w {
   433  		s.AddWaker(&w[i])
   434  	}
   435  	go func() {
   436  		for i := range w {
   437  			w[i].Assert()
   438  		}
   439  	}()
   440  
   441  	// Wait for all wake up notifications from all wakers.
   442  	for i := range w {
   443  		got := s.Fetch(true)
   444  		if want := &w[i]; got != want {
   445  			t.Fatalf("got %v want %v", got, want)
   446  		}
   447  	}
   448  }
   449  
   450  // BenchmarkSleeperMultiSelect measures how long it takes to fetch a wake up
   451  // from 4 wakers when at least one is already asserted.
   452  func BenchmarkSleeperMultiSelect(b *testing.B) {
   453  	const count = 4
   454  	s := Sleeper{}
   455  	w := make([]Waker, count)
   456  	for i := range w {
   457  		s.AddWaker(&w[i])
   458  	}
   459  
   460  	b.ResetTimer()
   461  	for i := 0; i < b.N; i++ {
   462  		w[count-1].Assert()
   463  		s.Fetch(true)
   464  	}
   465  }
   466  
   467  // BenchmarkGoMultiSelect measures how long it takes to fetch a zero-length
   468  // struct from one of 4 channels when at least one is ready.
   469  func BenchmarkGoMultiSelect(b *testing.B) {
   470  	const count = 4
   471  	ch := make([]chan struct{}, count)
   472  	for i := range ch {
   473  		ch[i] = make(chan struct{}, 1)
   474  	}
   475  
   476  	b.ResetTimer()
   477  	for i := 0; i < b.N; i++ {
   478  		ch[count-1] <- struct{}{}
   479  		select {
   480  		case <-ch[0]:
   481  		case <-ch[1]:
   482  		case <-ch[2]:
   483  		case <-ch[3]:
   484  		}
   485  	}
   486  }
   487  
   488  // BenchmarkSleeperSingleSelect measures how long it takes to fetch a wake up
   489  // from one waker that is already asserted.
   490  func BenchmarkSleeperSingleSelect(b *testing.B) {
   491  	s := Sleeper{}
   492  	w := Waker{}
   493  	s.AddWaker(&w)
   494  
   495  	b.ResetTimer()
   496  	for i := 0; i < b.N; i++ {
   497  		w.Assert()
   498  		s.Fetch(true)
   499  	}
   500  }
   501  
   502  // BenchmarkGoSingleSelect measures how long it takes to fetch a zero-length
   503  // struct from a channel that already has it buffered.
   504  func BenchmarkGoSingleSelect(b *testing.B) {
   505  	ch := make(chan struct{}, 1)
   506  
   507  	b.ResetTimer()
   508  	for i := 0; i < b.N; i++ {
   509  		ch <- struct{}{}
   510  		<-ch
   511  	}
   512  }
   513  
   514  // BenchmarkSleeperAssertNonWaiting measures how long it takes to assert a
   515  // channel that is already asserted.
   516  func BenchmarkSleeperAssertNonWaiting(b *testing.B) {
   517  	w := Waker{}
   518  	w.Assert()
   519  	for i := 0; i < b.N; i++ {
   520  		w.Assert()
   521  	}
   522  
   523  }
   524  
   525  // BenchmarkGoAssertNonWaiting measures how long it takes to write to a channel
   526  // that has already something written to it.
   527  func BenchmarkGoAssertNonWaiting(b *testing.B) {
   528  	ch := make(chan struct{}, 1)
   529  	ch <- struct{}{}
   530  	for i := 0; i < b.N; i++ {
   531  		select {
   532  		case ch <- struct{}{}:
   533  		default:
   534  		}
   535  	}
   536  }
   537  
   538  // BenchmarkSleeperWaitOnSingleSelect measures how long it takes to wait on one
   539  // waker channel while another goroutine wakes up the sleeper.
   540  func BenchmarkSleeperWaitOnSingleSelect(b *testing.B) {
   541  	var (
   542  		s  Sleeper
   543  		w  Waker
   544  		ns Sleeper
   545  		nw Waker
   546  	)
   547  	ns.AddWaker(&nw)
   548  	s.AddWaker(&w)
   549  	go func() {
   550  		for i := 0; i < b.N; i++ {
   551  			ns.Fetch(true)
   552  			w.Assert()
   553  		}
   554  	}()
   555  	for i := 0; i < b.N; i++ {
   556  		nw.Assert()
   557  		s.Fetch(true)
   558  	}
   559  }
   560  
   561  // BenchmarkSleeperWaitOnSingleSelectSync is a modification of the similarly
   562  // named benchmark, except it uses the synchronous AssertAndFetch.
   563  func BenchmarkSleeperWaitOnSingleSelectSync(b *testing.B) {
   564  	var (
   565  		s  Sleeper
   566  		w  Waker
   567  		ns Sleeper
   568  		nw Waker
   569  	)
   570  	ns.AddWaker(&nw)
   571  	s.AddWaker(&w)
   572  	go func() {
   573  		ns.Fetch(true)
   574  		defer w.Assert()
   575  		for i := 0; i < b.N-1; i++ {
   576  			ns.AssertAndFetch(&w)
   577  		}
   578  	}()
   579  	for i := 0; i < b.N; i++ {
   580  		s.AssertAndFetch(&nw)
   581  	}
   582  }
   583  
   584  // BenchmarkGoWaitOnSingleSelect measures how long it takes to wait on one
   585  // channel while another goroutine wakes up the sleeper.
   586  func BenchmarkGoWaitOnSingleSelect(b *testing.B) {
   587  	ch := make(chan struct{}, 1)
   588  	nch := make(chan struct{}, 1)
   589  	go func() {
   590  		for i := 0; i < b.N; i++ {
   591  			<-nch
   592  			ch <- struct{}{}
   593  		}
   594  	}()
   595  	for i := 0; i < b.N; i++ {
   596  		nch <- struct{}{}
   597  		<-ch
   598  	}
   599  }
   600  
   601  // BenchmarkSleeperWaitOnMultiSelect measures how long it takes to wait on 4
   602  // wakers while another goroutine wakes up the sleeper.
   603  func BenchmarkSleeperWaitOnMultiSelect(b *testing.B) {
   604  	const count = 4
   605  	var (
   606  		s  Sleeper
   607  		ns Sleeper
   608  		nw Waker
   609  	)
   610  	ns.AddWaker(&nw)
   611  	w := make([]Waker, count)
   612  	for i := range w {
   613  		s.AddWaker(&w[i])
   614  	}
   615  
   616  	b.ResetTimer()
   617  	go func() {
   618  		for i := 0; i < b.N; i++ {
   619  			ns.Fetch(true)
   620  			w[count-1].Assert()
   621  		}
   622  	}()
   623  	for i := 0; i < b.N; i++ {
   624  		nw.Assert()
   625  		s.Fetch(true)
   626  	}
   627  }
   628  
   629  // BenchmarkSleeperWaitOnMultiSelectSync is a modification of the similarly
   630  // named benchmark, except it uses the synchronous AssertAndFetch.
   631  func BenchmarkSleeperWaitOnMultiSelectSync(b *testing.B) {
   632  	const count = 4
   633  	var (
   634  		s  Sleeper
   635  		ns Sleeper
   636  		nw Waker
   637  	)
   638  	ns.AddWaker(&nw)
   639  	w := make([]Waker, count)
   640  	for i := range w {
   641  		s.AddWaker(&w[i])
   642  	}
   643  
   644  	b.ResetTimer()
   645  	go func() {
   646  		ns.Fetch(true)
   647  		defer w[count-1].Assert()
   648  		for i := 0; i < b.N-1; i++ {
   649  			ns.AssertAndFetch(&w[count-1])
   650  		}
   651  	}()
   652  	for i := 0; i < b.N; i++ {
   653  		s.AssertAndFetch(&nw)
   654  	}
   655  }
   656  
   657  // BenchmarkGoWaitOnMultiSelect measures how long it takes to wait on 4 channels
   658  // while another goroutine wakes up the sleeper.
   659  func BenchmarkGoWaitOnMultiSelect(b *testing.B) {
   660  	const count = 4
   661  	ch := make([]chan struct{}, count)
   662  	nch := make([]chan struct{}, count)
   663  	for i := range ch {
   664  		ch[i] = make(chan struct{}, 1)
   665  		nch[i] = make(chan struct{}, 1)
   666  	}
   667  
   668  	b.ResetTimer()
   669  	go func() {
   670  		for i := 0; i < b.N; i++ {
   671  			select {
   672  			case <-nch[0]:
   673  			case <-nch[1]:
   674  			case <-nch[2]:
   675  			case <-nch[3]:
   676  			}
   677  			ch[count-1] <- struct{}{}
   678  		}
   679  	}()
   680  	for i := 0; i < b.N; i++ {
   681  		nch[count-1] <- struct{}{}
   682  		select {
   683  		case <-ch[0]:
   684  		case <-ch[1]:
   685  		case <-ch[2]:
   686  		case <-ch[3]:
   687  		}
   688  	}
   689  }