| 1 | // Copyright 2020 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 | |
| 5 | package event_test |
| 6 | |
| 7 | import ( |
| 8 | "context" |
| 9 | "io/ioutil" |
| 10 | "log" |
| 11 | "testing" |
| 12 | |
| 13 | "golang.org/x/tools/internal/event" |
| 14 | "golang.org/x/tools/internal/event/core" |
| 15 | "golang.org/x/tools/internal/event/export" |
| 16 | "golang.org/x/tools/internal/event/keys" |
| 17 | "golang.org/x/tools/internal/event/label" |
| 18 | ) |
| 19 | |
| 20 | type Hooks struct { |
| 21 | A func(ctx context.Context, a int) (context.Context, func()) |
| 22 | B func(ctx context.Context, b string) (context.Context, func()) |
| 23 | } |
| 24 | |
| 25 | var ( |
| 26 | aValue = keys.NewInt("a", "") |
| 27 | bValue = keys.NewString("b", "") |
| 28 | aCount = keys.NewInt64("aCount", "Count of time A is called.") |
| 29 | aStat = keys.NewInt("aValue", "A value.") |
| 30 | bCount = keys.NewInt64("B", "Count of time B is called.") |
| 31 | bLength = keys.NewInt("BLen", "B length.") |
| 32 | |
| 33 | Baseline = Hooks{ |
| 34 | A: func(ctx context.Context, a int) (context.Context, func()) { |
| 35 | return ctx, func() {} |
| 36 | }, |
| 37 | B: func(ctx context.Context, b string) (context.Context, func()) { |
| 38 | return ctx, func() {} |
| 39 | }, |
| 40 | } |
| 41 | |
| 42 | StdLog = Hooks{ |
| 43 | A: func(ctx context.Context, a int) (context.Context, func()) { |
| 44 | log.Printf("A where a=%d", a) |
| 45 | return ctx, func() {} |
| 46 | }, |
| 47 | B: func(ctx context.Context, b string) (context.Context, func()) { |
| 48 | log.Printf("B where b=%q", b) |
| 49 | return ctx, func() {} |
| 50 | }, |
| 51 | } |
| 52 | |
| 53 | Log = Hooks{ |
| 54 | A: func(ctx context.Context, a int) (context.Context, func()) { |
| 55 | core.Log1(ctx, "A", aValue.Of(a)) |
| 56 | return ctx, func() {} |
| 57 | }, |
| 58 | B: func(ctx context.Context, b string) (context.Context, func()) { |
| 59 | core.Log1(ctx, "B", bValue.Of(b)) |
| 60 | return ctx, func() {} |
| 61 | }, |
| 62 | } |
| 63 | |
| 64 | Trace = Hooks{ |
| 65 | A: func(ctx context.Context, a int) (context.Context, func()) { |
| 66 | return core.Start1(ctx, "A", aValue.Of(a)) |
| 67 | }, |
| 68 | B: func(ctx context.Context, b string) (context.Context, func()) { |
| 69 | return core.Start1(ctx, "B", bValue.Of(b)) |
| 70 | }, |
| 71 | } |
| 72 | |
| 73 | Stats = Hooks{ |
| 74 | A: func(ctx context.Context, a int) (context.Context, func()) { |
| 75 | core.Metric1(ctx, aStat.Of(a)) |
| 76 | core.Metric1(ctx, aCount.Of(1)) |
| 77 | return ctx, func() {} |
| 78 | }, |
| 79 | B: func(ctx context.Context, b string) (context.Context, func()) { |
| 80 | core.Metric1(ctx, bLength.Of(len(b))) |
| 81 | core.Metric1(ctx, bCount.Of(1)) |
| 82 | return ctx, func() {} |
| 83 | }, |
| 84 | } |
| 85 | |
| 86 | initialList = []int{0, 1, 22, 333, 4444, 55555, 666666, 7777777} |
| 87 | stringList = []string{ |
| 88 | "A value", |
| 89 | "Some other value", |
| 90 | "A nice longer value but not too long", |
| 91 | "V", |
| 92 | "", |
| 93 | "ı", |
| 94 | "prime count of values", |
| 95 | } |
| 96 | ) |
| 97 | |
| 98 | type namedBenchmark struct { |
| 99 | name string |
| 100 | test func(*testing.B) |
| 101 | } |
| 102 | |
| 103 | func Benchmark(b *testing.B) { |
| 104 | b.Run("Baseline", Baseline.runBenchmark) |
| 105 | b.Run("StdLog", StdLog.runBenchmark) |
| 106 | benchmarks := []namedBenchmark{ |
| 107 | {"Log", Log.runBenchmark}, |
| 108 | {"Trace", Trace.runBenchmark}, |
| 109 | {"Stats", Stats.runBenchmark}, |
| 110 | } |
| 111 | |
| 112 | event.SetExporter(nil) |
| 113 | for _, t := range benchmarks { |
| 114 | b.Run(t.name+"NoExporter", t.test) |
| 115 | } |
| 116 | |
| 117 | event.SetExporter(noopExporter) |
| 118 | for _, t := range benchmarks { |
| 119 | b.Run(t.name+"Noop", t.test) |
| 120 | } |
| 121 | |
| 122 | event.SetExporter(export.Spans(export.LogWriter(ioutil.Discard, false))) |
| 123 | for _, t := range benchmarks { |
| 124 | b.Run(t.name, t.test) |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | func A(ctx context.Context, hooks Hooks, a int) int { |
| 129 | ctx, done := hooks.A(ctx, a) |
| 130 | defer done() |
| 131 | return B(ctx, hooks, a, stringList[a%len(stringList)]) |
| 132 | } |
| 133 | |
| 134 | func B(ctx context.Context, hooks Hooks, a int, b string) int { |
| 135 | _, done := hooks.B(ctx, b) |
| 136 | defer done() |
| 137 | return a + len(b) |
| 138 | } |
| 139 | |
| 140 | func (hooks Hooks) runBenchmark(b *testing.B) { |
| 141 | ctx := context.Background() |
| 142 | b.ReportAllocs() |
| 143 | b.ResetTimer() |
| 144 | var acc int |
| 145 | for i := 0; i < b.N; i++ { |
| 146 | for _, value := range initialList { |
| 147 | acc += A(ctx, hooks, value) |
| 148 | } |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | func init() { |
| 153 | log.SetOutput(ioutil.Discard) |
| 154 | } |
| 155 | |
| 156 | func noopExporter(ctx context.Context, ev core.Event, lm label.Map) context.Context { |
| 157 | return ctx |
| 158 | } |
| 159 |
Members