]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/tests/unit/metrics_test.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / seastar / tests / unit / metrics_test.cc
CommitLineData
9f95a23c
TL
1/*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18
19/*
20 * Copyright (C) 2019 ScyllaDB.
21 */
22
23#include <seastar/core/metrics_registration.hh>
24#include <seastar/core/metrics.hh>
25#include <seastar/core/metrics_api.hh>
f67539c2 26#include <seastar/core/reactor.hh>
9f95a23c
TL
27#include <seastar/core/scheduling.hh>
28#include <seastar/core/sleep.hh>
29#include <seastar/core/sharded.hh>
30#include <seastar/core/do_with.hh>
31#include <seastar/core/io_queue.hh>
f67539c2 32#include <seastar/core/loop.hh>
9f95a23c
TL
33#include <seastar/testing/test_case.hh>
34#include <seastar/testing/thread_test_case.hh>
35#include <seastar/testing/test_runner.hh>
36#include <boost/range/irange.hpp>
37
38SEASTAR_TEST_CASE(test_add_group) {
39 using namespace seastar::metrics;
40 // Just has to compile:
41 metric_groups()
42 .add_group("g1", {})
43 .add_group("g2", std::vector<metric_definition>());
44 return seastar::make_ready_future();
45}
46
47/**
48 * This function return the different name label values
49 * for the named metric.
50 *
51 * @note: If the statistic or label doesn't exist, the test
52 * that calls this function will fail.
53 *
54 * @param metric_name - the metric name
55 * @param label_name - the label name
56 * @return a set containing all the different values
57 * of the label.
58 */
59static std::set<seastar::sstring> get_label_values(seastar::sstring metric_name, seastar::sstring label_name) {
60 namespace smi = seastar::metrics::impl;
61 auto all_metrics = smi::get_values();
62 const auto& all_metadata = *all_metrics->metadata;
63 const auto qp_group = find_if(cbegin(all_metadata), cend(all_metadata),
64 [&metric_name] (const auto& x) { return x.mf.name == metric_name; });
65 BOOST_REQUIRE(qp_group != cend(all_metadata));
66 std::set<seastar::sstring> labels;
67 for (const auto& metric : qp_group->metrics) {
68 const auto found = metric.id.labels().find(label_name);
69 BOOST_REQUIRE(found != metric.id.labels().cend());
70 labels.insert(found->second);
71 }
72 return labels;
73}
74
75SEASTAR_THREAD_TEST_CASE(test_renaming_scheuling_groups) {
76 // this seams a little bit out of place but the
77 // renaming functionality is primarily for statistics
78 // otherwise those classes could have just been reused
79 // without renaming them.
80 using namespace seastar;
81
82 static const char* name1 = "A";
83 static const char* name2 = "B";
84 scheduling_group sg = create_scheduling_group("hello", 111).get0();
85 boost::integer_range<int> rng(0, 1000);
86 // repeatedly change the group name back and forth in
87 // decresing time intervals to see if it generate double
88 //registration statistics errors.
89 for (auto&& i : rng) {
90 const char* name = i%2 ? name1 : name2;
91 const char* prev_name = i%2 ? name2 : name1;
92 sleep(std::chrono::microseconds(100000/(i+1))).get();
93 rename_scheduling_group(sg, name).get();
94 std::set<sstring> label_vals = get_label_values(sstring("scheduler_shares"), sstring("group"));
95 // validate that the name that we *renamed to* is in the stats
96 BOOST_REQUIRE(label_vals.find(sstring(name)) != label_vals.end());
97 // validate that the name that we *renamed from* is *not* in the stats
98 BOOST_REQUIRE(label_vals.find(sstring(prev_name)) == label_vals.end());
99 }
100
101 smp::invoke_on_all([sg] () {
102 return do_with(std::uniform_int_distribution<int>(), boost::irange<int>(0, 1000),
103 [sg] (std::uniform_int_distribution<int>& dist, boost::integer_range<int>& rng) {
104 // flip a fair coin and rename to one of two options and rename to that
105 // scheduling group name, do it 1000 in parallel on all shards so there
106 // is a chance of collision.
107 return do_for_each(rng, [sg, &dist] (auto i) {
108 bool odd = dist(seastar::testing::local_random_engine)%2;
109 return rename_scheduling_group(sg, odd ? name1 : name2);
110 });
111 });
112 }).get();
113
114 std::set<sstring> label_vals = get_label_values(sstring("scheduler_shares"), sstring("group"));
115 // validate that only one of the names is eventually in the metrics
116 bool name1_found = label_vals.find(sstring(name1)) != label_vals.end();
117 bool name2_found = label_vals.find(sstring(name2)) != label_vals.end();
118 BOOST_REQUIRE((name1_found && !name2_found) || (name2_found && !name1_found));
119}
120
121SEASTAR_THREAD_TEST_CASE(test_renaming_io_priority_classes) {
122 // this seams a little bit out of place but the
123 // renaming functionality is primarily for statistics
124 // otherwise those classes could have just been reused
125 // without renaming them.
126 using namespace seastar;
127 static const char* name1 = "A";
128 static const char* name2 = "B";
20effc67
TL
129 seastar::io_priority_class pc = io_priority_class::register_one("hello",100);
130 smp::invoke_on_all([&pc] () {
9f95a23c
TL
131 // this is a trick to get all of the queues actually register their
132 // stats.
20effc67 133 return pc.update_shares(101);
9f95a23c
TL
134 }).get();
135
136 boost::integer_range<int> rng(0, 1000);
137 // repeatedly change the group name back and forth in
138 // decresing time intervals to see if it generate double
139 //registration statistics errors.
140 for (auto&& i : rng) {
141 const char* name = i%2 ? name1 : name2;
142 const char* prev_name = i%2 ? name2 : name1;
143 sleep(std::chrono::microseconds(100000/(i+1))).get();
20effc67 144 pc.rename(name).get();
9f95a23c
TL
145 std::set<sstring> label_vals = get_label_values(sstring("io_queue_shares"), sstring("class"));
146 // validate that the name that we *renamed to* is in the stats
147 BOOST_REQUIRE(label_vals.find(sstring(name)) != label_vals.end());
148 // validate that the name that we *renamed from* is *not* in the stats
149 BOOST_REQUIRE(label_vals.find(sstring(prev_name)) == label_vals.end());
150 }
151
20effc67 152 smp::invoke_on_all([&pc] () {
9f95a23c 153 return do_with(std::uniform_int_distribution<int>(), boost::irange<int>(0, 1000),
20effc67 154 [&pc] (std::uniform_int_distribution<int>& dist, boost::integer_range<int>& rng) {
9f95a23c
TL
155 // flip a fair coin and rename to one of two options and rename to that
156 // scheduling group name, do it 1000 in parallel on all shards so there
157 // is a chance of collision.
20effc67 158 return do_for_each(rng, [&pc, &dist] (auto i) {
9f95a23c 159 bool odd = dist(seastar::testing::local_random_engine)%2;
20effc67 160 return pc.rename(odd ? name1 : name2);
9f95a23c
TL
161 });
162 });
163 }).get();
164
165 std::set<sstring> label_vals = get_label_values(sstring("io_queue_shares"), sstring("class"));
166 // validate that only one of the names is eventually in the metrics
167 bool name1_found = label_vals.find(sstring(name1)) != label_vals.end();
168 bool name2_found = label_vals.find(sstring(name2)) != label_vals.end();
169 BOOST_REQUIRE((name1_found && !name2_found) || (name2_found && !name1_found));
170}