1// Copyright 2014 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package context_test 6 7import ( 8 . "context" 9 "fmt" 10 "runtime" 11 "sync" 12 "testing" 13 "time" 14) 15 16func BenchmarkCommonParentCancel(b *testing.B) { 17 root := WithValue(Background(), "key", "value") 18 shared, sharedcancel := WithCancel(root) 19 defer sharedcancel() 20 21 b.ResetTimer() 22 b.RunParallel(func(pb *testing.PB) { 23 x := 0 24 for pb.Next() { 25 ctx, cancel := WithCancel(shared) 26 if ctx.Value("key").(string) != "value" { 27 b.Fatal("should not be reached") 28 } 29 for i := 0; i < 100; i++ { 30 x /= x + 1 31 } 32 cancel() 33 for i := 0; i < 100; i++ { 34 x /= x + 1 35 } 36 } 37 }) 38} 39 40func BenchmarkWithTimeout(b *testing.B) { 41 for concurrency := 40; concurrency <= 4e5; concurrency *= 100 { 42 name := fmt.Sprintf("concurrency=%d", concurrency) 43 b.Run(name, func(b *testing.B) { 44 benchmarkWithTimeout(b, concurrency) 45 }) 46 } 47} 48 49func benchmarkWithTimeout(b *testing.B, concurrentContexts int) { 50 gomaxprocs := runtime.GOMAXPROCS(0) 51 perPContexts := concurrentContexts / gomaxprocs 52 root := Background() 53 54 // Generate concurrent contexts. 55 var wg sync.WaitGroup 56 ccf := make([][]CancelFunc, gomaxprocs) 57 for i := range ccf { 58 wg.Add(1) 59 go func(i int) { 60 defer wg.Done() 61 cf := make([]CancelFunc, perPContexts) 62 for j := range cf { 63 _, cf[j] = WithTimeout(root, time.Hour) 64 } 65 ccf[i] = cf 66 }(i) 67 } 68 wg.Wait() 69 70 b.ResetTimer() 71 b.RunParallel(func(pb *testing.PB) { 72 wcf := make([]CancelFunc, 10) 73 for pb.Next() { 74 for i := range wcf { 75 _, wcf[i] = WithTimeout(root, time.Hour) 76 } 77 for _, f := range wcf { 78 f() 79 } 80 } 81 }) 82 b.StopTimer() 83 84 for _, cf := range ccf { 85 for _, f := range cf { 86 f() 87 } 88 } 89} 90 91func BenchmarkCancelTree(b *testing.B) { 92 depths := []int{1, 10, 100, 1000} 93 for _, d := range depths { 94 b.Run(fmt.Sprintf("depth=%d", d), func(b *testing.B) { 95 b.Run("Root=Background", func(b *testing.B) { 96 for i := 0; i < b.N; i++ { 97 buildContextTree(Background(), d) 98 } 99 }) 100 b.Run("Root=OpenCanceler", func(b *testing.B) { 101 for i := 0; i < b.N; i++ { 102 ctx, cancel := WithCancel(Background()) 103 buildContextTree(ctx, d) 104 cancel() 105 } 106 }) 107 b.Run("Root=ClosedCanceler", func(b *testing.B) { 108 for i := 0; i < b.N; i++ { 109 ctx, cancel := WithCancel(Background()) 110 cancel() 111 buildContextTree(ctx, d) 112 } 113 }) 114 }) 115 } 116} 117 118func buildContextTree(root Context, depth int) { 119 for d := 0; d < depth; d++ { 120 root, _ = WithCancel(root) 121 } 122} 123 124func BenchmarkCheckCanceled(b *testing.B) { 125 ctx, cancel := WithCancel(Background()) 126 cancel() 127 b.Run("Err", func(b *testing.B) { 128 for i := 0; i < b.N; i++ { 129 ctx.Err() 130 } 131 }) 132 b.Run("Done", func(b *testing.B) { 133 for i := 0; i < b.N; i++ { 134 select { 135 case <-ctx.Done(): 136 default: 137 } 138 } 139 }) 140} 141