Skip to content

Commit 1ef6c78

Browse files
committed
Optimise allocs, and simplify a bit.
Add benchmarks from #460
1 parent 03576e6 commit 1ef6c78

File tree

4 files changed

+113
-149
lines changed

4 files changed

+113
-149
lines changed

benchmark/src/main/java/io/prometheus/benchmark/LabelNamesLookupBenchmark.java

Lines changed: 0 additions & 72 deletions
This file was deleted.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package io.prometheus.benchmark;
2+
3+
import io.prometheus.client.Counter;
4+
5+
import org.openjdk.jmh.annotations.*;
6+
import org.openjdk.jmh.runner.Runner;
7+
import org.openjdk.jmh.runner.RunnerException;
8+
import org.openjdk.jmh.runner.options.OptionsBuilder;
9+
10+
import java.util.concurrent.TimeUnit;
11+
12+
@State(Scope.Benchmark)
13+
@OutputTimeUnit(TimeUnit.NANOSECONDS)
14+
@BenchmarkMode(Mode.AverageTime)
15+
public class LabelsToChildLookupBenchmark {
16+
17+
private static final String LABEL1 = "label1", LABEL2 = "label2", LABEL3 = "label3";
18+
private static final String LABEL4 = "label4", LABEL5 = "label5";
19+
20+
private Counter noLabelsCollector, oneLabelCollector, twoLabelsCollector, threeLabelsCollector;
21+
private Counter fourLabelsCollector, fiveLabelsCollector;
22+
23+
@Setup
24+
public void setup() {
25+
Counter.Builder builder = new Counter.Builder().name("testCollector").help("testHelp");
26+
noLabelsCollector = builder.create();
27+
oneLabelCollector = builder.labelNames("name1").create();
28+
twoLabelsCollector = builder.labelNames("name1", "name2").create();
29+
threeLabelsCollector = builder.labelNames("name1", "name2", "name3").create();
30+
fourLabelsCollector = builder.labelNames("name1", "name2", "name3", "name4").create();
31+
fiveLabelsCollector = builder.labelNames("name1", "name2", "name3", "name4", "name5").create();
32+
}
33+
34+
@Benchmark
35+
public void baseline(LabelsToChildLookupBenchmark state) {
36+
noLabelsCollector.inc();
37+
}
38+
39+
@Benchmark
40+
public void oneLabel(LabelsToChildLookupBenchmark state) {
41+
oneLabelCollector.labels(LABEL1).inc();
42+
}
43+
44+
@Benchmark
45+
public void twoLabels(LabelsToChildLookupBenchmark state) {
46+
twoLabelsCollector.labels(LABEL1, LABEL2).inc();
47+
}
48+
49+
@Benchmark
50+
public void threeLabels(LabelsToChildLookupBenchmark state) {
51+
threeLabelsCollector.labels(LABEL1, LABEL2, LABEL3).inc();
52+
}
53+
54+
@Benchmark
55+
public void fourLabels(LabelsToChildLookupBenchmark state) {
56+
fourLabelsCollector.labels(LABEL1, LABEL2, LABEL3, LABEL4).inc();
57+
}
58+
59+
@Benchmark
60+
public void fiveLabels(LabelsToChildLookupBenchmark state) {
61+
fiveLabelsCollector.labels(LABEL1, LABEL2, LABEL3, LABEL4, LABEL5).inc();
62+
}
63+
64+
public static void main(String[] args) throws RunnerException {
65+
new Runner(new OptionsBuilder()
66+
.include(LabelsToChildLookupBenchmark.class.getSimpleName())
67+
.build()).run();
68+
}
69+
}

