| // Copyright 2014 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package context_test | |
| import ( | |
| . "context" | |
| "fmt" | |
| "runtime" | |
| "sync" | |
| "testing" | |
| "time" | |
| ) | |
| func BenchmarkCommonParentCancel(b *testing.B) { | |
| root := WithValue(Background(), "key", "value") | |
| shared, sharedcancel := WithCancel(root) | |
| defer sharedcancel() | |
| b.ResetTimer() | |
| b.RunParallel(func(pb *testing.PB) { | |
| x := 0 | |
| for pb.Next() { | |
| ctx, cancel := WithCancel(shared) | |
| if ctx.Value("key").(string) != "value" { | |
| b.Fatal("should not be reached") | |
| } | |
| for i := 0; i < 100; i++ { | |
| x /= x + 1 | |
| } | |
| cancel() | |
| for i := 0; i < 100; i++ { | |
| x /= x + 1 | |
| } | |
| } | |
| }) | |
| } | |
| func BenchmarkWithTimeout(b *testing.B) { | |
| for concurrency := 40; concurrency <= 4e5; concurrency *= 100 { | |
| name := fmt.Sprintf("concurrency=%d", concurrency) | |
| b.Run(name, func(b *testing.B) { | |
| benchmarkWithTimeout(b, concurrency) | |
| }) | |
| } | |
| } | |
| func benchmarkWithTimeout(b *testing.B, concurrentContexts int) { | |
| gomaxprocs := runtime.GOMAXPROCS(0) | |
| perPContexts := concurrentContexts / gomaxprocs | |
| root := Background() | |
| // Generate concurrent contexts. | |
| var wg sync.WaitGroup | |
| ccf := make([][]CancelFunc, gomaxprocs) | |
| for i := range ccf { | |
| wg.Add(1) | |
| go func(i int) { | |
| defer wg.Done() | |
| cf := make([]CancelFunc, perPContexts) | |
| for j := range cf { | |
| _, cf[j] = WithTimeout(root, time.Hour) | |
| } | |
| ccf[i] = cf | |
| }(i) | |
| } | |
| wg.Wait() | |
| b.ResetTimer() | |
| b.RunParallel(func(pb *testing.PB) { | |
| wcf := make([]CancelFunc, 10) | |
| for pb.Next() { | |
| for i := range wcf { | |
| _, wcf[i] = WithTimeout(root, time.Hour) | |
| } | |
| for _, f := range wcf { | |
| f() | |
| } | |
| } | |
| }) | |
| b.StopTimer() | |
| for _, cf := range ccf { | |
| for _, f := range cf { | |
| f() | |
| } | |
| } | |
| } | |
| func BenchmarkCancelTree(b *testing.B) { | |
| depths := []int{1, 10, 100, 1000} | |
| for _, d := range depths { | |
| b.Run(fmt.Sprintf("depth=%d", d), func(b *testing.B) { | |
| b.Run("Root=Background", func(b *testing.B) { | |
| for i := 0; i < b.N; i++ { | |
| buildContextTree(Background(), d) | |
| } | |
| }) | |
| b.Run("Root=OpenCanceler", func(b *testing.B) { | |
| for i := 0; i < b.N; i++ { | |
| ctx, cancel := WithCancel(Background()) | |
| buildContextTree(ctx, d) | |
| cancel() | |
| } | |
| }) | |
| b.Run("Root=ClosedCanceler", func(b *testing.B) { | |
| for i := 0; i < b.N; i++ { | |
| ctx, cancel := WithCancel(Background()) | |
| cancel() | |
| buildContextTree(ctx, d) | |
| } | |
| }) | |
| }) | |
| } | |
| } | |
| func buildContextTree(root Context, depth int) { | |
| for d := 0; d < depth; d++ { | |
| root, _ = WithCancel(root) | |
| } | |
| } | |
| func BenchmarkCheckCanceled(b *testing.B) { | |
| ctx, cancel := WithCancel(Background()) | |
| cancel() | |
| b.Run("Err", func(b *testing.B) { | |
| for i := 0; i < b.N; i++ { | |
| ctx.Err() | |
| } | |
| }) | |
| b.Run("Done", func(b *testing.B) { | |
| for i := 0; i < b.N; i++ { | |
| select { | |
| case <-ctx.Done(): | |
| default: | |
| } | |
| } | |
| }) | |
| } | |
| func BenchmarkContextCancelDone(b *testing.B) { | |
| ctx, cancel := WithCancel(Background()) | |
| defer cancel() | |
| b.RunParallel(func(pb *testing.PB) { | |
| for pb.Next() { | |
| select { | |
| case <-ctx.Done(): | |
| default: | |
| } | |
| } | |
| }) | |
| } | |
| func BenchmarkDeepValueNewGoRoutine(b *testing.B) { | |
| for _, depth := range []int{10, 20, 30, 50, 100} { | |
| ctx := Background() | |
| for i := 0; i < depth; i++ { | |
| ctx = WithValue(ctx, i, i) | |
| } | |
| b.Run(fmt.Sprintf("depth=%d", depth), func(b *testing.B) { | |
| for i := 0; i < b.N; i++ { | |
| var wg sync.WaitGroup | |
| wg.Add(1) | |
| go func() { | |
| defer wg.Done() | |
| ctx.Value(-1) | |
| }() | |
| wg.Wait() | |
| } | |
| }) | |
| } | |
| } | |
| func BenchmarkDeepValueSameGoRoutine(b *testing.B) { | |
| for _, depth := range []int{10, 20, 30, 50, 100} { | |
| ctx := Background() | |
| for i := 0; i < depth; i++ { | |
| ctx = WithValue(ctx, i, i) | |
| } | |
| b.Run(fmt.Sprintf("depth=%d", depth), func(b *testing.B) { | |
| for i := 0; i < b.N; i++ { | |
| ctx.Value(-1) | |
| } | |
| }) | |
| } | |
| } |