Skip to content

Commit 9f82e51

Browse files
Performance improvements for attribute value AsStringSlice, AsFloat64Slice, AsInt64Slice, AsBoolSlice (#6011)
Good day, This PR changes As[Bool|Int64|Float64|String]Slice to use a little less reflection. The benchstat result of this is as follows. ``` goos: linux goarch: amd64 pkg: go.opentelemetry.io/otel/internal/attribute cpu: AMD Ryzen 7 Pro 7735U with Radeon Graphics │ org.txt │ new.txt │ │ sec/op │ sec/op vs base │ AsFloat64Slice-16 373.3n ± 41% 181.0n ± 42% -51.51% (p=0.000 n=10) │ org.txt │ new.txt │ │ B/op │ B/op vs base │ AsFloat64Slice-16 64.00 ± 0% 40.00 ± 0% -37.50% (p=0.000 n=10) │ org.txt │ new.txt │ │ allocs/op │ allocs/op vs base │ AsFloat64Slice-16 3.000 ± 0% 2.000 ± 0% -33.33% (p=0.000 n=10) ``` --------- Co-authored-by: Damien Mathieu <[email protected]>
1 parent 09105a9 commit 9f82e51

File tree

3 files changed

+31
-24
lines changed

3 files changed

+31
-24
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1919
- Propagate non-retryable error messages to client in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. (#5929)
2020
- Propagate non-retryable error messages to client in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#5929)
2121
- Propagate non-retryable error messages to client in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#5929)
22+
- Performance improvements for attribute value `AsStringSlice`, `AsFloat64Slice`, `AsInt64Slice`, `AsBoolSlice`. (#6011)
2223

2324
### Fixed
2425

internal/attribute/attribute.go

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,11 @@ func AsBoolSlice(v interface{}) []bool {
4949
if rv.Type().Kind() != reflect.Array {
5050
return nil
5151
}
52-
var zero bool
53-
correctLen := rv.Len()
54-
correctType := reflect.ArrayOf(correctLen, reflect.TypeOf(zero))
55-
cpy := reflect.New(correctType)
56-
_ = reflect.Copy(cpy.Elem(), rv)
57-
return cpy.Elem().Slice(0, correctLen).Interface().([]bool)
52+
cpy := make([]bool, rv.Len())
53+
if len(cpy) > 0 {
54+
_ = reflect.Copy(reflect.ValueOf(cpy), rv)
55+
}
56+
return cpy
5857
}
5958

6059
// AsInt64Slice converts an int64 array into a slice into with same elements as array.
@@ -63,12 +62,11 @@ func AsInt64Slice(v interface{}) []int64 {
6362
if rv.Type().Kind() != reflect.Array {
6463
return nil
6564
}
66-
var zero int64
67-
correctLen := rv.Len()
68-
correctType := reflect.ArrayOf(correctLen, reflect.TypeOf(zero))
69-
cpy := reflect.New(correctType)
70-
_ = reflect.Copy(cpy.Elem(), rv)
71-
return cpy.Elem().Slice(0, correctLen).Interface().([]int64)
65+
cpy := make([]int64, rv.Len())
66+
if len(cpy) > 0 {
67+
_ = reflect.Copy(reflect.ValueOf(cpy), rv)
68+
}
69+
return cpy
7270
}
7371

7472
// AsFloat64Slice converts a float64 array into a slice into with same elements as array.
@@ -77,12 +75,11 @@ func AsFloat64Slice(v interface{}) []float64 {
7775
if rv.Type().Kind() != reflect.Array {
7876
return nil
7977
}
80-
var zero float64
81-
correctLen := rv.Len()
82-
correctType := reflect.ArrayOf(correctLen, reflect.TypeOf(zero))
83-
cpy := reflect.New(correctType)
84-
_ = reflect.Copy(cpy.Elem(), rv)
85-
return cpy.Elem().Slice(0, correctLen).Interface().([]float64)
78+
cpy := make([]float64, rv.Len())
79+
if len(cpy) > 0 {
80+
_ = reflect.Copy(reflect.ValueOf(cpy), rv)
81+
}
82+
return cpy
8683
}
8784

8885
// AsStringSlice converts a string array into a slice into with same elements as array.
@@ -91,10 +88,9 @@ func AsStringSlice(v interface{}) []string {
9188
if rv.Type().Kind() != reflect.Array {
9289
return nil
9390
}
94-
var zero string
95-
correctLen := rv.Len()
96-
correctType := reflect.ArrayOf(correctLen, reflect.TypeOf(zero))
97-
cpy := reflect.New(correctType)
98-
_ = reflect.Copy(cpy.Elem(), rv)
99-
return cpy.Elem().Slice(0, correctLen).Interface().([]string)
91+
cpy := make([]string, rv.Len())
92+
if len(cpy) > 0 {
93+
_ = reflect.Copy(reflect.ValueOf(cpy), rv)
94+
}
95+
return cpy
10096
}

internal/attribute/attribute_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,13 @@ func BenchmarkStringSliceValue(b *testing.B) {
133133
sync = StringSliceValue(s)
134134
}
135135
}
136+
137+
func BenchmarkAsFloat64Slice(b *testing.B) {
138+
b.ReportAllocs()
139+
var in interface{} = [2]float64{1, 2.3}
140+
b.ResetTimer()
141+
142+
for i := 0; i < b.N; i++ {
143+
sync = AsFloat64Slice(in)
144+
}
145+
}

0 commit comments

Comments
 (0)