1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #ifndef CEPH_CRUSH_TESTER_H
5 #define CEPH_CRUSH_TESTER_H
7 #include "crush/CrushWrapper.h"
15 map
<int, int> device_weight
;
16 int min_rule
, max_rule
;
25 float mark_down_device_ratio
;
26 float mark_down_bucket_ratio
;
28 bool output_utilization
;
29 bool output_utilization_all
;
30 bool output_statistics
;
32 bool output_bad_mappings
;
33 bool output_choose_tries
;
35 bool output_data_file
;
38 string output_data_file_name
;
41 * mark a ratio of devices down, can be used to simulate placement distributions
42 * under degrated cluster conditions
44 void adjust_weights(vector
<__u32
>& weight
);
47 * Get the maximum number of devices that could be selected to satisfy ruleno.
49 int get_maximum_affected_by_rule(int ruleno
);
52 * for maps where in devices have non-sequential id numbers, return a mapping of device id
53 * to a sequential id number. For example, if we have devices with id's 0 1 4 5 6 return a map
61 * which can help make post-processing easier
63 map
<int,int> get_collapsed_mapping();
66 * Essentially a re-implementation of CRUSH. Given a vector of devices
67 * check that the vector represents a valid placement for a given ruleno.
69 bool check_valid_placement(int ruleno
, vector
<int> in
, const vector
<__u32
>& weight
);
72 * Generate a random selection of devices which satisfies ruleno. Essentially a
73 * monte-carlo simulator for CRUSH placements which can be used to compare the
74 * statistical distribution of the CRUSH algorithm to a random number generator
76 int random_placement(int ruleno
, vector
<int>& out
, int maxout
, vector
<__u32
>& weight
);
78 // scaffolding to store data for off-line processing
79 struct tester_data_set
{
80 vector
<string
> device_utilization
;
81 vector
<string
> device_utilization_all
;
82 vector
<string
> placement_information
;
83 vector
<string
> batch_device_utilization_all
;
84 vector
<string
> batch_device_expected_utilization_all
;
85 map
<int, float> proportional_weights
;
86 map
<int, float> proportional_weights_all
;
87 map
<int, float> absolute_weights
;
90 void write_to_csv(ofstream
& csv_file
, vector
<string
>& payload
)
93 for (vector
<string
>::iterator it
= payload
.begin(); it
!= payload
.end(); ++it
)
97 void write_to_csv(ofstream
& csv_file
, map
<int, float>& payload
)
100 for (map
<int, float>::iterator it
= payload
.begin(); it
!= payload
.end(); ++it
)
101 csv_file
<< (*it
).first
<< ',' << (*it
).second
<< std::endl
;
104 void write_data_set_to_csv(string user_tag
, tester_data_set
& tester_data
)
107 ofstream
device_utilization_file ((user_tag
+ (string
)"-device_utilization.csv").c_str());
108 ofstream
device_utilization_all_file ((user_tag
+ (string
)"-device_utilization_all.csv").c_str());
109 ofstream
placement_information_file ((user_tag
+ (string
)"-placement_information.csv").c_str());
110 ofstream
proportional_weights_file ((user_tag
+ (string
)"-proportional_weights.csv").c_str());
111 ofstream
proportional_weights_all_file ((user_tag
+ (string
)"-proportional_weights_all.csv").c_str());
112 ofstream
absolute_weights_file ((user_tag
+ (string
)"-absolute_weights.csv").c_str());
115 device_utilization_file
<< "Device ID, Number of Objects Stored, Number of Objects Expected" << std::endl
;
116 device_utilization_all_file
<< "Device ID, Number of Objects Stored, Number of Objects Expected" << std::endl
;
117 proportional_weights_file
<< "Device ID, Proportional Weight" << std::endl
;
118 proportional_weights_all_file
<< "Device ID, Proportional Weight" << std::endl
;
119 absolute_weights_file
<< "Device ID, Absolute Weight" << std::endl
;
121 placement_information_file
<< "Input";
122 for (int i
= 0; i
< max_rep
; i
++) {
123 placement_information_file
<< ", OSD" << i
;
125 placement_information_file
<< std::endl
;
127 write_to_csv(device_utilization_file
, tester_data
.device_utilization
);
128 write_to_csv(device_utilization_all_file
, tester_data
.device_utilization_all
);
129 write_to_csv(placement_information_file
, tester_data
.placement_information
);
130 write_to_csv(proportional_weights_file
, tester_data
.proportional_weights
);
131 write_to_csv(proportional_weights_all_file
, tester_data
.proportional_weights_all
);
132 write_to_csv(absolute_weights_file
, tester_data
.absolute_weights
);
134 device_utilization_file
.close();
135 device_utilization_all_file
.close();
136 placement_information_file
.close();
137 proportional_weights_file
.close();
138 absolute_weights_file
.close();
140 if (num_batches
> 1) {
141 ofstream
batch_device_utilization_all_file ((user_tag
+ (string
)"-batch_device_utilization_all.csv").c_str());
142 ofstream
batch_device_expected_utilization_all_file ((user_tag
+ (string
)"-batch_device_expected_utilization_all.csv").c_str());
144 batch_device_utilization_all_file
<< "Batch Round";
145 for (unsigned i
= 0; i
< tester_data
.device_utilization
.size(); i
++) {
146 batch_device_utilization_all_file
<< ", Objects Stored on OSD" << i
;
148 batch_device_utilization_all_file
<< std::endl
;
150 batch_device_expected_utilization_all_file
<< "Batch Round";
151 for (unsigned i
= 0; i
< tester_data
.device_utilization
.size(); i
++) {
152 batch_device_expected_utilization_all_file
<< ", Objects Expected on OSD" << i
;
154 batch_device_expected_utilization_all_file
<< std::endl
;
156 write_to_csv(batch_device_utilization_all_file
, tester_data
.batch_device_utilization_all
);
157 write_to_csv(batch_device_expected_utilization_all_file
, tester_data
.batch_device_expected_utilization_all
);
158 batch_device_expected_utilization_all_file
.close();
159 batch_device_utilization_all_file
.close();
163 void write_integer_indexed_vector_data_string(vector
<string
> &dst
, int index
, vector
<int> vector_data
);
164 void write_integer_indexed_vector_data_string(vector
<string
> &dst
, int index
, vector
<float> vector_data
);
165 void write_integer_indexed_scalar_data_string(vector
<string
> &dst
, int index
, int scalar_data
);
166 void write_integer_indexed_scalar_data_string(vector
<string
> &dst
, int index
, float scalar_data
);
169 CrushTester(CrushWrapper
& c
, ostream
& eo
)
171 min_rule(-1), max_rule(-1),
173 min_x(-1), max_x(-1),
174 min_rep(-1), max_rep(-1),
178 mark_down_device_ratio(0.0),
179 mark_down_bucket_ratio(1.0),
180 output_utilization(false),
181 output_utilization_all(false),
182 output_statistics(false),
183 output_mappings(false),
184 output_bad_mappings(false),
185 output_choose_tries(false),
186 output_data_file(false),
188 output_data_file_name("")
192 void set_output_data_file_name(string name
) {
193 output_data_file_name
= name
;
195 string
get_output_data_file_name() const {
196 return output_data_file_name
;
199 void set_output_data_file(bool b
) {
200 output_data_file
= b
;
202 bool get_output_data_file() const {
203 return output_data_file
;
206 void set_output_csv(bool b
) {
209 bool get_output_csv() const {
213 void set_output_utilization(bool b
) {
214 output_utilization
= b
;
216 bool get_output_utilization() const {
217 return output_utilization
;
220 void set_output_utilization_all(bool b
) {
221 output_utilization_all
= b
;
223 bool get_output_utilization_all() const {
224 return output_utilization_all
;
227 void set_output_statistics(bool b
) {
228 output_statistics
= b
;
230 bool get_output_statistics() const {
231 return output_statistics
;
234 void set_output_mappings(bool b
) {
237 bool get_output_mappings() const {
238 return output_mappings
;
241 void set_output_bad_mappings(bool b
) {
242 output_bad_mappings
= b
;
244 bool get_output_bad_mappings() const {
245 return output_bad_mappings
;
248 void set_output_choose_tries(bool b
) {
249 output_choose_tries
= b
;
251 bool get_output_choose_tries() const {
252 return output_choose_tries
;
255 void set_batches(int b
) {
258 int get_batches() const {
262 void set_random_placement() {
265 bool get_random_placement() const {
266 return use_crush
== false;
269 void set_bucket_down_ratio(float bucket_ratio
) {
270 mark_down_bucket_ratio
= bucket_ratio
;
272 float get_bucket_down_ratio() const {
273 return mark_down_bucket_ratio
;
276 void set_device_down_ratio(float device_ratio
) {
277 mark_down_device_ratio
= device_ratio
;
279 float set_device_down_ratio() const {
280 return mark_down_device_ratio
;
283 void set_device_weight(int dev
, float f
);
285 void set_min_rep(int r
) {
288 int get_min_rep() const {
292 void set_max_rep(int r
) {
295 int get_max_rep() const {
299 void set_num_rep(int r
) {
300 min_rep
= max_rep
= r
;
303 void set_min_x(int x
) {
307 void set_pool_id(int64_t x
){
311 int get_min_x() const {
315 void set_max_x(int x
) {
318 int get_max_x() const {
326 void set_min_rule(int rule
) {
329 int get_min_rule() const {
333 void set_max_rule(int rule
) {
336 int get_max_rule() const {
340 void set_rule(int rule
) {
341 min_rule
= max_rule
= rule
;
344 void set_ruleset(int rs
) {
349 * check if any bucket/nodes is referencing an unknown name or type
350 * @param max_id rejects any non-bucket items with id less than this number,
351 * pass 0 to disable this check
352 * @return false if an dangling name/type is referenced or an item id is too
353 * large, true otherwise
355 bool check_name_maps(unsigned max_id
= 0) const;
357 * print out overlapped crush rules belonging to the same ruleset
359 void check_overlapped_rules() const;
361 int test_with_crushtool(const char *crushtool_cmd
= "crushtool",