Skip to content

Commit 84fe356

Browse files
committed
Optimized.
Signed-off-by: Bartlomiej Plotka <[email protected]>
1 parent 6d0a430 commit 84fe356

File tree

7 files changed

+52
-59
lines changed

7 files changed

+52
-59
lines changed

prometheus/cache/cache.go

Lines changed: 26 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func (c *CachedTGatherer) Gather() (_ []*dto.MetricFamily, done func(), err erro
6060
c.mMu.RLock()
6161

6262
// BenchmarkCachedTGatherer_Update shows, even for 1 million metrics with 1000 families
63-
// this is efficient enough (~250µs 50 kB per op), no need to cache it for now.
63+
// this is efficient enough (~300µs and ~50 kB per op), no need to cache it for now.
6464
return internal.NormalizeMetricFamilies(c.metricFamilyByName), c.mMu.RUnlock, nil
6565
}
6666

@@ -114,6 +114,11 @@ type Insert struct {
114114
// Update goes through inserts and deletions and updates current cache in concurrency safe manner.
115115
// If reset is set to true, all inserts and deletions are working on empty cache. In such case
116116
// this implementation tries to reuse memory from existing cached item when possible.
117+
//
118+
// Update reuses insert struct memory, so after use, Insert slice and its elements cannot be reused
119+
// outside of this method.
120+
// TODO(bwplotka): Lack of copying can pose memory safety problems if insert variables are reused. Consider copying if value
121+
// is different. Yet it gives significant allocation gains.
117122
func (c *CachedTGatherer) Update(reset bool, inserts []Insert, deletions []Key) error {
118123
c.mMu.Lock()
119124
defer c.mMu.Unlock()
@@ -126,48 +131,48 @@ func (c *CachedTGatherer) Update(reset bool, inserts []Insert, deletions []Key)
126131
}
127132

128133
errs := prometheus.MultiError{}
129-
for _, ins := range inserts {
134+
for i := range inserts {
130135
// TODO(bwplotka): Validate more about this insert?
131-
if err := ins.isValid(); err != nil {
136+
if err := inserts[i].isValid(); err != nil {
132137
errs.Append(err)
133138
continue
134139
}
135140

136141
// Update metric family.
137-
mf, ok := c.metricFamilyByName[ins.FQName]
142+
mf, ok := c.metricFamilyByName[inserts[i].FQName]
138143
if !ok {
139144
mf = &dto.MetricFamily{}
140-
mf.Name = proto.String(ins.FQName)
145+
mf.Name = &inserts[i].FQName
141146
} else if reset {
142147
// Reset metric slice, since we want to start from scratch.
143148
mf.Metric = mf.Metric[:0]
144149
}
145-
mf.Type = ins.ValueType.ToDTO()
146-
mf.Help = proto.String(ins.Help)
150+
mf.Type = inserts[i].ValueType.ToDTO()
151+
mf.Help = &inserts[i].Help
147152

148-
currMetricFamilies[ins.FQName] = mf
153+
currMetricFamilies[inserts[i].FQName] = mf
149154

150155
// Update metric pointer.
151-
hSum := ins.hash()
156+
hSum := inserts[i].hash()
152157
m, ok := c.metrics[hSum]
153158
if !ok {
154-
m = &dto.Metric{Label: make([]*dto.LabelPair, 0, len(ins.LabelNames))}
155-
for i := range ins.LabelNames {
159+
m = &dto.Metric{Label: make([]*dto.LabelPair, 0, len(inserts[i].LabelNames))}
160+
for j := range inserts[i].LabelNames {
156161
m.Label = append(m.Label, &dto.LabelPair{
157-
Name: proto.String(ins.LabelNames[i]),
158-
Value: proto.String(ins.LabelValues[i]),
162+
Name: &inserts[i].LabelNames[j],
163+
Value: &inserts[i].LabelValues[j],
159164
})
160165
}
161-
sort.Sort(labelPairSorter(m.Label))
166+
sort.Sort(internal.LabelPairSorter(m.Label))
162167
}
163168

164-
switch ins.ValueType {
169+
switch inserts[i].ValueType {
165170
case prometheus.CounterValue:
166171
v := m.Counter
167172
if v == nil {
168173
v = &dto.Counter{}
169174
}
170-
v.Value = proto.Float64(ins.Value)
175+
v.Value = &inserts[i].Value
171176
m.Counter = v
172177
m.Gauge = nil
173178
m.Untyped = nil
@@ -176,7 +181,7 @@ func (c *CachedTGatherer) Update(reset bool, inserts []Insert, deletions []Key)
176181
if v == nil {
177182
v = &dto.Gauge{}
178183
}
179-
v.Value = proto.Float64(ins.Value)
184+
v.Value = &inserts[i].Value
180185
m.Counter = nil
181186
m.Gauge = v
182187
m.Untyped = nil
@@ -185,17 +190,17 @@ func (c *CachedTGatherer) Update(reset bool, inserts []Insert, deletions []Key)
185190
if v == nil {
186191
v = &dto.Untyped{}
187192
}
188-
v.Value = proto.Float64(ins.Value)
193+
v.Value = &inserts[i].Value
189194
m.Counter = nil
190195
m.Gauge = nil
191196
m.Untyped = v
192197
default:
193-
return fmt.Errorf("unsupported value type %v", ins.ValueType)
198+
return fmt.Errorf("unsupported value type %v", inserts[i].ValueType)
194199
}
195200

196201
m.TimestampMs = nil
197-
if ins.Timestamp != nil {
198-
m.TimestampMs = proto.Int64(ins.Timestamp.Unix()*1000 + int64(ins.Timestamp.Nanosecond()/1000000))
202+
if inserts[i].Timestamp != nil {
203+
m.TimestampMs = proto.Int64(inserts[i].Timestamp.Unix()*1000 + int64(inserts[i].Timestamp.Nanosecond()/1000000))
199204
}
200205
currMetrics[hSum] = m
201206

@@ -254,19 +259,3 @@ func (c *CachedTGatherer) Update(reset bool, inserts []Insert, deletions []Key)
254259
c.metricFamilyByName = currMetricFamilies
255260
return errs.MaybeUnwrap()
256261
}
257-
258-
// labelPairSorter implements sort.Interface. It is used to sort a slice of
259-
// dto.LabelPair pointers.
260-
type labelPairSorter []*dto.LabelPair
261-
262-
func (s labelPairSorter) Len() int {
263-
return len(s)
264-
}
265-
266-
func (s labelPairSorter) Swap(i, j int) {
267-
s[i], s[j] = s[j], s[i]
268-
}
269-
270-
func (s labelPairSorter) Less(i, j int) bool {
271-
return s[i].GetName() < s[j].GetName()
272-
}

prometheus/desc.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
"strings"
2121

2222
"github.com/cespare/xxhash/v2"
23+
"github.com/prometheus/client_golang/prometheus/internal"
24+
2325
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
2426
"github.com/golang/protobuf/proto"
2527
"github.com/prometheus/common/model"
@@ -154,7 +156,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *
154156
Value: proto.String(v),
155157
})
156158
}
157-
sort.Sort(labelPairSorter(d.constLabelPairs))
159+
sort.Sort(internal.LabelPairSorter(d.constLabelPairs))
158160
return d
159161
}
160162

prometheus/internal/metric.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,22 @@ import (
1919
dto "github.com/prometheus/client_model/go"
2020
)
2121

22+
// LabelPairSorter implements sort.Interface. It is used to sort a slice of
23+
// dto.LabelPair pointers.
24+
type LabelPairSorter []*dto.LabelPair
25+
26+
func (s LabelPairSorter) Len() int {
27+
return len(s)
28+
}
29+
30+
func (s LabelPairSorter) Swap(i, j int) {
31+
s[i], s[j] = s[j], s[i]
32+
}
33+
34+
func (s LabelPairSorter) Less(i, j int) bool {
35+
return s[i].GetName() < s[j].GetName()
36+
}
37+
2238
// metricSorter is a sortable slice of *dto.Metric.
2339
type metricSorter []*dto.Metric
2440

prometheus/metric.go

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -115,22 +115,6 @@ func BuildFQName(namespace, subsystem, name string) string {
115115
return name
116116
}
117117

118-
// labelPairSorter implements sort.Interface. It is used to sort a slice of
119-
// dto.LabelPair pointers.
120-
type labelPairSorter []*dto.LabelPair
121-
122-
func (s labelPairSorter) Len() int {
123-
return len(s)
124-
}
125-
126-
func (s labelPairSorter) Swap(i, j int) {
127-
s[i], s[j] = s[j], s[i]
128-
}
129-
130-
func (s labelPairSorter) Less(i, j int) bool {
131-
return s[i].GetName() < s[j].GetName()
132-
}
133-
134118
type invalidMetric struct {
135119
desc *Desc
136120
err error

prometheus/registry.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -891,11 +891,11 @@ func checkMetricConsistency(
891891
h.Write(separatorByteSlice)
892892
// Make sure label pairs are sorted. We depend on it for the consistency
893893
// check.
894-
if !sort.IsSorted(labelPairSorter(dtoMetric.Label)) {
894+
if !sort.IsSorted(internal.LabelPairSorter(dtoMetric.Label)) {
895895
// We cannot sort dtoMetric.Label in place as it is immutable by contract.
896896
copiedLabels := make([]*dto.LabelPair, len(dtoMetric.Label))
897897
copy(copiedLabels, dtoMetric.Label)
898-
sort.Sort(labelPairSorter(copiedLabels))
898+
sort.Sort(internal.LabelPairSorter(copiedLabels))
899899
dtoMetric.Label = copiedLabels
900900
}
901901
for _, lp := range dtoMetric.Label {
@@ -942,7 +942,7 @@ func checkDescConsistency(
942942
metricFamily.GetName(), dtoMetric, desc,
943943
)
944944
}
945-
sort.Sort(labelPairSorter(lpsFromDesc))
945+
sort.Sort(internal.LabelPairSorter(lpsFromDesc))
946946
for i, lpFromDesc := range lpsFromDesc {
947947
lpFromMetric := dtoMetric.Label[i]
948948
if lpFromDesc.GetName() != lpFromMetric.GetName() ||

prometheus/value.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
2323
"github.com/golang/protobuf/proto"
2424
"github.com/golang/protobuf/ptypes"
25+
"github.com/prometheus/client_golang/prometheus/internal"
2526

2627
dto "github.com/prometheus/client_model/go"
2728
)
@@ -193,7 +194,7 @@ func MakeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair {
193194
})
194195
}
195196
labelPairs = append(labelPairs, desc.constLabelPairs...)
196-
sort.Sort(labelPairSorter(labelPairs))
197+
sort.Sort(internal.LabelPairSorter(labelPairs))
197198
return labelPairs
198199
}
199200

prometheus/wrap.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
2121
"github.com/golang/protobuf/proto"
2222

23+
"github.com/prometheus/client_golang/prometheus/internal"
2324
dto "github.com/prometheus/client_model/go"
2425
)
2526

@@ -182,7 +183,7 @@ func (m *wrappingMetric) Write(out *dto.Metric) error {
182183
Value: proto.String(lv),
183184
})
184185
}
185-
sort.Sort(labelPairSorter(out.Label))
186+
sort.Sort(internal.LabelPairSorter(out.Label))
186187
return nil
187188
}
188189

0 commit comments

Comments
 (0)