]> git.proxmox.com Git - ceph.git/blame - ceph/src/crush/CrushTester.h
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / crush / CrushTester.h
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#ifndef CEPH_CRUSH_TESTER_H
5#define CEPH_CRUSH_TESTER_H
6
7#include "crush/CrushWrapper.h"
8
9#include <fstream>
10#include <sstream>
11
12class CrushTester {
13 CrushWrapper& crush;
14 ostream& err;
15
16 map<int, int> device_weight;
17 int min_rule, max_rule;
18 int ruleset;
19 int min_x, max_x;
20 int min_rep, max_rep;
21 int64_t pool_id;
22
23 int num_batches;
24 bool use_crush;
25
26 float mark_down_device_ratio;
27 float mark_down_bucket_ratio;
28
29 bool output_utilization;
30 bool output_utilization_all;
31 bool output_statistics;
32 bool output_mappings;
33 bool output_bad_mappings;
34 bool output_choose_tries;
35
36 bool output_data_file;
37 bool output_csv;
38
39 string output_data_file_name;
40
41/*
42 * mark a ratio of devices down, can be used to simulate placement distributions
43 * under degrated cluster conditions
44 */
45 void adjust_weights(vector<__u32>& weight);
46
47 /*
48 * Get the maximum number of devices that could be selected to satisfy ruleno.
49 */
50 int get_maximum_affected_by_rule(int ruleno);
51
52 /*
53 * for maps where in devices have non-sequential id numbers, return a mapping of device id
54 * to a sequential id number. For example, if we have devices with id's 0 1 4 5 6 return a map
55 * where:
56 * 0 = 0
57 * 1 = 1
58 * 4 = 2
59 * 5 = 3
60 * 6 = 4
61 *
62 * which can help make post-processing easier
63 */
64 map<int,int> get_collapsed_mapping();
65
66 /*
67 * Essentially a re-implementation of CRUSH. Given a vector of devices
68 * check that the vector represents a valid placement for a given ruleno.
69 */
70 bool check_valid_placement(int ruleno, vector<int> in, const vector<__u32>& weight);
71
72 /*
73 * Generate a random selection of devices which satisfies ruleno. Essentially a
74 * monte-carlo simulator for CRUSH placements which can be used to compare the
75 * statistical distribution of the CRUSH algorithm to a random number generator
76 */
77 int random_placement(int ruleno, vector<int>& out, int maxout, vector<__u32>& weight);
78
79 // scaffolding to store data for off-line processing
80 struct tester_data_set {
81 vector <string> device_utilization;
82 vector <string> device_utilization_all;
83 vector <string> placement_information;
84 vector <string> batch_device_utilization_all;
85 vector <string> batch_device_expected_utilization_all;
86 map<int, float> proportional_weights;
87 map<int, float> proportional_weights_all;
88 map<int, float> absolute_weights;
89 } ;
90
91 void write_to_csv(ofstream& csv_file, vector<string>& payload)
92 {
93 if (csv_file.good())
94 for (vector<string>::iterator it = payload.begin(); it != payload.end(); ++it)
95 csv_file << (*it);
96 }
97
98 void write_to_csv(ofstream& csv_file, map<int, float>& payload)
99 {
100 if (csv_file.good())
101 for (map<int, float>::iterator it = payload.begin(); it != payload.end(); ++it)
102 csv_file << (*it).first << ',' << (*it).second << std::endl;
103 }
104
105 void write_data_set_to_csv(string user_tag, tester_data_set& tester_data)
106 {
107
108 ofstream device_utilization_file ((user_tag + (string)"-device_utilization.csv").c_str());
109 ofstream device_utilization_all_file ((user_tag + (string)"-device_utilization_all.csv").c_str());
110 ofstream placement_information_file ((user_tag + (string)"-placement_information.csv").c_str());
111 ofstream proportional_weights_file ((user_tag + (string)"-proportional_weights.csv").c_str());
112 ofstream proportional_weights_all_file ((user_tag + (string)"-proportional_weights_all.csv").c_str());
113 ofstream absolute_weights_file ((user_tag + (string)"-absolute_weights.csv").c_str());
114
115 // write the headers
116 device_utilization_file << "Device ID, Number of Objects Stored, Number of Objects Expected" << std::endl;
117 device_utilization_all_file << "Device ID, Number of Objects Stored, Number of Objects Expected" << std::endl;
118 proportional_weights_file << "Device ID, Proportional Weight" << std::endl;
119 proportional_weights_all_file << "Device ID, Proportional Weight" << std::endl;
120 absolute_weights_file << "Device ID, Absolute Weight" << std::endl;
121
122 placement_information_file << "Input";
123 for (int i = 0; i < max_rep; i++) {
124 placement_information_file << ", OSD" << i;
125 }
126 placement_information_file << std::endl;
127
128 write_to_csv(device_utilization_file, tester_data.device_utilization);
129 write_to_csv(device_utilization_all_file, tester_data.device_utilization_all);
130 write_to_csv(placement_information_file, tester_data.placement_information);
131 write_to_csv(proportional_weights_file, tester_data.proportional_weights);
132 write_to_csv(proportional_weights_all_file, tester_data.proportional_weights_all);
133 write_to_csv(absolute_weights_file, tester_data.absolute_weights);
134
135 device_utilization_file.close();
136 device_utilization_all_file.close();
137 placement_information_file.close();
138 proportional_weights_file.close();
139 absolute_weights_file.close();
140
141 if (num_batches > 1) {
142 ofstream batch_device_utilization_all_file ((user_tag + (string)"-batch_device_utilization_all.csv").c_str());
143 ofstream batch_device_expected_utilization_all_file ((user_tag + (string)"-batch_device_expected_utilization_all.csv").c_str());
144
145 batch_device_utilization_all_file << "Batch Round";
146 for (unsigned i = 0; i < tester_data.device_utilization.size(); i++) {
147 batch_device_utilization_all_file << ", Objects Stored on OSD" << i;
148 }
149 batch_device_utilization_all_file << std::endl;
150
151 batch_device_expected_utilization_all_file << "Batch Round";
152 for (unsigned i = 0; i < tester_data.device_utilization.size(); i++) {
153 batch_device_expected_utilization_all_file << ", Objects Expected on OSD" << i;
154 }
155 batch_device_expected_utilization_all_file << std::endl;
156
157 write_to_csv(batch_device_utilization_all_file, tester_data.batch_device_utilization_all);
158 write_to_csv(batch_device_expected_utilization_all_file, tester_data.batch_device_expected_utilization_all);
159 batch_device_expected_utilization_all_file.close();
160 batch_device_utilization_all_file.close();
161 }
162 }
163
164 void write_integer_indexed_vector_data_string(vector<string> &dst, int index, vector<int> vector_data);
165 void write_integer_indexed_vector_data_string(vector<string> &dst, int index, vector<float> vector_data);
166 void write_integer_indexed_scalar_data_string(vector<string> &dst, int index, int scalar_data);
167 void write_integer_indexed_scalar_data_string(vector<string> &dst, int index, float scalar_data);
168
169public:
170 CrushTester(CrushWrapper& c, ostream& eo)
171 : crush(c), err(eo),
172 min_rule(-1), max_rule(-1),
173 ruleset(-1),
174 min_x(-1), max_x(-1),
175 min_rep(-1), max_rep(-1),
176 pool_id(-1),
177 num_batches(1),
178 use_crush(true),
179 mark_down_device_ratio(0.0),
180 mark_down_bucket_ratio(1.0),
181 output_utilization(false),
182 output_utilization_all(false),
183 output_statistics(false),
184 output_mappings(false),
185 output_bad_mappings(false),
186 output_choose_tries(false),
187 output_data_file(false),
188 output_csv(false),
189 output_data_file_name("")
190
191 { }
192
193 void set_output_data_file_name(string name) {
194 output_data_file_name = name;
195 }
196 string get_output_data_file_name() const {
197 return output_data_file_name;
198 }
199
200 void set_output_data_file(bool b) {
201 output_data_file = b;
202 }
203 bool get_output_data_file() const {
204 return output_data_file;
205 }
206
207 void set_output_csv(bool b) {
208 output_csv = b;
209 }
210 bool get_output_csv() const {
211 return output_csv;
212 }
213
214 void set_output_utilization(bool b) {
215 output_utilization = b;
216 }
217 bool get_output_utilization() const {
218 return output_utilization;
219 }
220
221 void set_output_utilization_all(bool b) {
222 output_utilization_all = b;
223 }
224 bool get_output_utilization_all() const {
225 return output_utilization_all;
226 }
227
228 void set_output_statistics(bool b) {
229 output_statistics = b;
230 }
231 bool get_output_statistics() const {
232 return output_statistics;
233 }
234
235 void set_output_mappings(bool b) {
236 output_mappings = b;
237 }
238 bool get_output_mappings() const {
239 return output_mappings;
240 }
241
242 void set_output_bad_mappings(bool b) {
243 output_bad_mappings = b;
244 }
245 bool get_output_bad_mappings() const {
246 return output_bad_mappings;
247 }
248
249 void set_output_choose_tries(bool b) {
250 output_choose_tries = b;
251 }
252 bool get_output_choose_tries() const {
253 return output_choose_tries;
254 }
255
256 void set_batches(int b) {
257 num_batches = b;
258 }
259 int get_batches() const {
260 return num_batches;
261 }
262
263 void set_random_placement() {
264 use_crush = false;
265 }
266 bool get_random_placement() const {
267 return use_crush == false;
268 }
269
270 void set_bucket_down_ratio(float bucket_ratio) {
271 mark_down_bucket_ratio = bucket_ratio;
272 }
273 float get_bucket_down_ratio() const {
274 return mark_down_bucket_ratio;
275 }
276
277 void set_device_down_ratio(float device_ratio) {
278 mark_down_device_ratio = device_ratio;
279 }
280 float set_device_down_ratio() const {
281 return mark_down_device_ratio;
282 }
283
284 void set_device_weight(int dev, float f);
285
286 void set_min_rep(int r) {
287 min_rep = r;
288 }
289 int get_min_rep() const {
290 return min_rep;
291 }
292
293 void set_max_rep(int r) {
294 max_rep = r;
295 }
296 int get_max_rep() const {
297 return max_rep;
298 }
299
300 void set_num_rep(int r) {
301 min_rep = max_rep = r;
302 }
303
304 void set_min_x(int x) {
305 min_x = x;
306 }
307
308 void set_pool_id(int64_t x){
309 pool_id = x;
310 }
311
312 int get_min_x() const {
313 return min_x;
314 }
315
316 void set_max_x(int x) {
317 max_x = x;
318 }
319 int get_max_x() const {
320 return max_x;
321 }
322
323 void set_x(int x) {
324 min_x = max_x = x;
325 }
326
327 void set_min_rule(int rule) {
328 min_rule = rule;
329 }
330 int get_min_rule() const {
331 return min_rule;
332 }
333
334 void set_max_rule(int rule) {
335 max_rule = rule;
336 }
337 int get_max_rule() const {
338 return max_rule;
339 }
340
341 void set_rule(int rule) {
342 min_rule = max_rule = rule;
343 }
344
345 void set_ruleset(int rs) {
346 ruleset = rs;
347 }
348
349 /**
350 * check if any bucket/nodes is referencing an unknown name or type
351 * @param max_id rejects any non-bucket items with id less than this number,
352 * pass 0 to disable this check
353 * @return false if an dangling name/type is referenced or an item id is too
354 * large, true otherwise
355 */
356 bool check_name_maps(unsigned max_id = 0) const;
357 /**
358 * print out overlapped crush rules belonging to the same ruleset
359 */
360 void check_overlapped_rules() const;
361 int test();
362 int test_with_crushtool(const char *crushtool_cmd = "crushtool",
363 int max_id = -1,
364 int timeout = 0,
365 int ruleset = -1);
366};
367
368#endif