benchmark/src/main/java/io/prometheus/benchmark/SummaryBenchmark.java

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import org.openjdk.jmh.annotations.Scope;
1111
import org.openjdk.jmh.annotations.Setup;
1212
import org.openjdk.jmh.annotations.State;
13-
import org.openjdk.jmh.profile.GCProfiler;
1413
import org.openjdk.jmh.runner.Runner;
1514
import org.openjdk.jmh.runner.RunnerException;
1615
import org.openjdk.jmh.runner.options.Options;
@@ -30,7 +29,6 @@ public class SummaryBenchmark {
3029
io.prometheus.client.Histogram prometheusSimpleHistogram;
3130
io.prometheus.client.Histogram.Child prometheusSimpleHistogramChild;
3231
io.prometheus.client.Histogram prometheusSimpleHistogramNoLabels;
33-
String[] labelNames;
3432

3533
@Setup
3634
public void setup() {
@@ -44,9 +42,7 @@ public void setup() {
4442
.name("name")
4543
.help("some description..")
4644
.labelNames("some", "group").create();
47-
48-
labelNames = new String[]{"tests", "group"};
49-
prometheusSimpleSummaryChild = prometheusSimpleSummary.labels(labelNames);
45+
prometheusSimpleSummaryChild = prometheusSimpleSummary.labels("test", "group");
5046

5147
prometheusSimpleSummaryNoLabels = io.prometheus.client.Summary.build()
5248
.name("name")
@@ -57,7 +53,7 @@ public void setup() {
5753
.name("name")
5854
.help("some description..")
5955
.labelNames("some", "group").create();
60-
prometheusSimpleHistogramChild = prometheusSimpleHistogram.labels(labelNames);
56+
prometheusSimpleHistogramChild = prometheusSimpleHistogram.labels("test", "group");
6157

6258
prometheusSimpleHistogramNoLabels = io.prometheus.client.Histogram.build()
6359
.name("name")
@@ -89,13 +85,6 @@ public void prometheusSimpleSummaryBenchmark() {
8985
prometheusSimpleSummary.labels("test", "group").observe(1) ;
9086
}
9187

92-
@Benchmark
93-
@BenchmarkMode({Mode.AverageTime})
94-
@OutputTimeUnit(TimeUnit.NANOSECONDS)
95-
public void prometheusSimpleSummaryPooledLabelNamesBenchmark() {
96-
prometheusSimpleSummary.labels(labelNames).observe(1) ;
97-
}
98-
9988
@Benchmark
10089
@BenchmarkMode({Mode.AverageTime})
10190
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@@ -116,26 +105,6 @@ public void prometheusSimpleSummaryNoLabelsBenchmark() {
116105
public void prometheusSimpleHistogramBenchmark() {
117106
prometheusSimpleHistogram.labels("test", "group").observe(1) ;
118107
}
119-
@Benchmark
120-
@BenchmarkMode({Mode.AverageTime})
121-
@OutputTimeUnit(TimeUnit.NANOSECONDS)
122-
public void prometheusSimpleHistogramPooledLabelNamesBenchmark() {
123-
prometheusSimpleHistogram.labels(labelNames).observe(1) ;
124-
}
125-
126-
@Benchmark
127-
@BenchmarkMode({Mode.AverageTime})
128-
@OutputTimeUnit(TimeUnit.NANOSECONDS)
129-
public double prometheusSimpleHistogramTimerBenchmark() {
130-
return prometheusSimpleHistogram.labels("test", "group").startTimer().observeDuration();
131-
}
132-
133-
@Benchmark
134-
@BenchmarkMode({Mode.AverageTime})
135-
@OutputTimeUnit(TimeUnit.NANOSECONDS)
136-
public double prometheusSimpleHistogramTimerPooledLabelNamesBenchmark() {
137-
return prometheusSimpleHistogram.labels(labelNames).startTimer().observeDuration();
138-
}
139108

140109
@Benchmark
141110
@BenchmarkMode({Mode.AverageTime})
@@ -162,8 +131,6 @@ public static void main(String[] args) throws RunnerException {
162131

163132
Options opt = new OptionsBuilder()
164133
.include(SummaryBenchmark.class.getSimpleName())
165-
.jvmArgs("-XX:+UseBiasedLocking", "-XX:BiasedLockingStartupDelay=0")
166-
.addProfiler(GCProfiler.class)
167134
.warmupIterations(5)
168135
.measurementIterations(4)
169136
.threads(4)

simpleclient/src/main/java/io/prometheus/client/SimpleCollector.java

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -123,57 +123,83 @@ public int hashCode() {
123123
* Must be passed the same number of labels are were passed to {@link #labelNames}.
124124
*/
125125
public Child labels(String... labelValues) {
126-
validateLabels(labelValues);
127126
final List<String> labels;
128127
if (labelValues.length > 0) {
129-
labels = pooledLabelNamesOf(labelValues);
128+
labels = getPooledLabels();
129+
for (String label : labelValues) {
130+
labels.add(label);
131+
}
130132
} else {
131133
labels = Collections.emptyList();
132134
}
133135
return getOrCreateChild(labels);
134136
}
135137

136-
private List<String> pooledLabelNamesOf(String... labelValues) {
138+
public Child labels(String l1) {
139+
ArrayList<String> pooledLabels = getPooledLabels();
140+
pooledLabels.add(l1);
141+
return getOrCreateChild(pooledLabels);
142+
}
143+
public Child labels(String l1, String l2) {
144+
ArrayList<String> pooledLabels = getPooledLabels();
145+
pooledLabels.add(l1);
146+
pooledLabels.add(l2);
147+
return getOrCreateChild(pooledLabels);
148+
}
149+
public Child labels(String l1, String l2, String l3) {
150+
ArrayList<String> pooledLabels = getPooledLabels();
151+
pooledLabels.add(l1);
152+
pooledLabels.add(l2);
153+
pooledLabels.add(l3);
154+
return getOrCreateChild(pooledLabels);
155+
}
156+
public Child labels(String l1, String l2, String l3, String l4) {
157+
ArrayList<String> pooledLabels = getPooledLabels();
158+
pooledLabels.add(l1);
159+
pooledLabels.add(l2);
160+
pooledLabels.add(l3);
161+
pooledLabels.add(l4);
162+
return getOrCreateChild(pooledLabels);
163+
}
164+
165+
private ArrayList<String> getPooledLabels() {
137166
final ThreadLocal<ArrayList<String>> labelNamesPool = this.labelNamesPool;
138167
ArrayList<String> pooledLabels = labelNamesPool.get();
139-
final int labelValuesCount = labelValues.length;
140168
if (pooledLabels == null) {
141-
pooledLabels = new LabelNames(labelValuesCount);
169+
pooledLabels = new LabelNames(10);
142170
labelNamesPool.set(pooledLabels);
143-
}
144-
for (String label : labelValues) {
145-
pooledLabels.add(label);
171+
} else {
172+
pooledLabels.clear();
146173
}
147174
return pooledLabels;
148175
}
149176

150177
private Child getOrCreateChild(List<String> labels) {
151178
Child c = children.get(labels);
152179
if (c != null) {
153-
labels.clear();
154180
return c;
155181
}
156182
return tryCreateChild(labels);
157183
}
158184

159185
private Child tryCreateChild(List<String> labels) {
186+
validateLabels(labels);
160187
Child c2 = newChild();
161188
Child tmp = children.putIfAbsent(labels, c2);
162189
if (tmp == null) {
163-
//given that putIfAbsent return null only when a new
164-
//labels has been added, we need to clear up
165-
//the pool to avoid labels to be both in the pool
166-
//and as children key
190+
// given that putIfAbsent return null only when a new
191+
// labels has been added, we need to clear up
192+
// the pool to avoid labels to be both in the pool
193+
// and as children key
167194
labelNamesPool.set(null);
168195
return c2;
169196
} else {
170-
labels.clear();
171197
return tmp;
172198
}
173199
}
174200

175-
private void validateLabels(String... labelValues) {
176-
if (labelValues.length != labelNames.size()) {
201+
private void validateLabels(List<String> labelValues) {
202+
if (labelValues.size() != labelNames.size()) {
177203
throw new IllegalArgumentException("Incorrect number of labels.");
178204
}
179205
for (String label : labelValues) {
@@ -183,32 +209,6 @@ private void validateLabels(String... labelValues) {
183209
}
184210
}
185211

186-
private void validateLabel(String labelValue) {
187-
if (labelNames.size() != 1) {
188-
throw new IllegalArgumentException("Incorrect number of labels.");
189-
}
190-
if (labelValue == null) {
191-
throw new IllegalArgumentException("Label cannot be null.");
192-
}
193-
}
194-
195-
/**
196-
* Return the Child with the given labels, creating it if needed.
197-
* <p>
198-
* Must be passed the same number of labels are were passed to {@link #labelNames}.
199-
*/
200-
public Child labels(String labelValue) {
201-
validateLabel(labelValue);
202-
final ThreadLocal<ArrayList<String>> labelNamesPool = this.labelNamesPool;
203-
ArrayList<String> labels = labelNamesPool.get();
204-
if (labels == null) {
205-
labels = new LabelNames(1);
206-
labelNamesPool.set(labels);
207-
}
208-
labels.add(labelValue);
209-
return getOrCreateChild(labels);
210-
}
211-
212212
/**
213213
* Remove the Child with the given labels.
214214
* <p>

0 commit comments

Comments
 (0)