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