Skip to content

Commit e85499c

Browse files
authored
Introduce PromSummary.capacity to improve performance (#57)
* Introduce PromSummary.capacity to improve performance * Add a test for summary with custom capacity * Use Deque instead of Array to store summary values * Revert "Use Deque instead of Array to store summary values" This reverts commit 1dd8c32. * Use CircularBuffer instead of Array to store summary values * Slightly improve wording in comments
1 parent daf102f commit e85499c

File tree

4 files changed

+39
-6
lines changed

4 files changed

+39
-6
lines changed

Sources/Prometheus/MetricTypes/PromMetric.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ public enum PromMetricType: String {
1313
}
1414

1515
public enum Prometheus {
16+
/// Default capacity of Summaries
17+
public static let defaultSummaryCapacity = 500
18+
1619
/// Default quantiles used by Summaries
1720
public static let defaultQuantiles = [0.01, 0.05, 0.5, 0.9, 0.95, 0.99, 0.999]
1821
}

Sources/Prometheus/MetricTypes/Summary.swift

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import NIOConcurrencyHelpers
2+
import NIO
23
import struct CoreMetrics.TimeUnit
34
import Dispatch
45

@@ -43,8 +44,11 @@ public class PromSummary<NumType: DoubleRepresentable, Labels: SummaryLabels>: P
4344
private let count: PromCounter<NumType, EmptyLabels>
4445

4546
/// Values in this Summary
46-
private var values: [NumType] = []
47-
47+
private var values: CircularBuffer<NumType>
48+
49+
/// Number of values to keep for calculating quantiles
50+
internal let capacity: Int
51+
4852
/// Quantiles used by this Summary
4953
internal let quantiles: [Double]
5054

@@ -60,9 +64,10 @@ public class PromSummary<NumType: DoubleRepresentable, Labels: SummaryLabels>: P
6064
/// - name: Name of the Summary
6165
/// - help: Help text of the Summary
6266
/// - labels: Labels for the Summary
67+
/// - capacity: Number of values to keep for calculating quantiles
6368
/// - quantiles: Quantiles to use for the Summary
6469
/// - p: Prometheus instance creating this Summary
65-
internal init(_ name: String, _ help: String? = nil, _ labels: Labels = Labels(), _ quantiles: [Double] = Prometheus.defaultQuantiles, _ p: PrometheusClient) {
70+
internal init(_ name: String, _ help: String? = nil, _ labels: Labels = Labels(), _ capacity: Int = Prometheus.defaultSummaryCapacity, _ quantiles: [Double] = Prometheus.defaultQuantiles, _ p: PrometheusClient) {
6671
self.name = name
6772
self.help = help
6873

@@ -74,6 +79,10 @@ public class PromSummary<NumType: DoubleRepresentable, Labels: SummaryLabels>: P
7479

7580
self.count = .init("\(self.name)_count", nil, 0, p)
7681

82+
self.values = CircularBuffer(initialCapacity: capacity)
83+
84+
self.capacity = capacity
85+
7786
self.quantiles = quantiles
7887

7988
self.labels = labels
@@ -159,6 +168,9 @@ public class PromSummary<NumType: DoubleRepresentable, Labels: SummaryLabels>: P
159168
}
160169
self.count.inc(1)
161170
self.sum.inc(value)
171+
if self.values.count == self.capacity {
172+
_ = self.values.popFirst()
173+
}
162174
self.values.append(value)
163175
}
164176
}
@@ -190,7 +202,7 @@ extension PrometheusClient {
190202
if let summary = summaries.first {
191203
return summary
192204
} else {
193-
let newSummary = PromSummary<T, U>(summary.name, summary.help, labels, summary.quantiles, self)
205+
let newSummary = PromSummary<T, U>(summary.name, summary.help, labels, summary.capacity, summary.quantiles, self)
194206
summary.subSummaries.append(newSummary)
195207
return newSummary
196208
}

Sources/Prometheus/Prometheus.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ public class PrometheusClient {
240240
/// - type: The type the summary will observe
241241
/// - name: Name of the summary
242242
/// - helpText: Help text for the summary. Usually a short description
243+
/// - capacity: Number of observations to keep for calculating quantiles
243244
/// - quantiles: Quantiles to calculate
244245
/// - labels: Labels to give this summary. Can be left out to default to no labels
245246
///
@@ -248,15 +249,15 @@ public class PrometheusClient {
248249
forType type: T.Type,
249250
named name: String,
250251
helpText: String? = nil,
252+
capacity: Int = Prometheus.defaultSummaryCapacity,
251253
quantiles: [Double] = Prometheus.defaultQuantiles,
252254
labels: U.Type) -> PromSummary<T, U>
253255
{
254256
return self.lock.withLock {
255257
if let cachedSummary: PromSummary<T, U> = self._getMetricInstance(with: name, andType: .summary) {
256258
return cachedSummary
257259
}
258-
259-
let summary = PromSummary<T, U>(name, helpText, U(), quantiles, self)
260+
let summary = PromSummary<T, U>(name, helpText, U(), capacity, quantiles, self)
260261
let oldInstrument = self.metrics.updateValue(summary, forKey: name)
261262
precondition(oldInstrument == nil, "Label \(oldInstrument!.name) is already associated with a \(oldInstrument!._type).")
262263
return summary

Tests/SwiftPrometheusTests/SummaryTests.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,21 @@ final class SummaryTests: XCTestCase {
144144
my_summary_sum{myValue=\"labels\"} 123.0
145145
""")
146146
}
147+
148+
func testStandaloneSummaryWithCustomCapacity() {
149+
let capacity = 10
150+
let summary = prom.createSummary(forType: Double.self, named: "my_summary", helpText: "Summary for testing", capacity: capacity, quantiles: [0.5, 0.99], labels: BaseSummaryLabels.self)
151+
152+
for i in 0 ..< capacity { summary.observe(Double(i * 1_000)) }
153+
for i in 0 ..< capacity { summary.observe(Double(i)) }
154+
155+
XCTAssertEqual(summary.collect(), """
156+
# HELP my_summary Summary for testing
157+
# TYPE my_summary summary
158+
my_summary{quantile="0.5", myValue="*"} 4.5
159+
my_summary{quantile="0.99", myValue="*"} 9.0
160+
my_summary_count{myValue="*"} 20.0
161+
my_summary_sum{myValue="*"} 45045.0
162+
""")
163+
}
147164
}

0 commit comments

Comments
 (0)