Skip to content

Commit

Permalink
avoid using reflection for floats
Browse files Browse the repository at this point in the history
  • Loading branch information
dashpole committed Mar 3, 2022
1 parent aea38a9 commit 7b87ae9
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 2 deletions.
35 changes: 33 additions & 2 deletions model/pdata/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"math"
"sort"
"strconv"

Expand Down Expand Up @@ -379,8 +380,7 @@ func (a AttributeValue) AsString() string {
return strconv.FormatBool(a.BoolVal())

case AttributeValueTypeDouble:
jsonStr, _ := json.Marshal(a.DoubleVal())
return string(jsonStr)
return float64AsString(a.DoubleVal())

case AttributeValueTypeInt:
return strconv.FormatInt(a.IntVal(), 10)
Expand All @@ -401,6 +401,37 @@ func (a AttributeValue) AsString() string {
}
}

// See https://cs.opensource.google/go/go/+/refs/tags/go1.17.7:src/encoding/json/encode.go;l=585.
// This allows up to avoid using reflection.
func float64AsString(f float64) string {
if math.IsInf(f, 0) || math.IsNaN(f) {
return fmt.Sprintf("json: unsupported value: %s", strconv.FormatFloat(f, 'g', -1, int(64)))
}

// Convert as if by ES6 number to string conversion.
// This matches most other JSON generators.
// See golang.org/issue/6384 and golang.org/issue/14135.
// Like fmt %g, but the exponent cutoffs are different
// and exponents themselves are not padded to two digits.
scratch := [64]byte{}
b := scratch[:0]
abs := math.Abs(f)
fmt := byte('f')
if abs != 0 && abs < 1e-6 || abs >= 1e21 {
fmt = 'e'
}
b = strconv.AppendFloat(b, f, fmt, -1, int(64))
if fmt == 'e' {
// clean up e-09 to e-9
n := len(b)
if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' {
b[n-2] = b[n-1]
b = b[:n-1]
}
}
return string(b)
}

func newAttributeKeyValueString(k string, v string) otlpcommon.KeyValue {
orig := otlpcommon.KeyValue{Key: k}
akv := AttributeValue{&orig.Value}
Expand Down
9 changes: 9 additions & 0 deletions model/pdata/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,15 @@ func BenchmarkAttributeValue_SetIntVal(b *testing.B) {
}
}

func BenchmarkAttributeValueFloat_AsString(b *testing.B) {
av := NewAttributeValueDouble(2359871345.583429543)

b.ResetTimer()
for n := 0; n < b.N; n++ {
av.AsString()
}
}

func BenchmarkAttributeMap_Range(b *testing.B) {
const numElements = 20
rawOrig := make([]otlpcommon.KeyValue, numElements)
Expand Down

0 comments on commit 7b87ae9

Please sign in to comment.