Skip to content

Commit 83bab6f

Browse files
committed
feat: don't create temporary objects for serialization
Fix: #646
1 parent dfbf0fa commit 83bab6f

27 files changed

+551
-255
lines changed

core/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ add_library(core
1010
src/gauge.cc
1111
src/histogram.cc
1212
src/info.cc
13+
src/iovector.cc
1314
src/registry.cc
14-
src/serializer.cc
1515
src/summary.cc
1616
src/text_serializer.cc
1717
)

core/include/prometheus/collectable.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
#pragma once
22

3-
#include <vector>
4-
53
#include "prometheus/detail/core_export.h"
6-
7-
namespace prometheus {
8-
struct MetricFamily;
9-
}
4+
#include "prometheus/serializer.h"
105

116
namespace prometheus {
127

@@ -19,7 +14,7 @@ class PROMETHEUS_CPP_CORE_EXPORT Collectable {
1914
virtual ~Collectable() = default;
2015

2116
/// \brief Returns a list of metrics and their samples.
22-
virtual std::vector<MetricFamily> Collect() const = 0;
17+
virtual void Collect(const Serializer& out) const = 0;
2318
};
2419

2520
} // namespace prometheus

core/include/prometheus/family.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44
#include <mutex>
55
#include <string>
66
#include <unordered_map>
7-
#include <vector>
87

98
#include "prometheus/client_metric.h"
109
#include "prometheus/collectable.h"
1110
#include "prometheus/detail/core_export.h"
1211
#include "prometheus/detail/future_std.h"
1312
#include "prometheus/detail/utils.h"
1413
#include "prometheus/labels.h"
15-
#include "prometheus/metric_family.h"
14+
#include "prometheus/serializer.h"
1615

1716
// IWYU pragma: no_include "prometheus/counter.h"
1817
// IWYU pragma: no_include "prometheus/gauge.h"
@@ -140,7 +139,7 @@ class PROMETHEUS_CPP_CORE_EXPORT Family : public Collectable {
140139
/// Collect is called by the Registry when collecting metrics.
141140
///
142141
/// \return Zero or more samples for each dimensional data.
143-
std::vector<MetricFamily> Collect() const override;
142+
void Collect(const Serializer& out) const override;
144143

145144
private:
146145
std::unordered_map<Labels, std::unique_ptr<T>, detail::LabelHasher> metrics_;

core/include/prometheus/iovector.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#pragma once
2+
3+
#include <cstddef>
4+
#include <cstdint>
5+
#include <string>
6+
#include <vector>
7+
8+
#include "prometheus/detail/core_export.h"
9+
10+
namespace prometheus {
11+
12+
struct PROMETHEUS_CPP_CORE_EXPORT IOVector {
13+
using ByteVector = std::vector<std::uint8_t>;
14+
15+
bool empty() const;
16+
17+
std::size_t size() const;
18+
19+
std::size_t copy(std::size_t offset, void* buffer,
20+
std::size_t bufferSize) const;
21+
22+
void add(const std::string& str, std::size_t chunkSize);
23+
24+
std::vector<ByteVector> data;
25+
};
26+
27+
} // namespace prometheus

core/include/prometheus/metric_family.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,5 @@ struct PROMETHEUS_CPP_CORE_EXPORT MetricFamily {
1313
std::string name;
1414
std::string help;
1515
MetricType type = MetricType::Untyped;
16-
std::vector<ClientMetric> metric;
1716
};
1817
} // namespace prometheus

core/include/prometheus/registry.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include "prometheus/detail/core_export.h"
1010
#include "prometheus/family.h"
1111
#include "prometheus/labels.h"
12-
#include "prometheus/metric_family.h"
12+
#include "prometheus/serializer.h"
1313

