Skip to content

Commit

Permalink
Performance improvements for attribute value AsStringSlice, `AsFloa…
Browse files Browse the repository at this point in the history
…t64Slice`, `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 <42@dmathieu.com>
  • Loading branch information
boekkooi-impossiblecloud and dmathieu authored Dec 3, 2024
1 parent 09105a9 commit 9f82e51
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Propagate non-retryable error messages to client in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. (#5929)
- Propagate non-retryable error messages to client in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#5929)
- Propagate non-retryable error messages to client in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#5929)
- Performance improvements for attribute value `AsStringSlice`, `AsFloat64Slice`, `AsInt64Slice`, `AsBoolSlice`. (#6011)

### Fixed

Expand Down
44 changes: 20 additions & 24 deletions internal/attribute/attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,11 @@ func AsBoolSlice(v interface{}) []bool {
if rv.Type().Kind() != reflect.Array {
return nil
}
var zero bool
correctLen := rv.Len()
correctType := reflect.ArrayOf(correctLen, reflect.TypeOf(zero))
cpy := reflect.New(correctType)
_ = reflect.Copy(cpy.Elem(), rv)
return cpy.Elem().Slice(0, correctLen).Interface().([]bool)
cpy := make([]bool, rv.Len())
if len(cpy) > 0 {
_ = reflect.Copy(reflect.ValueOf(cpy), rv)
}
return cpy
}

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

// AsFloat64Slice converts a float64 array into a slice into with same elements as array.
Expand All @@ -77,12 +75,11 @@ func AsFloat64Slice(v interface{}) []float64 {
if rv.Type().Kind() != reflect.Array {
return nil
}
var zero float64
correctLen := rv.Len()
correctType := reflect.ArrayOf(correctLen, reflect.TypeOf(zero))
cpy := reflect.New(correctType)
_ = reflect.Copy(cpy.Elem(), rv)
return cpy.Elem().Slice(0, correctLen).Interface().([]float64)
cpy := make([]float64, rv.Len())
if len(cpy) > 0 {
_ = reflect.Copy(reflect.ValueOf(cpy), rv)
}
return cpy
}

// AsStringSlice converts a string array into a slice into with same elements as array.
Expand All @@ -91,10 +88,9 @@ func AsStringSlice(v interface{}) []string {
if rv.Type().Kind() != reflect.Array {
return nil
}
var zero string
correctLen := rv.Len()
correctType := reflect.ArrayOf(correctLen, reflect.TypeOf(zero))
cpy := reflect.New(correctType)
_ = reflect.Copy(cpy.Elem(), rv)
return cpy.Elem().Slice(0, correctLen).Interface().([]string)
cpy := make([]string, rv.Len())
if len(cpy) > 0 {
_ = reflect.Copy(reflect.ValueOf(cpy), rv)
}
return cpy
}
10 changes: 10 additions & 0 deletions internal/attribute/attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,13 @@ func BenchmarkStringSliceValue(b *testing.B) {
sync = StringSliceValue(s)
}
}

func BenchmarkAsFloat64Slice(b *testing.B) {
b.ReportAllocs()
var in interface{} = [2]float64{1, 2.3}
b.ResetTimer()

for i := 0; i < b.N; i++ {
sync = AsFloat64Slice(in)
}
}

0 comments on commit 9f82e51

Please sign in to comment.