Skip to content

Commit

Permalink
[metric] improve json serialize performance
Browse files Browse the repository at this point in the history
  • Loading branch information
poor-circle committed Sep 26, 2024
1 parent a52ac91 commit 79085b2
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 62 deletions.
45 changes: 30 additions & 15 deletions include/ylt/metric/counter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <algorithm>
#include <array>
#include <atomic>
#include <memory>
#include <thread>
#include <variant>
Expand All @@ -14,17 +15,18 @@ enum class op_type_t { INC, DEC, SET };

#ifdef CINATRA_ENABLE_METRIC_JSON
struct json_counter_metric_t {
std::map<std::string, std::string> labels;
std::vector<std::string_view> labels;
std::variant<int64_t, double> value;
};
YLT_REFL(json_counter_metric_t, labels, value);
struct json_counter_t {
std::string name;
std::string help;
std::string type;
std::string_view name;
std::string_view help;
std::string_view type;
std::vector<std::string_view> labels_name;
std::vector<json_counter_metric_t> metrics;
};
YLT_REFL(json_counter_t, name, help, type, metrics);
YLT_REFL(json_counter_t, name, help, type, labels_name, metrics);
#endif

template <typename value_type>
Expand Down Expand Up @@ -78,13 +80,23 @@ class basic_static_counter : public static_metric {

#ifdef CINATRA_ENABLE_METRIC_JSON
void serialize_to_json(std::string &str) override {
if (default_label_value_.value() == 0) {
auto value = default_label_value_.value();
if (value == 0 && !has_change_) {
return;
}

json_counter_t counter{name_, help_, std::string(metric_name())};
auto value = default_label_value_.value();
counter.metrics.push_back({static_labels_, value});
json_counter_t counter{name_, help_, metric_name()};

counter.labels_name.reserve(static_labels_.size());
for (auto &[k, _] : static_labels_) {
counter.labels_name.emplace_back(k);
}
counter.metrics.resize(1);
counter.metrics[0].labels.reserve(static_labels_.size());
for (auto &[k, _] : static_labels_) {
counter.metrics[0].labels.emplace_back(k);
}
counter.metrics[0].value = value;
iguana::to_json(counter, str);
}
#endif
Expand Down Expand Up @@ -248,10 +260,12 @@ class basic_dynamic_counter

#ifdef CINATRA_ENABLE_METRIC_JSON
void serialize_to_json(std::string &str) override {
std::string s;
auto map = Base::copy();
json_counter_t counter{Base::name_, Base::help_,
std::string(Base::metric_name())};
json_counter_t counter{Base::name_, Base::help_, Base::metric_name()};
counter.labels_name.reserve(Base::labels_name().size());
for (auto &e : Base::labels_name()) {
counter.labels_name.emplace_back(e);
}
to_json(counter, map, str);
}

Expand All @@ -262,10 +276,11 @@ class basic_dynamic_counter
auto &val = e->value;
json_counter_metric_t metric;
size_t index = 0;
metric.labels.reserve(k.size());
for (auto &label_value : k) {
metric.labels.emplace(Base::labels_name_[index++], label_value);
metric.labels.emplace_back(label_value);
}
metric.value = (int64_t)val;
metric.value = val.load(std::memory_order::relaxed);
counter.metrics.push_back(std::move(metric));
}
if (!counter.metrics.empty()) {
Expand All @@ -279,7 +294,7 @@ class basic_dynamic_counter
void serialize_map(T &value_map, std::string &str) {
for (auto &e : value_map) {
auto &labels_value = e->label;
auto &val = e->value;
auto val = e->value.load(std::memory_order::relaxed);
str.append(Base::name_);
if (Base::labels_name_.empty()) {
str.append(" ");
Expand Down
74 changes: 34 additions & 40 deletions include/ylt/metric/summary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,21 @@
namespace ylt::metric {
#ifdef CINATRA_ENABLE_METRIC_JSON
struct json_summary_metric_t {
std::map<std::string, std::string> labels;
std::map<double, double> quantiles;
int64_t count;
std::vector<std::string_view> labels;
std::vector<float> quantiles_value;
uint64_t count;
double sum;
};
YLT_REFL(json_summary_metric_t, labels, quantiles, count, sum);
YLT_REFL(json_summary_metric_t, labels, quantiles_value, count, sum);
struct json_summary_t {
std::string name;
std::string help;
std::string type;
std::string_view name;
std::string_view help;
std::string_view type;
const std::vector<std::string>& labels_name;
const std::vector<double>& quantiles_key;
std::vector<json_summary_metric_t> metrics;
};
YLT_REFL(json_summary_t, name, help, type, metrics);
YLT_REFL(json_summary_t, name, help, type, labels_name, quantiles_key, metrics);
#endif

class summary_t : public static_metric {
Expand Down Expand Up @@ -114,29 +116,17 @@ class summary_t : public static_metric {
return;
}

double sum = 0;
uint64_t count = 0;
auto rates = get_rates(sum, count);
if (count == 0) {
return;
}

json_summary_t summary{name_, help_, std::string(metric_name())};

json_summary_t summary{name_, help_, metric_name(), labels_name(),
quantiles_};
json_summary_metric_t metric;

for (size_t i = 0; i < quantiles_.size(); i++) {
for (size_t i = 0; i < labels_name_.size(); i++) {
metric.labels[labels_name_[i]] = labels_value_[i];
}
metric.quantiles.emplace(quantiles_[i], rates[i]);
metric.quantiles_value = get_rates(metric.sum, metric.count);
if (metric.count == 0) {
return;
}

metric.sum = sum;
metric.count = count;

metric.labels.reserve(labels_value_.size());
for (auto& e : labels_value_) metric.labels.emplace_back(e);
summary.metrics.push_back(std::move(metric));

iguana::to_json(summary, str);
}
#endif
Expand Down Expand Up @@ -228,26 +218,30 @@ class basic_dynamic_summary

#ifdef CINATRA_ENABLE_METRIC_JSON
virtual void serialize_to_json(std::string& str) override {
json_summary_t summary{Base::name_, Base::help_,
std::string(Base::metric_name())};
auto map = Base::copy();
for (auto& e : map) {
auto& labels_value = e->label;
auto& summary_value = e->value;
json_summary_metric_t metric;
if (map.empty()) {
return;
}
json_summary_t summary{Base::name_, Base::help_, Base::metric_name(),
Base::labels_name(), quantiles_};
summary.metrics.reserve(map.size());
for (size_t i = 0; i < map.size(); ++i) {
auto& labels_value = map[i]->label;
auto& summary_value = map[i]->value;
double sum = 0;
uint64_t count = 0;
auto rates = summary_value.stat(sum, count);
if (count == 0)
continue;
summary.metrics.emplace_back();
json_summary_metric_t& metric = summary.metrics.back();
metric.count = count;
metric.sum = sum;
for (size_t i = 0; i < quantiles_.size(); i++) {
for (size_t i = 0; i < labels_value.size(); i++) {
metric.labels[Base::labels_name_[i]] = labels_value[i];
}
metric.quantiles.emplace(quantiles_[i], rates[i]);
}
summary.metrics.push_back(std::move(metric));
metric.quantiles_value = std::move(rates);
metric.labels.reserve(labels_value.size());
for (auto& e : labels_value) metric.labels.emplace_back(e);
}
auto i3 = std::chrono::steady_clock::now();
iguana::to_json(summary, str);
}
#endif
Expand Down
2 changes: 2 additions & 0 deletions src/metric/tests/parallel_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
#include "ylt/metric.hpp"

TEST_CASE("test high parallel perform test") {
#ifndef _MSC_VER
bench_static_summary_mixed(std::thread::hardware_concurrency() * 4, 3s);
bench_dynamic_summary_mixed(std::thread::hardware_concurrency() * 4, 2s);
bench_static_counter_mixed(std::thread::hardware_concurrency() * 4, 2s);
bench_static_counter_mixed(std::thread::hardware_concurrency() * 4, 2s);
#endif
}
20 changes: 13 additions & 7 deletions src/metric/tests/test_metric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,8 @@ TEST_CASE("test gauge") {
std::string str_json;
g.serialize_to_json(str_json);
std::cout << str_json << "\n";
CHECK(str_json.find("\"code\":\"200\"") != std::string::npos);
std::cout << str_json.size() << std::endl;
CHECK(str_json.size() == 185);
#endif

std::string str;
Expand Down Expand Up @@ -702,7 +703,8 @@ TEST_CASE("test summary") {
std::string str_json;
summary.serialize_to_json(str_json);
std::cout << str_json << "\n";
CHECK(str_json.find("\"0.9\":") != std::string::npos);
std::cout << str_json.size() << std::endl;
CHECK(str_json.size() == 195);
#endif
}

Expand Down Expand Up @@ -731,7 +733,8 @@ TEST_CASE("test summary with INF") {
std::string str_json;
summary.serialize_to_json(str_json);
std::cout << str_json << "\n";
CHECK(str_json.find("\"0.9\":") != std::string::npos);
std::cout << str_json.size() << std::endl;
CHECK(str_json.size() == 238);
#endif
}

Expand Down Expand Up @@ -760,7 +763,8 @@ TEST_CASE("test summary with NAN") {
std::string str_json;
summary.serialize_to_json(str_json);
std::cout << str_json << "\n";
CHECK(str_json.find("\"0.9\":") != std::string::npos);
std::cout << str_json.size() << std::endl;
CHECK(str_json.size() == 238);
#endif
}

Expand Down Expand Up @@ -793,7 +797,8 @@ TEST_CASE("test summary with illegal quantities") {
std::string str_json;
summary.serialize_to_json(str_json);
std::cout << str_json << "\n";
CHECK(str_json.find("\"0.9\":") != std::string::npos);
std::cout << str_json.size() << std::endl;
CHECK(str_json.size() == 233);
#endif
}

Expand All @@ -811,7 +816,7 @@ TEST_CASE("test summary with many quantities") {
}
std::string str;
summary.serialize(str);
std::cout << str;
// std::cout << str;
double sum;
uint64_t cnt;
auto result = summary.get_rates(sum, cnt);
Expand All @@ -828,7 +833,8 @@ TEST_CASE("test summary with many quantities") {
std::string str_json;
summary.serialize_to_json(str_json);
std::cout << str_json << "\n";
CHECK(str_json.find("\"0.9\":") != std::string::npos);
std::cout << str_json.size() << std::endl;
CHECK(str_json.size() == 8868);
#endif
}

Expand Down

0 comments on commit 79085b2

Please sign in to comment.