go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/data/caching/cacheContext/context_test.go (about)

     1  // Copyright 2016 The LUCI 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 cacheContext
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  
    21  	. "github.com/smartystreets/goconvey/convey"
    22  )
    23  
    24  func TestCacheContext(t *testing.T) {
    25  	t.Parallel()
    26  
    27  	Convey(`A caching Context populated with values`, t, func() {
    28  		const count = 3
    29  		c := context.Background()
    30  		for i := 0; i < count; i++ {
    31  			c = context.WithValue(c, i, i)
    32  		}
    33  		c = Wrap(c)
    34  
    35  		Convey(`Successfully caches values.`, func() {
    36  			// Perform initial lookup to cache.
    37  			for i := 0; i < count; i++ {
    38  				_ = c.Value(i)
    39  			}
    40  
    41  			// Cache absence of value.
    42  			c.Value("missing")
    43  
    44  			// Clear the Context. Any passthrough calls will now panic.
    45  			c.(*cacheContext).Context = nil
    46  			So(func() { c.Value("not cached") }, ShouldPanic)
    47  
    48  			// Confirm that lookups happen from cache.
    49  			for i := 0; i < count; i++ {
    50  				So(c.Value(i), ShouldEqual, i)
    51  			}
    52  			So(c.Value("missing"), ShouldBeNil)
    53  		})
    54  
    55  		Convey(`Will not double-wrap.`, func() {
    56  			So(Wrap(c), ShouldEqual, c)
    57  		})
    58  	})
    59  }
    60  
    61  func runLookupBenchmark(b *testing.B, depth int, cache bool) {
    62  	c := context.Background()
    63  	for i := 0; i <= depth; i++ {
    64  		c = context.WithValue(c, i, i)
    65  	}
    66  	if cache {
    67  		c = Wrap(c)
    68  	}
    69  
    70  	for round := 0; round < b.N; round++ {
    71  		// Lookup the value up a few times.
    72  		for i := 0; i < 5; i++ {
    73  			v, ok := c.Value(0).(int)
    74  			if !ok {
    75  				b.Fatal("failed to lookup 0")
    76  			}
    77  			if v != 0 {
    78  				b.Fatalf("lookup mismatch (%d != 0)", v)
    79  			}
    80  		}
    81  	}
    82  }
    83  
    84  func runParallelLookupBenchmark(b *testing.B, depth int, cache bool) {
    85  	c := context.Background()
    86  	for i := 0; i <= depth; i++ {
    87  		c = context.WithValue(c, i, i)
    88  	}
    89  	if cache {
    90  		c = Wrap(c)
    91  	}
    92  
    93  	b.RunParallel(func(pb *testing.PB) {
    94  		for pb.Next() {
    95  			// Lookup the value up a few times.
    96  			for i := 0; i < 5; i++ {
    97  				v, ok := c.Value(0).(int)
    98  				if !ok {
    99  					b.Fatal("failed to lookup 0")
   100  				}
   101  				if v != 0 {
   102  					b.Fatalf("lookup mismatch (%d != 0)", v)
   103  				}
   104  			}
   105  		}
   106  	})
   107  }
   108  
   109  // Results of running `go test -bench . -cpu=8`:
   110  //
   111  // BenchmarkStandardLookup1-8              12789495      92.0 ns/op
   112  // BenchmarkStandardLookup10-8              2374756       511 ns/op
   113  // BenchmarkStandardLookup50-8               401910      2552 ns/op
   114  // BenchmarkStandardLookup1000-8              22759     52650 ns/op
   115  // BenchmarkCachedLookup1-8                 5957251       204 ns/op
   116  // BenchmarkCachedLookup10-8                5783949       203 ns/op
   117  // BenchmarkCachedLookup50-8                5679669       205 ns/op
   118  // BenchmarkCachedLookup1000-8              5805810       201 ns/op
   119  // BenchmarkParallelStandardLookup1-8      44769181      23.4 ns/op
   120  // BenchmarkParallelStandardLookup10-8      7837178       137 ns/op
   121  // BenchmarkParallelStandardLookup50-8      1808611       612 ns/op
   122  // BenchmarkParallelStandardLookup1000-8      92068     12511 ns/op
   123  // BenchmarkParallelCachedLookup1-8         4062573       300 ns/op
   124  // BenchmarkParallelCachedLookup10-8        3488845       353 ns/op
   125  // BenchmarkParallelCachedLookup50-8        3603590       323 ns/op
   126  // BenchmarkParallelCachedLookup1000-8      3482008       351 ns/op
   127  
   128  func BenchmarkStandardLookup1(b *testing.B)    { runLookupBenchmark(b, 1, false) }
   129  func BenchmarkStandardLookup10(b *testing.B)   { runLookupBenchmark(b, 10, false) }
   130  func BenchmarkStandardLookup50(b *testing.B)   { runLookupBenchmark(b, 50, false) }
   131  func BenchmarkStandardLookup1000(b *testing.B) { runLookupBenchmark(b, 1000, false) }
   132  
   133  func BenchmarkCachedLookup1(b *testing.B)    { runLookupBenchmark(b, 1, true) }
   134  func BenchmarkCachedLookup10(b *testing.B)   { runLookupBenchmark(b, 10, true) }
   135  func BenchmarkCachedLookup50(b *testing.B)   { runLookupBenchmark(b, 50, true) }
   136  func BenchmarkCachedLookup1000(b *testing.B) { runLookupBenchmark(b, 1000, true) }
   137  
   138  func BenchmarkParallelStandardLookup1(b *testing.B)    { runParallelLookupBenchmark(b, 1, false) }
   139  func BenchmarkParallelStandardLookup10(b *testing.B)   { runParallelLookupBenchmark(b, 10, false) }
   140  func BenchmarkParallelStandardLookup50(b *testing.B)   { runParallelLookupBenchmark(b, 50, false) }
   141  func BenchmarkParallelStandardLookup1000(b *testing.B) { runParallelLookupBenchmark(b, 1000, false) }
   142  
   143  func BenchmarkParallelCachedLookup1(b *testing.B)    { runParallelLookupBenchmark(b, 1, true) }
   144  func BenchmarkParallelCachedLookup10(b *testing.B)   { runParallelLookupBenchmark(b, 10, true) }
   145  func BenchmarkParallelCachedLookup50(b *testing.B)   { runParallelLookupBenchmark(b, 50, true) }
   146  func BenchmarkParallelCachedLookup1000(b *testing.B) { runParallelLookupBenchmark(b, 1000, true) }