Skip to content

Commit ebbd407

Browse files
committed
fastdto attempt.
Signed-off-by: bwplotka <[email protected]>
1 parent 6da4db6 commit ebbd407

File tree

11 files changed

+226
-125
lines changed

11 files changed

+226
-125
lines changed

prometheus/counter.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"sync/atomic"
2020
"time"
2121

22+
"github.com/prometheus/client_golang/prometheus/internal/fastdto"
2223
dto "github.com/prometheus/client_model/go"
2324
"google.golang.org/protobuf/types/known/timestamppb"
2425
)
@@ -94,7 +95,7 @@ func NewCounter(opts CounterOpts) Counter {
9495
if opts.now == nil {
9596
opts.now = time.Now
9697
}
97-
result := &counter{desc: desc, labelPairs: desc.labelPairs, now: opts.now}
98+
result := &counter{desc: desc, labelPairs: fastdto.ToDTOLabelPair(desc.labelPairs), now: opts.now}
9899
result.init(result) // Init self-collection.
99100
result.createdTs = timestamppb.New(opts.now())
100101
return result

prometheus/desc.go

+12-17
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,8 @@ import (
1919
"strings"
2020

2121
"github.com/cespare/xxhash/v2"
22-
dto "github.com/prometheus/client_model/go"
22+
"github.com/prometheus/client_golang/prometheus/internal/fastdto"
2323
"github.com/prometheus/common/model"
24-
"google.golang.org/protobuf/proto"
25-
26-
"github.com/prometheus/client_golang/prometheus/internal"
2724
)
2825

2926
// Desc is the descriptor used by every Prometheus Metric. It is essentially
@@ -56,7 +53,7 @@ type Desc struct {
5653
variableLabelOrder []int
5754
// labelPairs contains the sorted DTO label pairs based on the constant labels
5855
// and variable labels
59-
labelPairs []*dto.LabelPair
56+
labelPairs []fastdto.LabelPair
6057
// id is a hash of the values of the ConstLabels and fqName. This
6158
// must be unique among all registered descriptors and can therefore be
6259
// used as an identifier of the descriptor.
@@ -164,24 +161,23 @@ func (v2) NewDesc(fqName, help string, variableLabels ConstrainableLabels, const
164161
}
165162
d.dimHash = xxh.Sum64()
166163

167-
d.labelPairs = make([]*dto.LabelPair, 0, len(constLabels)+len(d.variableLabels.names))
164+
d.labelPairs = make([]fastdto.LabelPair, len(constLabels)+len(d.variableLabels.names))
165+
i := 0
168166
for n, v := range constLabels {
169-
d.labelPairs = append(d.labelPairs, &dto.LabelPair{
170-
Name: proto.String(n),
171-
Value: proto.String(v),
172-
})
167+
d.labelPairs[i].Name = n
168+
d.labelPairs[i].Value = v
169+
i++
173170
}
174171
for _, labelName := range d.variableLabels.names {
175-
d.labelPairs = append(d.labelPairs, &dto.LabelPair{
176-
Name: proto.String(labelName),
177-
})
172+
d.labelPairs[i].Name = labelName
173+
i++
178174
}
179-
sort.Sort(internal.LabelPairSorter(d.labelPairs))
175+
sort.Sort(fastdto.LabelPairSorter(d.labelPairs))
180176

181177
d.variableLabelOrder = make([]int, len(d.variableLabels.names))
182178
for outputIndex, pair := range d.labelPairs {
183179
// Constant labels have values variable labels do not.
184-
if pair.Value != nil {
180+
if pair.Value != "" {
185181
continue
186182
}
187183
for sourceIndex, variableLabel := range d.variableLabels.names {
@@ -190,7 +186,6 @@ func (v2) NewDesc(fqName, help string, variableLabels ConstrainableLabels, const
190186
}
191187
}
192188
}
193-
194189
return d
195190
}
196191

@@ -207,7 +202,7 @@ func NewInvalidDesc(err error) *Desc {
207202
func (d *Desc) String() string {
208203
lpStrings := make([]string, 0, len(d.labelPairs))
209204
for _, lp := range d.labelPairs {
210-
if lp.Value == nil {
205+
if lp.Value == "" {
211206
continue
212207
}
213208
lpStrings = append(

prometheus/desc_test.go

+10
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ func TestNewInvalidDesc_String(t *testing.T) {
6363
}
6464
}
6565

66+
/*
67+
export bench=newDesc && go test ./prometheus \
68+
-run '^$' -bench '^BenchmarkNewDesc/labels=10' \
69+
-benchtime 5s -benchmem -cpu 2 -timeout 999m \
70+
-memprofile=${bench}.mem.pprof \
71+
| tee ${bench}.txt
72+
73+
*/
6674
func BenchmarkNewDesc(b *testing.B) {
6775
for _, bm := range []struct {
6876
labelCount int
@@ -82,6 +90,8 @@ func BenchmarkNewDesc(b *testing.B) {
8290
},
8391
} {
8492
b.Run(fmt.Sprintf("labels=%v", bm.labelCount), func(b *testing.B) {
93+
b.ReportAllocs()
94+
b.ResetTimer()
8595
for i := 0; i < b.N; i++ {
8696
bm.descFunc()
8797
}

prometheus/gauge.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"sync/atomic"
1919
"time"
2020

21+
"github.com/prometheus/client_golang/prometheus/internal/fastdto"
2122
dto "github.com/prometheus/client_model/go"
2223
)
2324

@@ -82,7 +83,7 @@ func NewGauge(opts GaugeOpts) Gauge {
8283
nil,
8384
opts.ConstLabels,
8485
)
85-
result := &gauge{desc: desc, labelPairs: desc.labelPairs}
86+
result := &gauge{desc: desc, labelPairs: fastdto.ToDTOLabelPair(desc.labelPairs)}
8687
result.init(result) // Init self-collection.
8788
return result
8889
}

prometheus/histogram.go

+44-44
Original file line numberDiff line numberDiff line change
@@ -956,13 +956,13 @@ func (h *histogram) limitBuckets(counts *histogramCounts, value float64, bucket
956956
// h.nativeHistogramMinResetDuration has been passed. It returns true if the
957957
// histogram has been reset. The caller must have locked h.mtx.
958958
func (h *histogram) maybeReset(
959-
hot, cold *histogramCounts, coldIdx uint64, value float64, bucket int,
959+
hot, cold *histogramCounts, coldIdx uint64, value float64, bucket int,
960960
) bool {
961961
// We are using the possibly mocked h.now() rather than
962962
// time.Since(h.lastResetTime) to enable testing.
963963
if h.nativeHistogramMinResetDuration == 0 || // No reset configured.
964-
h.resetScheduled || // Do not interefere if a reset is already scheduled.
965-
h.now().Sub(h.lastResetTime) < h.nativeHistogramMinResetDuration {
964+
h.resetScheduled || // Do not interefere if a reset is already scheduled.
965+
h.now().Sub(h.lastResetTime) < h.nativeHistogramMinResetDuration {
966966
return false
967967
}
968968
// Completely reset coldCounts.
@@ -1355,11 +1355,11 @@ func (h *constHistogram) Write(out *dto.Metric) error {
13551355
// NewConstHistogram returns an error if the length of labelValues is not
13561356
// consistent with the variable labels in Desc or if Desc is invalid.
13571357
func NewConstHistogram(
1358-
desc *Desc,
1359-
count uint64,
1360-
sum float64,
1361-
buckets map[float64]uint64,
1362-
labelValues ...string,
1358+
desc *Desc,
1359+
count uint64,
1360+
sum float64,
1361+
buckets map[float64]uint64,
1362+
labelValues ...string,
13631363
) (Metric, error) {
13641364
if desc.err != nil {
13651365
return nil, desc.err
@@ -1379,11 +1379,11 @@ func NewConstHistogram(
13791379
// MustNewConstHistogram is a version of NewConstHistogram that panics where
13801380
// NewConstHistogram would have returned an error.
13811381
func MustNewConstHistogram(
1382-
desc *Desc,
1383-
count uint64,
1384-
sum float64,
1385-
buckets map[float64]uint64,
1386-
labelValues ...string,
1382+
desc *Desc,
1383+
count uint64,
1384+
sum float64,
1385+
buckets map[float64]uint64,
1386+
labelValues ...string,
13871387
) Metric {
13881388
m, err := NewConstHistogram(desc, count, sum, buckets, labelValues...)
13891389
if err != nil {
@@ -1394,12 +1394,12 @@ func MustNewConstHistogram(
13941394

13951395
// NewConstHistogramWithCreatedTimestamp does the same thing as NewConstHistogram but sets the created timestamp.
13961396
func NewConstHistogramWithCreatedTimestamp(
1397-
desc *Desc,
1398-
count uint64,
1399-
sum float64,
1400-
buckets map[float64]uint64,
1401-
ct time.Time,
1402-
labelValues ...string,
1397+
desc *Desc,
1398+
count uint64,
1399+
sum float64,
1400+
buckets map[float64]uint64,
1401+
ct time.Time,
1402+
labelValues ...string,
14031403
) (Metric, error) {
14041404
if desc.err != nil {
14051405
return nil, desc.err
@@ -1420,12 +1420,12 @@ func NewConstHistogramWithCreatedTimestamp(
14201420
// MustNewConstHistogramWithCreatedTimestamp is a version of NewConstHistogramWithCreatedTimestamp that panics where
14211421
// NewConstHistogramWithCreatedTimestamp would have returned an error.
14221422
func MustNewConstHistogramWithCreatedTimestamp(
1423-
desc *Desc,
1424-
count uint64,
1425-
sum float64,
1426-
buckets map[float64]uint64,
1427-
ct time.Time,
1428-
labelValues ...string,
1423+
desc *Desc,
1424+
count uint64,
1425+
sum float64,
1426+
buckets map[float64]uint64,
1427+
ct time.Time,
1428+
labelValues ...string,
14291429
) Metric {
14301430
m, err := NewConstHistogramWithCreatedTimestamp(desc, count, sum, buckets, ct, labelValues...)
14311431
if err != nil {
@@ -1873,7 +1873,7 @@ func validateCount(sum float64, count uint64, negativeBuckets, positiveBuckets m
18731873
// Otherwise, the number of observations must be equal to the sum of all bucket counts .
18741874

18751875
if math.IsNaN(sum) && bucketPopulationSum > int64(count) ||
1876-
!math.IsNaN(sum) && bucketPopulationSum != int64(count) {
1876+
!math.IsNaN(sum) && bucketPopulationSum != int64(count) {
18771877
return errors.New("the sum of all bucket populations exceeds the count of observations")
18781878
}
18791879
return nil
@@ -1902,15 +1902,15 @@ func validateCount(sum float64, count uint64, negativeBuckets, positiveBuckets m
19021902
//
19031903
// See https://opentelemetry.io/docs/specs/otel/compatibility/prometheus_and_openmetrics/#exponential-histograms for more details about the conversion from OTel to Prometheus.
19041904
func NewConstNativeHistogram(
1905-
desc *Desc,
1906-
count uint64,
1907-
sum float64,
1908-
positiveBuckets, negativeBuckets map[int]int64,
1909-
zeroBucket uint64,
1910-
schema int32,
1911-
zeroThreshold float64,
1912-
createdTimestamp time.Time,
1913-
labelValues ...string,
1905+
desc *Desc,
1906+
count uint64,
1907+
sum float64,
1908+
positiveBuckets, negativeBuckets map[int]int64,
1909+
zeroBucket uint64,
1910+
schema int32,
1911+
zeroThreshold float64,
1912+
createdTimestamp time.Time,
1913+
labelValues ...string,
19141914
) (Metric, error) {
19151915
if desc.err != nil {
19161916
return nil, desc.err
@@ -1958,15 +1958,15 @@ func NewConstNativeHistogram(
19581958
// MustNewConstNativeHistogram is a version of NewConstNativeHistogram that panics where
19591959
// NewConstNativeHistogram would have returned an error.
19601960
func MustNewConstNativeHistogram(
1961-
desc *Desc,
1962-
count uint64,
1963-
sum float64,
1964-
positiveBuckets, negativeBuckets map[int]int64,
1965-
zeroBucket uint64,
1966-
nativeHistogramSchema int32,
1967-
nativeHistogramZeroThreshold float64,
1968-
createdTimestamp time.Time,
1969-
labelValues ...string,
1961+
desc *Desc,
1962+
count uint64,
1963+
sum float64,
1964+
positiveBuckets, negativeBuckets map[int]int64,
1965+
zeroBucket uint64,
1966+
nativeHistogramSchema int32,
1967+
nativeHistogramZeroThreshold float64,
1968+
createdTimestamp time.Time,
1969+
labelValues ...string,
19701970
) Metric {
19711971
nativehistogram, err := NewConstNativeHistogram(desc,
19721972
count,

prometheus/internal/fastdto/labels.go

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package fastdto
2+
3+
import (
4+
dto "github.com/prometheus/client_model/go"
5+
)
6+
7+
type LabelPair struct {
8+
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
9+
Value string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"`
10+
}
11+
12+
func (p LabelPair) GetName() string {
13+
return p.Name
14+
}
15+
16+
func (p LabelPair) GetValue() string {
17+
return p.Value
18+
}
19+
20+
// LabelPairSorter implements sort.Interface. It is used to sort a slice of
21+
// LabelPairs
22+
type LabelPairSorter []LabelPair
23+
24+
func (s LabelPairSorter) Len() int {
25+
return len(s)
26+
}
27+
28+
func (s LabelPairSorter) Swap(i, j int) {
29+
s[i], s[j] = s[j], s[i]
30+
}
31+
32+
func (s LabelPairSorter) Less(i, j int) bool {
33+
return s[i].Name < s[j].Name
34+
}
35+
36+
func ToDTOLabelPair(in []LabelPair) []*dto.LabelPair {
37+
ret := make([]*dto.LabelPair, len(in))
38+
for i := range in {
39+
ret[i] = &dto.LabelPair{
40+
Name: &(in[i].Name),
41+
Value: &(in[i].Value),
42+
}
43+
}
44+
return ret
45+
}
+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package fastdto
2+
3+
import (
4+
"sort"
5+
"testing"
6+
7+
"github.com/google/go-cmp/cmp"
8+
"github.com/google/go-cmp/cmp/cmpopts"
9+
dto "github.com/prometheus/client_model/go"
10+
"google.golang.org/protobuf/proto"
11+
)
12+
13+
func BenchmarkToDTOLabelPairs(b *testing.B) {
14+
test := []LabelPair{
15+
{"foo", "bar"},
16+
{"foo2", "bar2"},
17+
{"foo3", "bar3"},
18+
}
19+
b.ReportAllocs()
20+
b.ResetTimer()
21+
for i := 0; i < b.N; i++ {
22+
_ = ToDTOLabelPair(test)
23+
}
24+
}
25+
26+
func TestLabelPairSorter(t *testing.T) {
27+
test := []LabelPair{
28+
{"foo3", "bar3"},
29+
{"foo", "bar"},
30+
{"foo2", "bar2"},
31+
}
32+
sort.Sort(LabelPairSorter(test))
33+
34+
expected := []LabelPair{
35+
{"foo", "bar"},
36+
{"foo2", "bar2"},
37+
{"foo3", "bar3"},
38+
}
39+
if diff := cmp.Diff(test, expected); diff != "" {
40+
t.Fatal(diff)
41+
}
42+
}
43+
44+
func TestToDTOLabelPair(t *testing.T) {
45+
test := []LabelPair{
46+
{"foo", "bar"},
47+
{"foo2", "bar2"},
48+
{"foo3", "bar3"},
49+
}
50+
expected := []*dto.LabelPair{
51+
{Name: proto.String("foo"), Value: proto.String("bar")},
52+
{Name: proto.String("foo2"), Value: proto.String("bar2")},
53+
{Name: proto.String("foo3"), Value: proto.String("bar3")},
54+
}
55+
if diff := cmp.Diff(ToDTOLabelPair(test), expected, cmpopts.IgnoreUnexported(dto.LabelPair{})); diff != "" {
56+
t.Fatal(diff)
57+
}
58+
}

0 commit comments

Comments
 (0)