]>
Commit | Line | Data |
---|---|---|
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 | ||
38 | SEASTAR_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 | */ | |
59 | static 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 | ||
75 | SEASTAR_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 | ||
121 | SEASTAR_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 | } |