summaryrefslogtreecommitdiffstats
path: root/src/test
diff options
context:
space:
mode:
authorAli Maredia <amaredia@redhat.com>2022-07-19 23:39:02 +0200
committerAli Maredia <amaredia@redhat.com>2023-02-23 18:05:36 +0100
commit56e2a1006f975829c0f00db31c745f32da24676b (patch)
tree8198d3223ed815fabd76f708d5ed64bb29c13a6b /src/test
parentcommon: add abstraction for label-aware perf counter keys (diff)
downloadceph-56e2a1006f975829c0f00db31c745f32da24676b.tar.xz
ceph-56e2a1006f975829c0f00db31c745f32da24676b.zip
common: Add labeled perf counters
Add the ability to dump labeled perf counters for a daemon. Labeled perf counters are stored in a CephContext's PerfCountersCollection. Labeled and unlabeled perf counters are dumped to the admin socket via `counters dump` command. The schema for labeled and unlabeled perf counters are dumped to the admin socket via `counters schema` command. This commit includes docs and additional unit tests Signed-off-by: Ali Maredia <amaredia@redhat.com>
Diffstat (limited to 'src/test')
-rw-r--r--src/test/fio/fio_ceph_messenger.cc2
-rw-r--r--src/test/fio/fio_ceph_objectstore.cc2
-rw-r--r--src/test/perf_counters.cc368
3 files changed, 370 insertions, 2 deletions
diff --git a/src/test/fio/fio_ceph_messenger.cc b/src/test/fio/fio_ceph_messenger.cc
index 8c962af5df7..2e18c7c6330 100644
--- a/src/test/fio/fio_ceph_messenger.cc
+++ b/src/test/fio/fio_ceph_messenger.cc
@@ -132,7 +132,7 @@ static void put_ceph_context(void)
Formatter* f;
f = Formatter::create("json-pretty");
- g_ceph_context->get_perfcounters_collection()->dump_formatted(f, false);
+ g_ceph_context->get_perfcounters_collection()->dump_formatted(f, false, false);
ostr << ">>>>>>>>>>>>> PERFCOUNTERS BEGIN <<<<<<<<<<<<" << std::endl;
f->flush(ostr);
ostr << ">>>>>>>>>>>>> PERFCOUNTERS END <<<<<<<<<<<<" << std::endl;
diff --git a/src/test/fio/fio_ceph_objectstore.cc b/src/test/fio/fio_ceph_objectstore.cc
index fe9c793ab12..ade043f0cd1 100644
--- a/src/test/fio/fio_ceph_objectstore.cc
+++ b/src/test/fio/fio_ceph_objectstore.cc
@@ -338,7 +338,7 @@ struct Engine {
Formatter* f = Formatter::create(
"json-pretty", "json-pretty", "json-pretty");
f->open_object_section("perf_output");
- cct->get_perfcounters_collection()->dump_formatted(f, false);
+ cct->get_perfcounters_collection()->dump_formatted(f, false, false);
if (g_conf()->rocksdb_perf) {
f->open_object_section("rocksdb_perf");
os->get_db_statistics(f);
diff --git a/src/test/perf_counters.cc b/src/test/perf_counters.cc
index a4dfe48d1e7..31b10fff167 100644
--- a/src/test/perf_counters.cc
+++ b/src/test/perf_counters.cc
@@ -16,6 +16,7 @@
// now, this include has to come before the others.
+#include "common/perf_counters_key.h"
#include "common/perf_counters_collection.h"
#include "common/admin_socket_client.h"
#include "common/ceph_context.h"
@@ -182,6 +183,7 @@ TEST(PerfCounters, MultiplePerfCounters) {
"{\"avgcount\":0,\"sum\":0.000000000,\"avgtime\":0.000000000}},\"test_perfcounter_2\":{\"foo\":0,\"bar\":0.000000000}}"), msg);
coll->remove(fake_pf2);
+ delete fake_pf2;
ASSERT_EQ("", client.do_request("{ \"prefix\": \"perf dump\", \"format\": \"json\" }", &msg));
ASSERT_EQ(sd("{\"test_perfcounter_1\":{\"element1\":13,\"element2\":0.000000000,"
"\"element3\":{\"avgcount\":0,\"sum\":0.000000000,\"avgtime\":0.000000000}}}"), msg);
@@ -255,3 +257,369 @@ TEST(PerfCounters, read_avg) {
t2.join();
t1.join();
}
+
+static PerfCounters* setup_test_perfcounter4(std::string name, CephContext *cct)
+{
+ PerfCountersBuilder bld(cct, name,
+ TEST_PERFCOUNTERS2_ELEMENT_FIRST, TEST_PERFCOUNTERS2_ELEMENT_LAST);
+ bld.add_u64(TEST_PERFCOUNTERS2_ELEMENT_FOO, "foo");
+ bld.add_time(TEST_PERFCOUNTERS2_ELEMENT_BAR, "bar");
+
+ PerfCounters* counters = bld.create_perf_counters();
+ cct->get_perfcounters_collection()->add(counters);
+ return counters;
+}
+
+TEST(PerfCounters, TestLabeledCountersOnly) {
+ constexpr std::string_view empty_dump_format_raw = R"({}
+)";
+ std::string counter_key1 = ceph::perf_counters::key_create("name1", {{"label1", "val1"}});
+ std::string counter_key2 = ceph::perf_counters::key_create("name2", {{"label2", "val2"}});
+
+ PerfCounters* counters1 = setup_test_perfcounter4(counter_key1, g_ceph_context);
+ PerfCounters* counters2 = setup_test_perfcounter4(counter_key2, g_ceph_context);
+
+ counters1->inc(TEST_PERFCOUNTERS2_ELEMENT_FOO, 3);
+ counters1->dec(TEST_PERFCOUNTERS2_ELEMENT_FOO, 1);
+ counters2->set(TEST_PERFCOUNTERS2_ELEMENT_FOO, 4);
+
+ AdminSocketClient client(get_rand_socket_path());
+ std::string message;
+ ASSERT_EQ("", client.do_request(R"({ "prefix": "counter dump", "format": "raw" })", &message));
+ ASSERT_EQ(R"({
+ "name1": {
+ "labels": {
+ "label1": "val1"
+ },
+ "counters": {
+ "foo": 2,
+ "bar": 0.000000000
+ }
+ },
+ "name2": {
+ "labels": {
+ "label2": "val2"
+ },
+ "counters": {
+ "foo": 4,
+ "bar": 0.000000000
+ }
+ }
+}
+)", message);
+
+ // make sure labeled counters are not in normal perf dump
+ ASSERT_EQ("", client.do_request(R"({ "prefix": "perf dump", "format": "raw" })", &message));
+ ASSERT_EQ(empty_dump_format_raw, message);
+
+ ASSERT_EQ("", client.do_request(R"({ "prefix": "counter schema", "format": "raw" })", &message));
+ ASSERT_EQ(R"({
+ "name1": {
+ "labels": {
+ "label1": "val1"
+ },
+ "counters": {
+ "foo": {
+ "type": 2,
+ "metric_type": "gauge",
+ "value_type": "integer",
+ "description": "",
+ "nick": "",
+ "priority": 0,
+ "units": "none"
+ },
+ "bar": {
+ "type": 1,
+ "metric_type": "gauge",
+ "value_type": "real",
+ "description": "",
+ "nick": "",
+ "priority": 0,
+ "units": "none"
+ }
+ }
+ },
+ "name2": {
+ "labels": {
+ "label2": "val2"
+ },
+ "counters": {
+ "foo": {
+ "type": 2,
+ "metric_type": "gauge",
+ "value_type": "integer",
+ "description": "",
+ "nick": "",
+ "priority": 0,
+ "units": "none"
+ },
+ "bar": {
+ "type": 1,
+ "metric_type": "gauge",
+ "value_type": "real",
+ "description": "",
+ "nick": "",
+ "priority": 0,
+ "units": "none"
+ }
+ }
+ }
+}
+)", message);
+
+ // make sure labeled counters are not in normal perf schema
+ ASSERT_EQ("", client.do_request(R"({ "prefix": "perf schema", "format": "raw" })", &message));
+ ASSERT_EQ(empty_dump_format_raw, message);
+
+ g_ceph_context->get_perfcounters_collection()->clear();
+}
+
+TEST(PerfCounters, TestLabelStrings) {
+ AdminSocketClient client(get_rand_socket_path());
+ std::string message;
+
+ // test empty val in a label pair will get the label pair added but empty key will not
+ std::string counter_key1 = ceph::perf_counters::key_create("good_ctrs", {{"label3", "val4"}, {"label1", ""}});
+ PerfCounters* counters1 = setup_test_perfcounter4(counter_key1, g_ceph_context);
+
+ std::string counter_key2 = ceph::perf_counters::key_create("bad_ctrs", {{"", "val4"}, {"label1", "val1"}});
+ PerfCounters* counters2 = setup_test_perfcounter4(counter_key2, g_ceph_context);
+
+ counters1->set(TEST_PERFCOUNTERS2_ELEMENT_FOO, 2);
+ counters2->set(TEST_PERFCOUNTERS2_ELEMENT_FOO, 4);
+
+ // test empty keys in each of the label pairs will get only the labels section added
+ std::string counter_key3 = ceph::perf_counters::key_create("bad_ctrs2", {{"", "val2"}, {"", "val33"}});
+ PerfCounters* counters3 = setup_test_perfcounter4(counter_key3, g_ceph_context);
+ counters3->set(TEST_PERFCOUNTERS2_ELEMENT_FOO, 6);
+
+ // a key with a somehow odd number of entries after the the key name will omit final unfinished label pair
+ std::string counter_key4 = "too_many_delimiters";
+ counter_key4 += '\0';
+ counter_key4 += "label1";
+ counter_key4 += '\0';
+ counter_key4 += "val1";
+ counter_key4 += '\0';
+ counter_key4 += "label2";
+ counter_key4 += '\0';
+ PerfCounters* counters4 = setup_test_perfcounter4(counter_key4, g_ceph_context);
+ counters4->set(TEST_PERFCOUNTERS2_ELEMENT_FOO, 8);
+
+ // test unlabeled perf counters are in the counter dump with labels and counters sections
+ std::string counter_key5 = "only_key";
+ PerfCounters* no_label_counters = setup_test_perfcounter4(counter_key5, g_ceph_context);
+ no_label_counters->set(TEST_PERFCOUNTERS2_ELEMENT_FOO, 4);
+
+ ASSERT_EQ("", client.do_request(R"({ "prefix": "counter dump", "format": "raw" })", &message));
+ ASSERT_EQ(R"({
+ "bad_ctrs": {
+ "labels": {
+ "label1": "val1"
+ },
+ "counters": {
+ "foo": 4,
+ "bar": 0.000000000
+ }
+ },
+ "bad_ctrs2": {
+ "labels": {},
+ "counters": {
+ "foo": 6,
+ "bar": 0.000000000
+ }
+ },
+ "good_ctrs": {
+ "labels": {
+ "label1": "",
+ "label3": "val4"
+ },
+ "counters": {
+ "foo": 2,
+ "bar": 0.000000000
+ }
+ },
+ "only_key": {
+ "labels": {},
+ "counters": {
+ "foo": 4,
+ "bar": 0.000000000
+ }
+ },
+ "too_many_delimiters": {
+ "labels": {
+ "label1": "val1"
+ },
+ "counters": {
+ "foo": 8,
+ "bar": 0.000000000
+ }
+ }
+}
+)", message);
+
+ // test unlabeled perf counters are in the schema dump with labels and counters sections
+ ASSERT_EQ("", client.do_request(R"({ "prefix": "counter schema", "format": "raw" })", &message));
+ ASSERT_EQ(R"({
+ "bad_ctrs": {
+ "labels": {
+ "label1": "val1"
+ },
+ "counters": {
+ "foo": {
+ "type": 2,
+ "metric_type": "gauge",
+ "value_type": "integer",
+ "description": "",
+ "nick": "",
+ "priority": 0,
+ "units": "none"
+ },
+ "bar": {
+ "type": 1,
+ "metric_type": "gauge",
+ "value_type": "real",
+ "description": "",
+ "nick": "",
+ "priority": 0,
+ "units": "none"
+ }
+ }
+ },
+ "bad_ctrs2": {
+ "labels": {},
+ "counters": {
+ "foo": {
+ "type": 2,
+ "metric_type": "gauge",
+ "value_type": "integer",
+ "description": "",
+ "nick": "",
+ "priority": 0,
+ "units": "none"
+ },
+ "bar": {
+ "type": 1,
+ "metric_type": "gauge",
+ "value_type": "real",
+ "description": "",
+ "nick": "",
+ "priority": 0,
+ "units": "none"
+ }
+ }
+ },
+ "good_ctrs": {
+ "labels": {
+ "label1": "",
+ "label3": "val4"
+ },
+ "counters": {
+ "foo": {
+ "type": 2,
+ "metric_type": "gauge",
+ "value_type": "integer",
+ "description": "",
+ "nick": "",
+ "priority": 0,
+ "units": "none"
+ },
+ "bar": {
+ "type": 1,
+ "metric_type": "gauge",
+ "value_type": "real",
+ "description": "",
+ "nick": "",
+ "priority": 0,
+ "units": "none"
+ }
+ }
+ },
+ "only_key": {
+ "labels": {},
+ "counters": {
+ "foo": {
+ "type": 2,
+ "metric_type": "gauge",
+ "value_type": "integer",
+ "description": "",
+ "nick": "",
+ "priority": 0,
+ "units": "none"
+ },
+ "bar": {
+ "type": 1,
+ "metric_type": "gauge",
+ "value_type": "real",
+ "description": "",
+ "nick": "",
+ "priority": 0,
+ "units": "none"
+ }
+ }
+ },
+ "too_many_delimiters": {
+ "labels": {
+ "label1": "val1"
+ },
+ "counters": {
+ "foo": {
+ "type": 2,
+ "metric_type": "gauge",
+ "value_type": "integer",
+ "description": "",
+ "nick": "",
+ "priority": 0,
+ "units": "none"
+ },
+ "bar": {
+ "type": 1,
+ "metric_type": "gauge",
+ "value_type": "real",
+ "description": "",
+ "nick": "",
+ "priority": 0,
+ "units": "none"
+ }
+ }
+ }
+}
+)", message);
+
+ // test unlabeled perf counters are in the perf dump without the labels and counters section
+ ASSERT_EQ("", client.do_request(R"({ "prefix": "perf dump", "format": "raw" })", &message));
+ ASSERT_EQ(R"({
+ "only_key": {
+ "foo": 4,
+ "bar": 0.000000000
+ }
+}
+)", message);
+
+ // test unlabeled perf counters are in the perf schema without the labels and counters section
+ ASSERT_EQ("", client.do_request(R"({ "prefix": "perf schema", "format": "raw" })", &message));
+ ASSERT_EQ(R"({
+ "only_key": {
+ "foo": {
+ "type": 2,
+ "metric_type": "gauge",
+ "value_type": "integer",
+ "description": "",
+ "nick": "",
+ "priority": 0,
+ "units": "none"
+ },
+ "bar": {
+ "type": 1,
+ "metric_type": "gauge",
+ "value_type": "real",
+ "description": "",
+ "nick": "",
+ "priority": 0,
+ "units": "none"
+ }
+ }
+}
+)", message);
+
+ g_ceph_context->get_perfcounters_collection()->clear();
+}