From 6ea99afaa0e266f31bd52da3a1c4d1298e87cce1 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Thu, 22 Feb 2024 09:15:43 -0800 Subject: [PATCH] log: Add benchmark tests (#4958) --- log/keyvalue_bench_test.go | 255 +++++++++++++++++++++++++++++++++++++ log/record_bench_test.go | 120 +++++++++++++++++ 2 files changed, 375 insertions(+) create mode 100644 log/keyvalue_bench_test.go create mode 100644 log/record_bench_test.go diff --git a/log/keyvalue_bench_test.go b/log/keyvalue_bench_test.go new file mode 100644 index 000000000..ea43cded1 --- /dev/null +++ b/log/keyvalue_bench_test.go @@ -0,0 +1,255 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package log_test + +import ( + "testing" + + "go.opentelemetry.io/otel/log" +) + +// Store results in a file scope var to ensure compiler does not optimize the +// test away. +var ( + outV log.Value + outKV log.KeyValue + + outAny any + outBool bool + outFloat64 float64 + outInt64 int64 + outMap []log.KeyValue + outSlice []log.Value + outStr string +) + +func BenchmarkBool(b *testing.B) { + const k, v = "bool", true + + b.Run("Value", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outV = log.BoolValue(v) + } + }) + b.Run("KeyValue", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outKV = log.Bool(k, v) + } + }) + + kv := log.Bool(k, v) + b.Run("AsBool", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outBool = kv.Value.AsBool() + } + }) + b.Run("AsAny", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outAny = kv.Value.AsAny() + } + }) +} + +func BenchmarkFloat64(b *testing.B) { + const k, v = "float64", 3.0 + + b.Run("Value", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outV = log.Float64Value(v) + } + }) + b.Run("KeyValue", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outKV = log.Float64(k, v) + } + }) + + kv := log.Float64(k, v) + b.Run("AsFloat64", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outFloat64 = kv.Value.AsFloat64() + } + }) + b.Run("AsAny", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outAny = kv.Value.AsAny() + } + }) +} + +func BenchmarkInt(b *testing.B) { + const k, v = "int", 32 + + b.Run("Value", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outV = log.IntValue(v) + } + }) + b.Run("KeyValue", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outKV = log.Int(k, v) + } + }) + + kv := log.Int(k, v) + b.Run("AsInt64", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outInt64 = kv.Value.AsInt64() + } + }) + b.Run("AsAny", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outAny = kv.Value.AsAny() + } + }) +} + +func BenchmarkInt64(b *testing.B) { + const k, v = "int64", int64(32) + + b.Run("Value", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outV = log.Int64Value(v) + } + }) + b.Run("KeyValue", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outKV = log.Int64(k, v) + } + }) + + kv := log.Int64(k, v) + b.Run("AsInt64", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outInt64 = kv.Value.AsInt64() + } + }) + b.Run("AsAny", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outAny = kv.Value.AsAny() + } + }) +} + +func BenchmarkMap(b *testing.B) { + const k = "map" + v := []log.KeyValue{log.Bool("b", true), log.Int("i", 1)} + + b.Run("Value", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outV = log.MapValue(v...) + } + }) + b.Run("KeyValue", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outKV = log.Map(k, v...) + } + }) + + kv := log.Map(k, v...) + b.Run("AsMap", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outMap = kv.Value.AsMap() + } + }) + b.Run("AsAny", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outAny = kv.Value.AsAny() + } + }) +} + +func BenchmarkSlice(b *testing.B) { + const k = "slice" + v := []log.Value{log.BoolValue(true), log.IntValue(1)} + + b.Run("Value", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outV = log.SliceValue(v...) + } + }) + b.Run("KeyValue", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outKV = log.Slice(k, v...) + } + }) + + kv := log.Slice(k, v...) + b.Run("AsSlice", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outSlice = kv.Value.AsSlice() + } + }) + b.Run("AsAny", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outAny = kv.Value.AsAny() + } + }) +} + +func BenchmarkString(b *testing.B) { + const k, v = "str", "value" + + b.Run("Value", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outV = log.StringValue(v) + } + }) + b.Run("KeyValue", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outKV = log.String(k, v) + } + }) + + kv := log.String(k, v) + b.Run("AsString", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outStr = kv.Value.AsString() + } + }) + b.Run("AsAny", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + outAny = kv.Value.AsAny() + } + }) +} diff --git a/log/record_bench_test.go b/log/record_bench_test.go new file mode 100644 index 000000000..b83845ad9 --- /dev/null +++ b/log/record_bench_test.go @@ -0,0 +1,120 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package log_test + +import ( + "testing" + "time" + + "go.opentelemetry.io/otel/log" +) + +func BenchmarkRecord(b *testing.B) { + var ( + tStamp time.Time + sev log.Severity + text string + body log.Value + attr log.KeyValue + n int + ) + + b.Run("Timestamp", func(b *testing.B) { + b.ReportAllocs() + for n := 0; n < b.N; n++ { + var r log.Record + r.SetTimestamp(y2k) + tStamp = r.Timestamp() + } + }) + + b.Run("ObservedTimestamp", func(b *testing.B) { + b.ReportAllocs() + for n := 0; n < b.N; n++ { + var r log.Record + r.SetObservedTimestamp(y2k) + tStamp = r.ObservedTimestamp() + } + }) + + b.Run("Severity", func(b *testing.B) { + b.ReportAllocs() + for n := 0; n < b.N; n++ { + var r log.Record + r.SetSeverity(log.SeverityDebug) + sev = r.Severity() + } + }) + + b.Run("SeverityText", func(b *testing.B) { + b.ReportAllocs() + for n := 0; n < b.N; n++ { + var r log.Record + r.SetSeverityText("text") + text = r.SeverityText() + } + }) + + bodyVal := log.BoolValue(true) + b.Run("Body", func(b *testing.B) { + b.ReportAllocs() + for n := 0; n < b.N; n++ { + var r log.Record + r.SetBody(bodyVal) + body = r.Body() + } + }) + + attrs10 := []log.KeyValue{ + log.Bool("b1", true), + log.Int("i1", 324), + log.Float64("f1", -230.213), + log.String("s1", "value1"), + log.Map("m1", log.Slice("slice1", log.BoolValue(true))), + log.Bool("b2", false), + log.Int("i2", 39847), + log.Float64("f2", 0.382964329), + log.String("s2", "value2"), + log.Map("m2", log.Slice("slice2", log.BoolValue(false))), + } + attrs5 := attrs10[:5] + walk := func(kv log.KeyValue) bool { + attr = kv + return true + } + b.Run("Attributes", func(b *testing.B) { + b.Run("5", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + var r log.Record + r.AddAttributes(attrs5...) + n = r.AttributesLen() + r.WalkAttributes(walk) + } + }) + b.Run("10", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + var r log.Record + r.AddAttributes(attrs10...) + n = r.AttributesLen() + r.WalkAttributes(walk) + } + }) + }) + + // Convince the linter these values are used. + _, _, _, _, _, _ = tStamp, sev, text, body, attr, n +}