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) }