11
45
device_weight[dev] = w;
48
void CrushTester::adjust_weights(vector<__u32>& weight)
50
#ifdef HAVE_BOOST_RANDOM_DISCRETE_DISTRIBUTION
51
//err << "start " << weight << std::endl;
53
if (mark_down_device_ratio > 0) {
55
vector<int> bucket_ids;
56
for (int i = 0; i < crush.get_max_buckets(); i++) {
58
if (crush.get_bucket_weight(id) > 0) {
59
bucket_ids.push_back(id);
63
// get buckets that are one level above a device
64
vector<int> buckets_above_devices;
65
for (unsigned i = 0; i < bucket_ids.size(); i++) {
66
// grab the first child object of a bucket and check if it's ID is less than 0
67
int id = bucket_ids[i];
68
if (crush.get_bucket_size(id) == 0)
70
int first_child = crush.get_bucket_item(id, 0); // returns the ID of the bucket or device
71
if (first_child >= 0) {
72
buckets_above_devices.push_back(id);
76
// create the uniform distribution on the number of buckets to visit
77
boost::random::uniform_int_distribution<> bucket_choose(0, buckets_above_devices.size() - 1);
79
// permute bucket list
80
for (unsigned i = 0; i < buckets_above_devices.size(); i++) {
81
unsigned j = bucket_choose(bucket_gen);
82
std::swap(buckets_above_devices[i], buckets_above_devices[j]);
85
// calculate how many buckets and devices we need to reap...
86
int num_buckets_to_visit = (int) (mark_down_bucket_ratio * buckets_above_devices.size());
88
for (int i = 0; i < num_buckets_to_visit; i++) {
89
int id = buckets_above_devices[i];
90
int size = crush.get_bucket_size(id);
92
for (int o = 0; o < size; o++)
93
items.push_back(crush.get_bucket_item(id, o));
96
boost::random::uniform_int_distribution<> item_choose(0, size - 1);
97
for (int o = 0; o < size; o++) {
98
int j = item_choose(bucket_gen);
99
std::swap(items[o], items[j]);
102
int local_devices_to_visit = (int) (mark_down_device_ratio*size);
103
for (int o = 0; o < local_devices_to_visit; o++){
104
int item = crush.get_bucket_item(id, o);
105
//err << "device " << item << " in bucket " << id << " weight " << crush.get_bucket_item_weight(id, o) << std::endl;
111
err << "WARNING: boost::random not compiled in, mark down ratios not working" << std::endl;
14
115
int CrushTester::test()
16
117
if (min_rule < 0 || max_rule < 0) {
43
158
minr = crush.get_rule_mask_min_size(r);
44
159
maxr = crush.get_rule_mask_max_size(r);
162
if (output_statistics)
48
163
err << "rule " << r << " (" << crush.get_rule_name(r)
49
<< "), x = " << min_x << ".." << max_x
50
<< ", numrep = " << minr << ".." << maxr
164
<< "), x = " << min_x << ".." << max_x
165
<< ", numrep = " << minr << ".." << maxr
52
168
for (int nr = minr; nr <= maxr; nr++) {
53
169
vector<int> per(crush.get_max_devices());
54
170
map<int,int> sizes;
55
for (int x = min_x; x <= max_x; x++) {
57
crush.do_rule(r, x, out, nr, weight);
60
err << " rule " << r << " x " << x << " " << out << std::endl;
61
for (unsigned i = 0; i < out.size(); i++)
65
for (unsigned i = 0; i < per.size(); i++)
67
err << " device " << i << ":\t" << per[i] << std::endl;
172
int num_objects = ((max_x - min_x) + 1);
173
float num_devices = (float) per.size(); // get the total number of devices, better to cast as a float here
175
#ifdef HAVE_BOOST_RANDOM_DISCRETE_DISTRIBUTION
176
float test_chi_statistic = 0.0; // our observed chi squared statistic
178
// look up the maximum expected chi squared statistic for the 5% and 1% confidence levels
179
float chi_statistic_five_percent = quantile(complement(chi_squared(num_devices_active-1), 0.05));
180
float chi_statistic_one_percent = quantile(complement(chi_squared(num_devices_active-1), 0.01));
183
// create a map to hold batch-level placement information
184
map<int, vector<int> > batchPer;
185
vector <float> deviceTestChi (per.size() );
187
int objects_per_batch = num_objects / num_batches;
189
int batch_min = min_x;
190
int batch_max = min_x + objects_per_batch - 1;
193
#ifdef HAVE_BOOST_RANDOM_DISCRETE_DISTRIBUTION
194
// placeholders for the reference values, we will probably SEGFAULT if we try zero degrees of freedom
195
float batch_chi_statistic_five_percent = -1.0;
196
float batch_chi_statistic_one_percent = -1.0;
198
if (num_batches > 1) {
199
// look up the chi squared statistic for the 5% and 1% confidence levels
200
batch_chi_statistic_five_percent = quantile(complement(chi_squared(num_batches-1), 0.05));
201
batch_chi_statistic_one_percent = quantile(complement(chi_squared(num_batches-1), 0.01));
205
// get the total weight of the system
206
int total_weight = 0;
208
for (unsigned i = 0; i < per.size(); i++)
209
total_weight += weight[i];
211
// compute the expected number of objects stored per device in the absence of weighting
212
float expected_objects = min(nr, num_devices_active) * num_objects;
214
// compute each device's proportional weight
215
vector<float> proportional_weights( per.size() );
217
for (unsigned i = 0; i < per.size(); i++)
218
proportional_weights[i] = (float) weight[i] / (float) total_weight;
221
#ifdef HAVE_BOOST_RANDOM_DISCRETE_DISTRIBUTION
222
// create a random number generator with the device weights to use for simulating placements
223
boost::random::discrete_distribution<> dist(proportional_weights);
226
// compute the expected number of objects stored per device when a device's weight is considered
227
vector<float> num_objects_expected(num_devices);
229
for (unsigned i = 0; i < num_devices; i++)
230
num_objects_expected[i] = (proportional_weights[i]*expected_objects);
233
for (int currentBatch = 0; currentBatch < num_batches; currentBatch++) {
234
if (currentBatch == (num_batches - 1)) {
236
objects_per_batch = (batch_max - batch_min + 1);
239
float batch_expected_objects = min(nr, num_devices_active) * objects_per_batch;
240
vector<float> batch_num_objects_expected( per.size() );
242
for (unsigned i = 0; i < per.size() ; i++)
243
batch_num_objects_expected[i] = (proportional_weights[i]*batch_expected_objects);
245
// create a vector to hold placement results temporarily
246
vector<int> temporary_per ( per.size() );
248
for (int x = batch_min; x <= batch_max; x++) {
250
// create a vector to hold the results of a CRUSH placement or RNG simulation
254
if (output_statistics)
255
err << "CRUSH"; // prepend CRUSH to placement output
256
crush.do_rule(r, x, out, nr, weight);
258
if (output_statistics)
259
err << "RNG"; // prepend RNG to placement output to denote simulation
261
#ifdef HAVE_BOOST_RANDOM_DISCRETE_DISTRIBUTION
262
// fill our vector with random numbers representing an OSD ID
263
// one day we'll worry about duplicate entries, probably
264
for (int j = 0; j < nr; j++)
265
out.push_back( dist(gen) );
270
if (output_statistics)
271
err << " rule " << r << " x " << x << " " << out << std::endl;
272
for (unsigned i = 0; i < out.size(); i++) {
274
temporary_per[out[i]]++;
277
batchPer[currentBatch] = temporary_per;
280
if (output_bad_mappings && out.size() != (unsigned)nr) {
281
cout << "bad mapping rule " << r << " x " << x << " num_rep " << nr << " result " << out << std::endl;
285
// compute chi squared statistic for device examining the uniformity this batch of placements
286
for (unsigned i = 0; i < per.size(); i++)
287
deviceTestChi[i] += pow( (temporary_per[i] - batch_num_objects_expected[i]), 2) /
288
batch_num_objects_expected[i];
290
batch_min = batch_max + 1;
291
batch_max = batch_min + objects_per_batch - 1;
294
for (unsigned i = 0; i < per.size(); i++)
295
if (output_utilization && !output_statistics)
296
err << " device " << i
68
299
for (map<int,int>::iterator p = sizes.begin(); p != sizes.end(); p++)
69
if (verbose>0 || p->first != nr)
70
err << "rule " << r << " (" << crush.get_rule_name(r) << ") num_rep " << nr
71
<< " result size == " << p->first << ":\t"
72
<< p->second << "/" << (max_x-min_x+1) << std::endl;
300
if ( output_statistics || p->first != nr)
301
err << "rule " << r << " (" << crush.get_rule_name(r) << ") num_rep " << nr
302
<< " result size == " << p->first << ":\t"
303
<< p->second << "/" << (max_x-min_x+1) << std::endl;
306
#ifdef HAVE_BOOST_RANDOM_DISCRETE_DISTRIBUTION
307
// compute our overall test chi squared statistic examining the final distribution of placements
308
for (unsigned i = 0; i < per.size(); i++)
309
if (num_objects_expected[i] > 0)
310
test_chi_statistic += pow((num_objects_expected[i] - per[i]),2) / (float) num_objects_expected[i];
312
int num_devices_failing_at_five_percent = 0;
313
int num_devices_failing_at_one_percent = 0;
315
for (unsigned i = 0; i < per.size(); i++) {
316
if (deviceTestChi[i] > batch_chi_statistic_five_percent)
317
num_devices_failing_at_five_percent++;
318
if (deviceTestChi[i] > batch_chi_statistic_one_percent)
319
num_devices_failing_at_one_percent++;
323
if (output_statistics)
324
for (unsigned i = 0; i < per.size(); i++) {
325
if (output_utilization && num_batches > 1){
326
if (num_objects_expected[i] > 0 && per[i] > 0) {
327
err << " device " << i << ":\t"
328
<< "\t" << " stored " << ": " << per[i]
329
<< "\t" << " expected " << ": " << num_objects_expected[i]
330
#ifdef HAVE_BOOST_RANDOM_DISCRETE_DISTRIBUTION
331
<< "\t" << " X^2 " << ": " << deviceTestChi[i]
332
<< "\t" << " critical (5% confidence) " << ": " << batch_chi_statistic_five_percent
333
<< "\t" << " (1% confidence) " << ": " << batch_chi_statistic_one_percent
337
} else if (output_utilization_all && num_batches > 1) {
338
err << " device " << i << ":\t"
339
<< "\t" << " stored " << ": " << per[i]
340
<< "\t" << " expected " << ": " << num_objects_expected[i]
341
#ifdef HAVE_BOOST_RANDOM_DISCRETE_DISTRIBUTION
342
<< "\t" << " X^2 " << ": " << deviceTestChi[i]
343
<< "\t" << " critical X^2 (5% confidence) " << ": " << batch_chi_statistic_five_percent
344
<< "\t" << " (1% confidence) " << ": " << batch_chi_statistic_one_percent
350
#ifdef HAVE_BOOST_RANDOM_DISCRETE_DISTRIBUTION
351
err << " chi squared = " << test_chi_statistic
352
<< " (vs " << chi_statistic_five_percent << " / "
353
<< chi_statistic_one_percent
354
<< " for 5% / 1% confidence level) " << std::endl;
355
if (output_utilization || output_utilization_all)
356
err << " total system weight (dec) = " << (total_weight / (float) 0x10000) << std::endl;
358
if (num_batches > 1 && output_statistics) {
359
err << " " << num_devices_failing_at_five_percent << "/" << num_devices_active << " ("
360
<< (100.0*((float) num_devices_failing_at_five_percent / (float) num_devices_active))
361
<< "%) devices failed testing at 5% confidence level" << std::endl;
362
err << " " << num_devices_failing_at_one_percent << "/" << num_devices_active << " ("
363
<< (100.0*((float) num_devices_failing_at_one_percent / (float) num_devices_active))
364
<< "%) devices failed testing at 1% confidence level" << std::endl;
370
if (output_choose_tries) {
372
int n = crush.get_choose_profile(&v);
373
for (int i=0; i<n; i++) {
374
cout.setf(std::ios::right);
376
<< i << ": " << std::setw(9) << v[i];
377
cout.unsetf(std::ios::right);
381
crush.stop_choose_profile();