Provide custom marshalling for Point

Point has a non-standard marshalling, and is also
where the vast majority of CPU time is spent so
it is worth optimising.
This commit is contained in:
Brian Brazil 2018-02-07 12:27:57 +00:00
parent f35fca1c3f
commit cc39021b2b
2 changed files with 45 additions and 6 deletions

View File

@ -26,8 +26,9 @@ import (
"sort" "sort"
"strconv" "strconv"
"time" "time"
"unsafe"
"github.com/json-iterator/go" jsoniter "github.com/json-iterator/go"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/prometheus/common/route" "github.com/prometheus/common/route"
"github.com/prometheus/tsdb" "github.com/prometheus/tsdb"
@ -820,3 +821,41 @@ func parseDuration(s string) (time.Duration, error) {
} }
return 0, fmt.Errorf("cannot parse %q to a valid duration", s) return 0, fmt.Errorf("cannot parse %q to a valid duration", s)
} }
func init() {
jsoniter.RegisterTypeEncoderFunc("promql.Point", marshalPointJSON, marshalPointJSONIsEmpty)
}
func marshalPointJSON(ptr unsafe.Pointer, stream *jsoniter.Stream) {
p := *((*promql.Point)(ptr))
stream.WriteArrayStart()
// Write out the timestamp as a float divided by 1000.
// This is ~3x faster than converting to a float.
t := p.T
if t < 0 {
stream.WriteRaw(`-`)
t = -t
}
stream.WriteInt64(t / 1000)
fraction := t % 1000
if fraction != 0 {
stream.WriteRaw(`.`)
if fraction < 100 {
stream.WriteRaw(`0`)
}
if fraction < 10 {
stream.WriteRaw(`0`)
}
stream.WriteInt64(fraction)
}
stream.WriteMore()
stream.WriteRaw(`"`)
stream.WriteFloat64(p.V)
stream.WriteRaw(`"`)
stream.WriteArrayEnd()
}
func marshalPointJSONIsEmpty(ptr unsafe.Pointer) bool {
return false
}

View File

@ -882,11 +882,11 @@ func TestRespond(t *testing.T) {
}, },
{ {
response: promql.Point{V: 20, T: 10}, response: promql.Point{V: 20, T: 10},
expected: `{"status":"success","data":[0.01,"20"]}`, expected: `{"status":"success","data":[0.010,"20"]}`,
}, },
{ {
response: promql.Point{V: 20, T: 100}, response: promql.Point{V: 20, T: 100},
expected: `{"status":"success","data":[0.1,"20"]}`, expected: `{"status":"success","data":[0.100,"20"]}`,
}, },
{ {
response: promql.Point{V: 20, T: 1001}, response: promql.Point{V: 20, T: 1001},
@ -894,15 +894,15 @@ func TestRespond(t *testing.T) {
}, },
{ {
response: promql.Point{V: 20, T: 1010}, response: promql.Point{V: 20, T: 1010},
expected: `{"status":"success","data":[1.01,"20"]}`, expected: `{"status":"success","data":[1.010,"20"]}`,
}, },
{ {
response: promql.Point{V: 20, T: 1100}, response: promql.Point{V: 20, T: 1100},
expected: `{"status":"success","data":[1.1,"20"]}`, expected: `{"status":"success","data":[1.100,"20"]}`,
}, },
{ {
response: promql.Point{V: 20, T: 12345678123456555}, response: promql.Point{V: 20, T: 12345678123456555},
expected: `{"status":"success","data":[12345678123456.557,"20"]}`, expected: `{"status":"success","data":[12345678123456.555,"20"]}`,
}, },
{ {
response: promql.Point{V: 20, T: -1}, response: promql.Point{V: 20, T: -1},