1414
namespace prometheus {
1515

@@ -79,7 +79,7 @@ class PROMETHEUS_CPP_CORE_EXPORT Registry : public Collectable {
7979
/// function.
8080
///
8181
/// \return Zero or more metrics and their samples.
82-
std::vector<MetricFamily> Collect() const override;
82+
void Collect(const Serializer& out) const override;
8383

8484
/// \brief Removes a metrics family from the registry.
8585
///

core/include/prometheus/serializer.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
#pragma once
22

3-
#include <iosfwd>
4-
#include <string>
5-
#include <vector>
6-
3+
#include "prometheus/client_metric.h"
74
#include "prometheus/detail/core_export.h"
85
#include "prometheus/metric_family.h"
96

@@ -12,9 +9,10 @@ namespace prometheus {
129
class PROMETHEUS_CPP_CORE_EXPORT Serializer {
1310
public:
1411
virtual ~Serializer() = default;
15-
virtual std::string Serialize(const std::vector<MetricFamily>&) const;
16-
virtual void Serialize(std::ostream& out,
17-
const std::vector<MetricFamily>& metrics) const = 0;
12+
13+
virtual void SerializeHelp(const MetricFamily& family) const = 0;
14+
virtual void SerializeMetrics(const MetricFamily& family,
15+
const ClientMetric& metric) const = 0;
1816
};
1917

2018
} // namespace prometheus
Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
11
#pragma once
22

3+
#include <cstddef>
34
#include <iosfwd>
4-
#include <vector>
55

6+
#include "prometheus/client_metric.h"
67
#include "prometheus/detail/core_export.h"
8+
#include "prometheus/iovector.h"
79
#include "prometheus/metric_family.h"
810
#include "prometheus/serializer.h"
911

1012
namespace prometheus {
1113

1214
class PROMETHEUS_CPP_CORE_EXPORT TextSerializer : public Serializer {
1315
public:
14-
using Serializer::Serialize;
15-
void Serialize(std::ostream& out,
16-
const std::vector<MetricFamily>& metrics) const override;
16+
TextSerializer(IOVector& ioVector);
17+
18+
void SerializeHelp(const MetricFamily& family) const override;
19+
void SerializeMetrics(const MetricFamily& family,
20+
const ClientMetric& metric) const override;
21+
22+
private:
23+
void Add(const std::ostringstream& stream) const;
24+
25+
IOVector& ioVector_;
26+
static constexpr std::size_t chunkSize_ = 1 * 1024 * 1024;
1727
};
1828

1929
} // namespace prometheus

core/src/family.cc

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "prometheus/gauge.h"
1212
#include "prometheus/histogram.h"
1313
#include "prometheus/info.h"
14+
#include "prometheus/metric_family.h"
1415
#include "prometheus/summary.h"
1516

1617
namespace prometheus {
@@ -86,22 +87,24 @@ const Labels& Family<T>::GetConstantLabels() const {
8687
}
8788

8889
template <typename T>
89-
std::vector<MetricFamily> Family<T>::Collect() const {
90+
void Family<T>::Collect(const Serializer& out) const {
9091
std::lock_guard<std::mutex> lock{mutex_};
9192

9293
if (metrics_.empty()) {
93-
return {};
94+
return;
9495
}
9596

9697
auto family = MetricFamily{};
9798
family.name = name_;
9899
family.help = help_;
99100
family.type = T::metric_type;
100-
family.metric.reserve(metrics_.size());
101+
102+
out.SerializeHelp(family);
103+
101104
for (const auto& m : metrics_) {
102-
family.metric.push_back(std::move(CollectMetric(m.first, m.second.get())));
105+
auto&& metric = CollectMetric(m.first, m.second.get());
106+
out.SerializeMetrics(family, metric);
103107
}
104-
return {family};
105108
}
106109

107110
template <typename T>

core/src/iovector.cc

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#include "prometheus/iovector.h"
2+
3+
#include <algorithm>
4+
#include <iterator>
5+
#include <memory>
6+
#include <numeric>
7+
8+
namespace prometheus {
9+
10+
bool IOVector::empty() const { return data.empty() || !size(); }
11+
12+
std::size_t IOVector::size() const {
13+
return std::accumulate(begin(data), end(data), std::size_t{0},
14+
[](std::size_t size, const ByteVector& chunk) {
15+
return size + chunk.size();
16+
});
17+
}
18+
19+
std::size_t IOVector::copy(std::size_t offset, void* buffer,
20+
std::size_t bufferSize) const {
21+
std::size_t copied = 0;
22+
for (const auto& chunk : data) {
23+
if (offset >= chunk.size()) {
24+
offset -= chunk.size();
25+
continue;
26+
}
27+
28+
auto chunkSize = std::min(chunk.size() - offset, bufferSize - copied);
29+
std::copy_n(chunk.data() + offset, chunkSize,
30+
reinterpret_cast<std::uint8_t*>(buffer) + copied);
31+
copied += chunkSize;
32+
offset = 0;
33+
34+
if (copied == bufferSize) {
35+
break;
36+
}
37+
}
38+
return copied;
39+
}
40+
41+
void IOVector::add(const std::string& str, std::size_t chunkSize) {
42+
std::size_t size = str.size();
43+
std::size_t offset = 0;
44+
45+
while (size > 0U) {
46+
if (data.empty() || data.back().size() >= chunkSize) {
47+
data.emplace_back();
48+
data.back().reserve(chunkSize);
49+
}
50+
auto&& chunk = data.back();
51+
const auto toAdd = std::min(size, chunkSize - chunk.size());
52+
chunk.insert(chunk.end(), str.data() + offset, str.data() + offset + toAdd);
53+
54+
size -= toAdd;
55+
offset += toAdd;
56+
}
57+
}
58+
} // namespace prometheus

0 commit comments

Comments
 (0)