1// Copyright 2019, OpenTelemetry 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 15package metric_test 16 17import ( 18 "context" 19 "fmt" 20 "math/rand" 21 "strings" 22 "testing" 23 24 "go.opentelemetry.io/otel/api/core" 25 "go.opentelemetry.io/otel/api/key" 26 "go.opentelemetry.io/otel/api/metric" 27 export "go.opentelemetry.io/otel/sdk/export/metric" 28 sdk "go.opentelemetry.io/otel/sdk/metric" 29 "go.opentelemetry.io/otel/sdk/metric/aggregator/counter" 30 "go.opentelemetry.io/otel/sdk/metric/aggregator/ddsketch" 31 "go.opentelemetry.io/otel/sdk/metric/aggregator/gauge" 32 "go.opentelemetry.io/otel/sdk/metric/aggregator/minmaxsumcount" 33) 34 35type benchFixture struct { 36 sdk *sdk.SDK 37 B *testing.B 38} 39 40func newFixture(b *testing.B) *benchFixture { 41 b.ReportAllocs() 42 bf := &benchFixture{ 43 B: b, 44 } 45 bf.sdk = sdk.New(bf, sdk.NewDefaultLabelEncoder()) 46 return bf 47} 48 49func (*benchFixture) AggregatorFor(descriptor *export.Descriptor) export.Aggregator { 50 switch descriptor.MetricKind() { 51 case export.CounterKind: 52 return counter.New() 53 case export.GaugeKind: 54 return gauge.New() 55 case export.MeasureKind: 56 if strings.HasSuffix(descriptor.Name(), "minmaxsumcount") { 57 return minmaxsumcount.New(descriptor) 58 } else if strings.HasSuffix(descriptor.Name(), "ddsketch") { 59 return ddsketch.New(ddsketch.NewDefaultConfig(), descriptor) 60 } else if strings.HasSuffix(descriptor.Name(), "array") { 61 return ddsketch.New(ddsketch.NewDefaultConfig(), descriptor) 62 } 63 } 64 return nil 65} 66 67func (*benchFixture) Process(context.Context, export.Record) error { 68 return nil 69} 70 71func (*benchFixture) CheckpointSet() export.CheckpointSet { 72 return nil 73} 74 75func (*benchFixture) FinishedCollection() { 76} 77 78func makeLabelSets(n int) [][]core.KeyValue { 79 r := make([][]core.KeyValue, n) 80 81 for i := 0; i < n; i++ { 82 r[i] = makeLabels(1) 83 } 84 85 return r 86} 87 88func makeLabels(n int) []core.KeyValue { 89 used := map[string]bool{} 90 l := make([]core.KeyValue, n) 91 for i := 0; i < n; i++ { 92 var k string 93 for { 94 k = fmt.Sprint("k", rand.Intn(1000000000)) 95 if !used[k] { 96 used[k] = true 97 break 98 } 99 } 100 l[i] = key.New(k).String(fmt.Sprint("v", rand.Intn(1000000000))) 101 } 102 return l 103} 104 105func benchmarkLabels(b *testing.B, n int) { 106 fix := newFixture(b) 107 labs := makeLabels(n) 108 109 b.ResetTimer() 110 111 for i := 0; i < b.N; i++ { 112 fix.sdk.Labels(labs...) 113 } 114} 115 116func BenchmarkLabels_1(b *testing.B) { 117 benchmarkLabels(b, 1) 118} 119 120func BenchmarkLabels_2(b *testing.B) { 121 benchmarkLabels(b, 2) 122} 123 124func BenchmarkLabels_4(b *testing.B) { 125 benchmarkLabels(b, 4) 126} 127 128func BenchmarkLabels_8(b *testing.B) { 129 benchmarkLabels(b, 8) 130} 131 132func BenchmarkLabels_16(b *testing.B) { 133 benchmarkLabels(b, 16) 134} 135 136// Note: performance does not depend on label set size for the 137// benchmarks below. 138 139func BenchmarkAcquireNewHandle(b *testing.B) { 140 fix := newFixture(b) 141 labelSets := makeLabelSets(b.N) 142 cnt := fix.sdk.NewInt64Counter("int64.counter") 143 labels := make([]metric.LabelSet, b.N) 144 145 for i := 0; i < b.N; i++ { 146 labels[i] = fix.sdk.Labels(labelSets[i]...) 147 } 148 149 b.ResetTimer() 150 151 for i := 0; i < b.N; i++ { 152 cnt.Bind(labels[i]) 153 } 154} 155 156func BenchmarkAcquireExistingHandle(b *testing.B) { 157 fix := newFixture(b) 158 labelSets := makeLabelSets(b.N) 159 cnt := fix.sdk.NewInt64Counter("int64.counter") 160 labels := make([]metric.LabelSet, b.N) 161 162 for i := 0; i < b.N; i++ { 163 labels[i] = fix.sdk.Labels(labelSets[i]...) 164 cnt.Bind(labels[i]).Unbind() 165 } 166 167 b.ResetTimer() 168 169 for i := 0; i < b.N; i++ { 170 cnt.Bind(labels[i]) 171 } 172} 173 174func BenchmarkAcquireReleaseExistingHandle(b *testing.B) { 175 fix := newFixture(b) 176 labelSets := makeLabelSets(b.N) 177 cnt := fix.sdk.NewInt64Counter("int64.counter") 178 labels := make([]metric.LabelSet, b.N) 179 180 for i := 0; i < b.N; i++ { 181 labels[i] = fix.sdk.Labels(labelSets[i]...) 182 cnt.Bind(labels[i]).Unbind() 183 } 184 185 b.ResetTimer() 186 187 for i := 0; i < b.N; i++ { 188 cnt.Bind(labels[i]).Unbind() 189 } 190} 191 192// Counters 193 194func BenchmarkInt64CounterAdd(b *testing.B) { 195 ctx := context.Background() 196 fix := newFixture(b) 197 labs := fix.sdk.Labels(makeLabels(1)...) 198 cnt := fix.sdk.NewInt64Counter("int64.counter") 199 200 b.ResetTimer() 201 202 for i := 0; i < b.N; i++ { 203 cnt.Add(ctx, 1, labs) 204 } 205} 206 207func BenchmarkInt64CounterHandleAdd(b *testing.B) { 208 ctx := context.Background() 209 fix := newFixture(b) 210 labs := fix.sdk.Labels(makeLabels(1)...) 211 cnt := fix.sdk.NewInt64Counter("int64.counter") 212 handle := cnt.Bind(labs) 213 214 b.ResetTimer() 215 216 for i := 0; i < b.N; i++ { 217 handle.Add(ctx, 1) 218 } 219} 220 221func BenchmarkFloat64CounterAdd(b *testing.B) { 222 ctx := context.Background() 223 fix := newFixture(b) 224 labs := fix.sdk.Labels(makeLabels(1)...) 225 cnt := fix.sdk.NewFloat64Counter("float64.counter") 226 227 b.ResetTimer() 228 229 for i := 0; i < b.N; i++ { 230 cnt.Add(ctx, 1.1, labs) 231 } 232} 233 234func BenchmarkFloat64CounterHandleAdd(b *testing.B) { 235 ctx := context.Background() 236 fix := newFixture(b) 237 labs := fix.sdk.Labels(makeLabels(1)...) 238 cnt := fix.sdk.NewFloat64Counter("float64.counter") 239 handle := cnt.Bind(labs) 240 241 b.ResetTimer() 242 243 for i := 0; i < b.N; i++ { 244 handle.Add(ctx, 1.1) 245 } 246} 247 248// Gauges 249 250func BenchmarkInt64GaugeAdd(b *testing.B) { 251 ctx := context.Background() 252 fix := newFixture(b) 253 labs := fix.sdk.Labels(makeLabels(1)...) 254 gau := fix.sdk.NewInt64Gauge("int64.gauge") 255 256 b.ResetTimer() 257 258 for i := 0; i < b.N; i++ { 259 gau.Set(ctx, int64(i), labs) 260 } 261} 262 263func BenchmarkInt64GaugeHandleAdd(b *testing.B) { 264 ctx := context.Background() 265 fix := newFixture(b) 266 labs := fix.sdk.Labels(makeLabels(1)...) 267 gau := fix.sdk.NewInt64Gauge("int64.gauge") 268 handle := gau.Bind(labs) 269 270 b.ResetTimer() 271 272 for i := 0; i < b.N; i++ { 273 handle.Set(ctx, int64(i)) 274 } 275} 276 277func BenchmarkFloat64GaugeAdd(b *testing.B) { 278 ctx := context.Background() 279 fix := newFixture(b) 280 labs := fix.sdk.Labels(makeLabels(1)...) 281 gau := fix.sdk.NewFloat64Gauge("float64.gauge") 282 283 b.ResetTimer() 284 285 for i := 0; i < b.N; i++ { 286 gau.Set(ctx, float64(i), labs) 287 } 288} 289 290func BenchmarkFloat64GaugeHandleAdd(b *testing.B) { 291 ctx := context.Background() 292 fix := newFixture(b) 293 labs := fix.sdk.Labels(makeLabels(1)...) 294 gau := fix.sdk.NewFloat64Gauge("float64.gauge") 295 handle := gau.Bind(labs) 296 297 b.ResetTimer() 298 299 for i := 0; i < b.N; i++ { 300 handle.Set(ctx, float64(i)) 301 } 302} 303 304// Measures 305 306func benchmarkInt64MeasureAdd(b *testing.B, name string) { 307 ctx := context.Background() 308 fix := newFixture(b) 309 labs := fix.sdk.Labels(makeLabels(1)...) 310 mea := fix.sdk.NewInt64Measure(name) 311 312 b.ResetTimer() 313 314 for i := 0; i < b.N; i++ { 315 mea.Record(ctx, int64(i), labs) 316 } 317} 318 319func benchmarkInt64MeasureHandleAdd(b *testing.B, name string) { 320 ctx := context.Background() 321 fix := newFixture(b) 322 labs := fix.sdk.Labels(makeLabels(1)...) 323 mea := fix.sdk.NewInt64Measure(name) 324 handle := mea.Bind(labs) 325 326 b.ResetTimer() 327 328 for i := 0; i < b.N; i++ { 329 handle.Record(ctx, int64(i)) 330 } 331} 332 333func benchmarkFloat64MeasureAdd(b *testing.B, name string) { 334 ctx := context.Background() 335 fix := newFixture(b) 336 labs := fix.sdk.Labels(makeLabels(1)...) 337 mea := fix.sdk.NewFloat64Measure(name) 338 339 b.ResetTimer() 340 341 for i := 0; i < b.N; i++ { 342 mea.Record(ctx, float64(i), labs) 343 } 344} 345 346func benchmarkFloat64MeasureHandleAdd(b *testing.B, name string) { 347 ctx := context.Background() 348 fix := newFixture(b) 349 labs := fix.sdk.Labels(makeLabels(1)...) 350 mea := fix.sdk.NewFloat64Measure(name) 351 handle := mea.Bind(labs) 352 353 b.ResetTimer() 354 355 for i := 0; i < b.N; i++ { 356 handle.Record(ctx, float64(i)) 357 } 358} 359 360// MaxSumCount 361 362func BenchmarkInt64MaxSumCountAdd(b *testing.B) { 363 benchmarkInt64MeasureAdd(b, "int64.minmaxsumcount") 364} 365 366func BenchmarkInt64MaxSumCountHandleAdd(b *testing.B) { 367 benchmarkInt64MeasureHandleAdd(b, "int64.minmaxsumcount") 368} 369 370func BenchmarkFloat64MaxSumCountAdd(b *testing.B) { 371 benchmarkFloat64MeasureAdd(b, "float64.minmaxsumcount") 372} 373 374func BenchmarkFloat64MaxSumCountHandleAdd(b *testing.B) { 375 benchmarkFloat64MeasureHandleAdd(b, "float64.minmaxsumcount") 376} 377 378// DDSketch 379 380func BenchmarkInt64DDSketchAdd(b *testing.B) { 381 benchmarkInt64MeasureAdd(b, "int64.ddsketch") 382} 383 384func BenchmarkInt64DDSketchHandleAdd(b *testing.B) { 385 benchmarkInt64MeasureHandleAdd(b, "int64.ddsketch") 386} 387 388func BenchmarkFloat64DDSketchAdd(b *testing.B) { 389 benchmarkFloat64MeasureAdd(b, "float64.ddsketch") 390} 391 392func BenchmarkFloat64DDSketchHandleAdd(b *testing.B) { 393 benchmarkFloat64MeasureHandleAdd(b, "float64.ddsketch") 394} 395 396// Array 397 398func BenchmarkInt64ArrayAdd(b *testing.B) { 399 benchmarkInt64MeasureAdd(b, "int64.array") 400} 401 402func BenchmarkInt64ArrayHandleAdd(b *testing.B) { 403 benchmarkInt64MeasureHandleAdd(b, "int64.array") 404} 405 406func BenchmarkFloat64ArrayAdd(b *testing.B) { 407 benchmarkFloat64MeasureAdd(b, "float64.array") 408} 409 410func BenchmarkFloat64ArrayHandleAdd(b *testing.B) { 411 benchmarkFloat64MeasureHandleAdd(b, "float64.array") 412} 413