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 std::map
<int, int> device_weight
;
16 int min_rule
, max_rule
;
24 float mark_down_device_ratio
;
25 float mark_down_bucket_ratio
;
27 bool output_utilization
;
28 bool output_utilization_all
;
29 bool output_statistics
;
31 bool output_bad_mappings
;
32 bool output_choose_tries
;
34 bool output_data_file
;
37 std::string output_data_file_name
;
40 * mark a ratio of devices down, can be used to simulate placement distributions
41 * under degrated cluster conditions
43 void adjust_weights(std::vector
<__u32
>& weight
);
46 * Get the maximum number of devices that could be selected to satisfy ruleno.
48 int get_maximum_affected_by_rule(int ruleno
);
51 * for maps where in devices have non-sequential id numbers, return a mapping of device id
52 * to a sequential id number. For example, if we have devices with id's 0 1 4 5 6 return a map
60 * which can help make post-processing easier
62 std::map
<int,int> get_collapsed_mapping();
65 * Essentially a re-implementation of CRUSH. Given a vector of devices
66 * check that the vector represents a valid placement for a given ruleno.
68 bool check_valid_placement(int ruleno
, std::vector
<int> in
, const std::vector
<__u32
>& weight
);
71 * Generate a random selection of devices which satisfies ruleno. Essentially a
72 * monte-carlo simulator for CRUSH placements which can be used to compare the
73 * statistical distribution of the CRUSH algorithm to a random number generator
75 int random_placement(int ruleno
, std::vector
<int>& out
, int maxout
, std::vector
<__u32
>& weight
);
77 // scaffolding to store data for off-line processing
78 struct tester_data_set
{
79 std::vector
<std::string
> device_utilization
;
80 std::vector
<std::string
> device_utilization_all
;
81 std::vector
<std::string
> placement_information
;
82 std::vector
<std::string
> batch_device_utilization_all
;
83 std::vector
<std::string
> batch_device_expected_utilization_all
;
84 std::map
<int, float> proportional_weights
;
85 std::map
<int, float> proportional_weights_all
;
86 std::map
<int, float> absolute_weights
;
89 void write_to_csv(std::ofstream
& csv_file
, std::vector
<std::string
>& payload
)
92 for (std::vector
<std::string
>::iterator it
= payload
.begin(); it
!= payload
.end(); ++it
)
96 void write_to_csv(std::ofstream
& csv_file
, std::map
<int, float>& payload
)
99 for (std::map
<int, float>::iterator it
= payload
.begin(); it
!= payload
.end(); ++it
)
100 csv_file
<< (*it
).first
<< ',' << (*it
).second
<< std::endl
;
103 void write_data_set_to_csv(std::string user_tag
, tester_data_set
& tester_data
)
106 std::ofstream
device_utilization_file((user_tag
+ (std::string
)"-device_utilization.csv").c_str());
107 std::ofstream
device_utilization_all_file((user_tag
+ (std::string
)"-device_utilization_all.csv").c_str());
108 std::ofstream
placement_information_file((user_tag
+ (std::string
)"-placement_information.csv").c_str());
109 std::ofstream
proportional_weights_file((user_tag
+ (std::string
)"-proportional_weights.csv").c_str());
110 std::ofstream
proportional_weights_all_file((user_tag
+ (std::string
)"-proportional_weights_all.csv").c_str());
111 std::ofstream
absolute_weights_file((user_tag
+ (std::string
)"-absolute_weights.csv").c_str());
114 device_utilization_file
<< "Device ID, Number of Objects Stored, Number of Objects Expected" << std::endl
;
115 device_utilization_all_file
<< "Device ID, Number of Objects Stored, Number of Objects Expected" << std::endl
;
116 proportional_weights_file
<< "Device ID, Proportional Weight" << std::endl
;
117 proportional_weights_all_file
<< "Device ID, Proportional Weight" << std::endl
;
118 absolute_weights_file
<< "Device ID, Absolute Weight" << std::endl
;
120 placement_information_file
<< "Input";
121 for (int i
= 0; i
< max_rep
; i
++) {
122 placement_information_file
<< ", OSD" << i
;
124 placement_information_file
<< std::endl
;
126 write_to_csv(device_utilization_file
, tester_data
.device_utilization
);
127 write_to_csv(device_utilization_all_file
, tester_data
.device_utilization_all
);
128 write_to_csv(placement_information_file
, tester_data
.placement_information
);
129 write_to_csv(proportional_weights_file
, tester_data
.proportional_weights
);
130 write_to_csv(proportional_weights_all_file
, tester_data
.proportional_weights_all
);
131 write_to_csv(absolute_weights_file
, tester_data
.absolute_weights
);
133 device_utilization_file
.close();
134 device_utilization_all_file
.close();
135 placement_information_file
.close();
136 proportional_weights_file
.close();
137 absolute_weights_file
.close();
139 if (num_batches
> 1) {
140 std::ofstream
batch_device_utilization_all_file ((user_tag
+ (std::string
)"-batch_device_utilization_all.csv").c_str());
141 std::ofstream
batch_device_expected_utilization_all_file ((user_tag
+ (std::string
)"-batch_device_expected_utilization_all.csv").c_str());
143 batch_device_utilization_all_file
<< "Batch Round";
144 for (unsigned i
= 0; i
< tester_data
.device_utilization
.size(); i
++) {
145 batch_device_utilization_all_file
<< ", Objects Stored on OSD" << i
;
147 batch_device_utilization_all_file
<< std::endl
;
149 batch_device_expected_utilization_all_file
<< "Batch Round";
150 for (unsigned i
= 0; i
< tester_data
.device_utilization
.size(); i
++) {
151 batch_device_expected_utilization_all_file
<< ", Objects Expected on OSD" << i
;
153 batch_device_expected_utilization_all_file
<< std::endl
;
155 write_to_csv(batch_device_utilization_all_file
, tester_data
.batch_device_utilization_all
);
156 write_to_csv(batch_device_expected_utilization_all_file
, tester_data
.batch_device_expected_utilization_all
);
157 batch_device_expected_utilization_all_file
.close();
158 batch_device_utilization_all_file
.close();
162 void write_integer_indexed_vector_data_string(std::vector
<std::string
> &dst
, int index
, std::vector
<int> vector_data
);
163 void write_integer_indexed_vector_data_string(std::vector
<std::string
> &dst
, int index
, std::vector
<float> vector_data
);
164 void write_integer_indexed_scalar_data_string(std::vector
<std::string
> &dst
, int index
, int scalar_data
);
165 void write_integer_indexed_scalar_data_string(std::vector
<std::string
> &dst
, int index
, float scalar_data
);
168 CrushTester(CrushWrapper
& c
, std::ostream
& eo
)
170 min_rule(-1), max_rule(-1),
171 min_x(-1), max_x(-1),
172 min_rep(-1), max_rep(-1),
176 mark_down_device_ratio(0.0),
177 mark_down_bucket_ratio(1.0),
178 output_utilization(false),
179 output_utilization_all(false),
180 output_statistics(false),
181 output_mappings(false),
182 output_bad_mappings(false),
183 output_choose_tries(false),
184 output_data_file(false),
186 output_data_file_name("")
190 void set_output_data_file_name(std::string name
) {
191 output_data_file_name
= name
;
193 std::string
get_output_data_file_name() const {
194 return output_data_file_name
;
197 void set_output_data_file(bool b
) {
198 output_data_file
= b
;
200 bool get_output_data_file() const {
201 return output_data_file
;
204 void set_output_csv(bool b
) {
207 bool get_output_csv() const {
211 void set_output_utilization(bool b
) {
212 output_utilization
= b
;
214 bool get_output_utilization() const {
215 return output_utilization
;
218 void set_output_utilization_all(bool b
) {
219 output_utilization_all
= b
;
221 bool get_output_utilization_all() const {
222 return output_utilization_all
;
225 void set_output_statistics(bool b
) {
226 output_statistics
= b
;
228 bool get_output_statistics() const {
229 return output_statistics
;
232 void set_output_mappings(bool b
) {
235 bool get_output_mappings() const {
236 return output_mappings
;
239 void set_output_bad_mappings(bool b
) {
240 output_bad_mappings
= b
;
242 bool get_output_bad_mappings() const {
243 return output_bad_mappings
;
246 void set_output_choose_tries(bool b
) {
247 output_choose_tries
= b
;
249 bool get_output_choose_tries() const {
250 return output_choose_tries
;
253 void set_batches(int b
) {
256 int get_batches() const {
260 void set_random_placement() {
263 bool get_random_placement() const {
264 return use_crush
== false;
267 void set_bucket_down_ratio(float bucket_ratio
) {
268 mark_down_bucket_ratio
= bucket_ratio
;
270 float get_bucket_down_ratio() const {
271 return mark_down_bucket_ratio
;
274 void set_device_down_ratio(float device_ratio
) {
275 mark_down_device_ratio
= device_ratio
;
277 float set_device_down_ratio() const {
278 return mark_down_device_ratio
;
281 void set_device_weight(int dev
, float f
);
283 void set_min_rep(int r
) {
286 int get_min_rep() const {
290 void set_max_rep(int r
) {
293 int get_max_rep() const {
297 void set_num_rep(int r
) {
298 min_rep
= max_rep
= r
;
301 void set_min_x(int x
) {
305 void set_pool_id(int64_t x
){
309 int get_min_x() const {
313 void set_max_x(int x
) {
316 int get_max_x() const {
324 void set_min_rule(int rule
) {
327 int get_min_rule() const {
331 void set_max_rule(int rule
) {
334 int get_max_rule() const {
338 void set_rule(int rule
) {
339 min_rule
= max_rule
= rule
;
343 * check if any bucket/nodes is referencing an unknown name or type
344 * @param max_id rejects any non-bucket items with id less than this number,
345 * pass 0 to disable this check
346 * @return false if an dangling name/type is referenced or an item id is too
347 * large, true otherwise
349 bool check_name_maps(unsigned max_id
= 0) const;
351 int test_with_fork(int timeout
);
353 int compare(CrushWrapper
& other
);