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"
16 map
<int, int> device_weight
;
17 int min_rule
, max_rule
;
26 float mark_down_device_ratio
;
27 float mark_down_bucket_ratio
;
29 bool output_utilization
;
30 bool output_utilization_all
;
31 bool output_statistics
;
33 bool output_bad_mappings
;
34 bool output_choose_tries
;
36 bool output_data_file
;
39 string output_data_file_name
;
42 * mark a ratio of devices down, can be used to simulate placement distributions
43 * under degrated cluster conditions
45 void adjust_weights(vector
<__u32
>& weight
);
48 * Get the maximum number of devices that could be selected to satisfy ruleno.
50 int get_maximum_affected_by_rule(int ruleno
);
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
62 * which can help make post-processing easier
64 map
<int,int> get_collapsed_mapping();
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.
70 bool check_valid_placement(int ruleno
, vector
<int> in
, const vector
<__u32
>& weight
);
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
77 int random_placement(int ruleno
, vector
<int>& out
, int maxout
, vector
<__u32
>& weight
);
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
;
91 void write_to_csv(ofstream
& csv_file
, vector
<string
>& payload
)
94 for (vector
<string
>::iterator it
= payload
.begin(); it
!= payload
.end(); ++it
)
98 void write_to_csv(ofstream
& csv_file
, map
<int, float>& payload
)
101 for (map
<int, float>::iterator it
= payload
.begin(); it
!= payload
.end(); ++it
)
102 csv_file
<< (*it
).first
<< ',' << (*it
).second
<< std::endl
;
105 void write_data_set_to_csv(string user_tag
, tester_data_set
& tester_data
)
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());
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
;
122 placement_information_file
<< "Input";
123 for (int i
= 0; i
< max_rep
; i
++) {
124 placement_information_file
<< ", OSD" << i
;
126 placement_information_file
<< std::endl
;
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
);
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();
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());
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
;
149 batch_device_utilization_all_file
<< std::endl
;
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
;
155 batch_device_expected_utilization_all_file
<< std::endl
;
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();
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
);
170 CrushTester(CrushWrapper
& c
, ostream
& eo
)
172 min_rule(-1), max_rule(-1),
174 min_x(-1), max_x(-1),
175 min_rep(-1), max_rep(-1),
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),
189 output_data_file_name("")
193 void set_output_data_file_name(string name
) {
194 output_data_file_name
= name
;
196 string
get_output_data_file_name() const {
197 return output_data_file_name
;
200 void set_output_data_file(bool b
) {
201 output_data_file
= b
;
203 bool get_output_data_file() const {
204 return output_data_file
;
207 void set_output_csv(bool b
) {
210 bool get_output_csv() const {
214 void set_output_utilization(bool b
) {
215 output_utilization
= b
;
217 bool get_output_utilization() const {
218 return output_utilization
;
221 void set_output_utilization_all(bool b
) {
222 output_utilization_all
= b
;
224 bool get_output_utilization_all() const {
225 return output_utilization_all
;
228 void set_output_statistics(bool b
) {
229 output_statistics
= b
;
231 bool get_output_statistics() const {
232 return output_statistics
;
235 void set_output_mappings(bool b
) {
238 bool get_output_mappings() const {
239 return output_mappings
;
242 void set_output_bad_mappings(bool b
) {
243 output_bad_mappings
= b
;
245 bool get_output_bad_mappings() const {
246 return output_bad_mappings
;
249 void set_output_choose_tries(bool b
) {
250 output_choose_tries
= b
;
252 bool get_output_choose_tries() const {
253 return output_choose_tries
;
256 void set_batches(int b
) {
259 int get_batches() const {
263 void set_random_placement() {
266 bool get_random_placement() const {
267 return use_crush
== false;
270 void set_bucket_down_ratio(float bucket_ratio
) {
271 mark_down_bucket_ratio
= bucket_ratio
;
273 float get_bucket_down_ratio() const {
274 return mark_down_bucket_ratio
;
277 void set_device_down_ratio(float device_ratio
) {
278 mark_down_device_ratio
= device_ratio
;
280 float set_device_down_ratio() const {
281 return mark_down_device_ratio
;
284 void set_device_weight(int dev
, float f
);
286 void set_min_rep(int r
) {
289 int get_min_rep() const {
293 void set_max_rep(int r
) {
296 int get_max_rep() const {
300 void set_num_rep(int r
) {
301 min_rep
= max_rep
= r
;
304 void set_min_x(int x
) {
308 void set_pool_id(int64_t x
){
312 int get_min_x() const {
316 void set_max_x(int x
) {
319 int get_max_x() const {
327 void set_min_rule(int rule
) {
330 int get_min_rule() const {
334 void set_max_rule(int rule
) {
337 int get_max_rule() const {
341 void set_rule(int rule
) {
342 min_rule
= max_rule
= rule
;
345 void set_ruleset(int rs
) {
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
356 bool check_name_maps(unsigned max_id
= 0) const;
358 * print out overlapped crush rules belonging to the same ruleset
360 void check_overlapped_rules() const;
362 int test_with_crushtool(const char *crushtool_cmd
= "crushtool",