summaryrefslogtreecommitdiffstats
path: root/src/osd/DynamicPerfStats.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
commit19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch)
tree42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/osd/DynamicPerfStats.h
parentInitial commit. (diff)
downloadceph-upstream/16.2.11+ds.tar.xz
ceph-upstream/16.2.11+ds.zip
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/osd/DynamicPerfStats.h267
1 files changed, 267 insertions, 0 deletions
diff --git a/src/osd/DynamicPerfStats.h b/src/osd/DynamicPerfStats.h
new file mode 100644
index 000000000..1c6c26c71
--- /dev/null
+++ b/src/osd/DynamicPerfStats.h
@@ -0,0 +1,267 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef DYNAMIC_PERF_STATS_H
+#define DYNAMIC_PERF_STATS_H
+
+#include "include/random.h"
+#include "messages/MOSDOp.h"
+#include "mgr/OSDPerfMetricTypes.h"
+#include "osd/OSD.h"
+#include "osd/OpRequest.h"
+
+class DynamicPerfStats {
+public:
+ DynamicPerfStats() {
+ }
+
+ DynamicPerfStats(const std::list<OSDPerfMetricQuery> &queries) {
+ for (auto &query : queries) {
+ data[query];
+ }
+ }
+
+ void merge(const DynamicPerfStats &dps) {
+ for (auto &query_it : dps.data) {
+ auto &query = query_it.first;
+ for (auto &key_it : query_it.second) {
+ auto &key = key_it.first;
+ auto counter_it = key_it.second.begin();
+ auto update_counter_fnc =
+ [&counter_it](const PerformanceCounterDescriptor &d,
+ PerformanceCounter *c) {
+ c->first += counter_it->first;
+ c->second += counter_it->second;
+ counter_it++;
+ };
+
+ ceph_assert(key_it.second.size() >= data[query][key].size());
+ query.update_counters(update_counter_fnc, &data[query][key]);
+ }
+ }
+ }
+
+ void set_queries(const std::list<OSDPerfMetricQuery> &queries) {
+ std::map<OSDPerfMetricQuery,
+ std::map<OSDPerfMetricKey, PerformanceCounters>> new_data;
+ for (auto &query : queries) {
+ std::swap(new_data[query], data[query]);
+ }
+ std::swap(data, new_data);
+ }
+
+ bool is_enabled() {
+ return !data.empty();
+ }
+
+ void add(const OSDService *osd, const pg_info_t &pg_info, const OpRequest& op,
+ uint64_t inb, uint64_t outb, const utime_t &latency) {
+
+ auto update_counter_fnc =
+ [&op, inb, outb, &latency](const PerformanceCounterDescriptor &d,
+ PerformanceCounter *c) {
+ ceph_assert(d.is_supported());
+
+ switch(d.type) {
+ case PerformanceCounterType::OPS:
+ c->first++;
+ return;
+ case PerformanceCounterType::WRITE_OPS:
+ if (op.may_write() || op.may_cache()) {
+ c->first++;
+ }
+ return;
+ case PerformanceCounterType::READ_OPS:
+ if (op.may_read()) {
+ c->first++;
+ }
+ return;
+ case PerformanceCounterType::BYTES:
+ c->first += inb + outb;
+ return;
+ case PerformanceCounterType::WRITE_BYTES:
+ if (op.may_write() || op.may_cache()) {
+ c->first += inb;
+ }
+ return;
+ case PerformanceCounterType::READ_BYTES:
+ if (op.may_read()) {
+ c->first += outb;
+ }
+ return;
+ case PerformanceCounterType::LATENCY:
+ c->first += latency.to_nsec();
+ c->second++;
+ return;
+ case PerformanceCounterType::WRITE_LATENCY:
+ if (op.may_write() || op.may_cache()) {
+ c->first += latency.to_nsec();
+ c->second++;
+ }
+ return;
+ case PerformanceCounterType::READ_LATENCY:
+ if (op.may_read()) {
+ c->first += latency.to_nsec();
+ c->second++;
+ }
+ return;
+ default:
+ ceph_abort_msg("unknown counter type");
+ }
+ };
+
+ auto get_subkey_fnc =
+ [&osd, &pg_info, &op](const OSDPerfMetricSubKeyDescriptor &d,
+ OSDPerfMetricSubKey *sub_key) {
+ ceph_assert(d.is_supported());
+
+ auto m = op.get_req<MOSDOp>();
+ std::string match_string;
+ switch(d.type) {
+ case OSDPerfMetricSubKeyType::CLIENT_ID:
+ match_string = stringify(m->get_reqid().name);
+ break;
+ case OSDPerfMetricSubKeyType::CLIENT_ADDRESS:
+ match_string = stringify(m->get_connection()->get_peer_addr());
+ break;
+ case OSDPerfMetricSubKeyType::POOL_ID:
+ match_string = stringify(m->get_spg().pool());
+ break;
+ case OSDPerfMetricSubKeyType::NAMESPACE:
+ match_string = m->get_hobj().nspace;
+ break;
+ case OSDPerfMetricSubKeyType::OSD_ID:
+ match_string = stringify(osd->get_nodeid());
+ break;
+ case OSDPerfMetricSubKeyType::PG_ID:
+ match_string = stringify(pg_info.pgid);
+ break;
+ case OSDPerfMetricSubKeyType::OBJECT_NAME:
+ match_string = m->get_oid().name;
+ break;
+ case OSDPerfMetricSubKeyType::SNAP_ID:
+ match_string = stringify(m->get_snapid());
+ break;
+ default:
+ ceph_abort_msg("unknown counter type");
+ }
+
+ std::smatch match;
+ if (!std::regex_search(match_string, match, d.regex)) {
+ return false;
+ }
+ if (match.size() <= 1) {
+ return false;
+ }
+ for (size_t i = 1; i < match.size(); i++) {
+ sub_key->push_back(match[i].str());
+ }
+ return true;
+ };
+
+ for (auto &it : data) {
+ auto &query = it.first;
+ OSDPerfMetricKey key;
+ if (query.get_key(get_subkey_fnc, &key)) {
+ query.update_counters(update_counter_fnc, &it.second[key]);
+ }
+ }
+ }
+
+ void add_to_reports(
+ const std::map<OSDPerfMetricQuery, OSDPerfMetricLimits> &limits,
+ std::map<OSDPerfMetricQuery, OSDPerfMetricReport> *reports) {
+ for (auto &it : data) {
+ auto &query = it.first;
+ auto limit_it = limits.find(query);
+ if (limit_it == limits.end()) {
+ continue;
+ }
+ auto &query_limits = limit_it->second;
+ auto &counters = it.second;
+ auto &report = (*reports)[query];
+
+ query.get_performance_counter_descriptors(
+ &report.performance_counter_descriptors);
+
+ auto &descriptors = report.performance_counter_descriptors;
+ ceph_assert(descriptors.size() > 0);
+
+ if (!is_limited(query_limits, counters.size())) {
+ for (auto &it_counters : counters) {
+ auto &bl = report.group_packed_performance_counters[it_counters.first];
+ query.pack_counters(it_counters.second, &bl);
+ }
+ continue;
+ }
+
+ for (auto &limit : query_limits) {
+ size_t index = 0;
+ for (; index < descriptors.size(); index++) {
+ if (descriptors[index] == limit.order_by) {
+ break;
+ }
+ }
+ if (index == descriptors.size()) {
+ // should not happen
+ continue;
+ }
+
+ // Weighted Random Sampling (Algorithm A-Chao):
+ // Select the first [0, max_count) samples, randomly replace
+ // with samples from [max_count, end) using weighted
+ // probability, and return [0, max_count) as the result.
+
+ ceph_assert(limit.max_count < counters.size());
+ typedef std::map<OSDPerfMetricKey, PerformanceCounters>::iterator
+ Iterator;
+ std::vector<Iterator> counter_iterators;
+ counter_iterators.reserve(limit.max_count);
+
+ Iterator it_counters = counters.begin();
+ uint64_t wsum = 0;
+ for (size_t i = 0; i < limit.max_count; i++) {
+ wsum += it_counters->second[index].first;
+ counter_iterators.push_back(it_counters++);
+ }
+ for (; it_counters != counters.end(); it_counters++) {
+ wsum += it_counters->second[index].first;
+ if (ceph::util::generate_random_number(0, wsum) <=
+ it_counters->second[index].first) {
+ auto i = ceph::util::generate_random_number(0, limit.max_count - 1);
+ counter_iterators[i] = it_counters;
+ }
+ }
+
+ for (auto it_counters : counter_iterators) {
+ auto &bl =
+ report.group_packed_performance_counters[it_counters->first];
+ if (bl.length() == 0) {
+ query.pack_counters(it_counters->second, &bl);
+ }
+ }
+ }
+ }
+ }
+
+private:
+ static bool is_limited(const OSDPerfMetricLimits &limits,
+ size_t counters_size) {
+ if (limits.empty()) {
+ return false;
+ }
+
+ for (auto &limit : limits) {
+ if (limit.max_count >= counters_size) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ std::map<OSDPerfMetricQuery,
+ std::map<OSDPerfMetricKey, PerformanceCounters>> data;
+};
+
+#endif // DYNAMIC_PERF_STATS_H