EXTRA_CFLAGS = #-I${HOME}/include -L${HOME}/lib
EXTRA_CFLAGS += -g
EXTRA_CFLAGS += -pg
-EXTRA_CFLAGS += -O3
+#EXTRA_CFLAGS += -O3
# base
CFLAGS = -Wall -I. -D_FILE_OFFSET_BITS=64 -D_REENTRANT -D_THREAD_SAFE ${EXTRA_CFLAGS}
extractosdmaps: extractosdmaps.cc common.o osd.o mon.o ebofs.o
${CC} ${CFLAGS} ${LIBS} $^ -o $@
-cmon: cmon.o mon.o msg/SimpleMessenger.o common.o
+cmon: cmon.o mon.o msg/SimpleMessenger.o common.o crush/libcrush.o
${CC} ${CFLAGS} ${LIBS} $^ -o $@
cmonctl: cmonctl.cc msg/SimpleMessenger.o common.o
${CC} ${CFLAGS} ${LIBS} $^ -o $@
-cosd: cosd.o osd.o ebofs.o msg/SimpleMessenger.o common.o
+cosd: cosd.o osd.o ebofs.o msg/SimpleMessenger.o common.o crush/libcrush.o
${CC} ${CFLAGS} ${LIBS} $^ -o $@
-cmds: cmds.o mds.o osdc.o msg/SimpleMessenger.o common.o
+cmds: cmds.o mds.o osdc.o msg/SimpleMessenger.o common.o crush/libcrush.o
${CC} ${CFLAGS} ${LIBS} $^ -o $@
-csyn: csyn.o client.o osdc.o msg/SimpleMessenger.o common.o
+csyn: csyn.o client.o osdc.o msg/SimpleMessenger.o common.o crush/libcrush.o
${CC} ${CFLAGS} ${LIBS} $^ -o $@
-cfuse: cfuse.o client.o osdc.o client/fuse.o client/fuse_ll.o msg/SimpleMessenger.o common.o
+cfuse: cfuse.o client.o osdc.o client/fuse.o client/fuse_ll.o msg/SimpleMessenger.o common.o crush/libcrush.o
${CC} ${CFLAGS} ${LIBS} -lfuse $^ -o $@
# fake*
-fakefuse: fakefuse.o mon.o mds.o client.o osd.o osdc.o ebofs.o client/fuse.o client/fuse_ll.o msg/FakeMessenger.o common.o
+fakefuse: fakefuse.o mon.o mds.o client.o osd.o osdc.o ebofs.o client/fuse.o client/fuse_ll.o msg/FakeMessenger.o common.o crush/libcrush.o
${CC} ${CFLAGS} ${LIBS} -lfuse $^ -o $@
-fakesyn: fakesyn.o mon.o mds.o client.o osd.o ebofs.o osdc.o msg/FakeMessenger.o common.o
+fakesyn: fakesyn.o mon.o mds.o client.o osd.o ebofs.o osdc.o msg/FakeMessenger.o common.o crush/libcrush.o
${CC} ${CFLAGS} ${LIBS} $^ -o $@
# mpi startup
-newsyn: newsyn.cc mon.o mds.o client.o osd.o ebofs.o osdc.o msg/SimpleMessenger.o common.o
+newsyn: newsyn.cc mon.o mds.o client.o osd.o ebofs.o osdc.o msg/SimpleMessenger.o common.o crush/libcrush.o
${MPICC} ${MPICFLAGS} ${MPILIBS} $^ -o $@
test_disk_bw: test/test_disk_bw.cc common.o
${CC} ${CFLAGS} ${LIBS} $^ -o $@
+# crush
+
+crush/libcrush.o: force_look
+ cd crush ; make
+
+force_look:
+ true
+
# bits
common.o: ${COMMON_OBJS}
${LDINC} $@ $^
osbdb.o: ${OSBDB_OBJS}
${LDINC} $@ $^
-
# generic rules
%.so: %.cc
${CC} -shared -fPIC ${CFLAGS} $< -o $@
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#ifndef __crush_BINARYTREE_H
+#define __crush_BINARYTREE_H
+
+#include <cassert>
+#include <iostream>
+#include <map>
+#include <vector>
+using std::map;
+using std::vector;
+
+#include "include/buffer.h"
+
+namespace crush {
+
+ class BinaryTree {
+ private:
+ // tree def
+ int root_node; // 0 for empty tree.
+ int alloc;
+ vector<int> node_nested; // all existing nodes in this map
+ vector<float> node_weight; // and this one
+ vector<int> node_complete; // only nodes with all possible children
+
+ public:
+ BinaryTree() : root_node(0), alloc(0) {}
+
+ void _encode(bufferlist& bl) {
+ bl.append((char*)&root_node, sizeof(root_node));
+ bl.append((char*)&alloc, sizeof(alloc));
+ ::_encode(node_nested, bl);
+ ::_encode(node_weight, bl);
+ ::_encode(node_complete, bl);
+ }
+ void _decode(bufferlist& bl, int& off) {
+ bl.copy(off, sizeof(root_node), (char*)&root_node);
+ off += sizeof(root_node);
+ bl.copy(off, sizeof(alloc), (char*)&alloc);
+ off += sizeof(alloc);
+ ::_decode(node_nested, bl, off);
+ ::_decode(node_weight, bl, off);
+ ::_decode(node_complete, bl, off);
+ }
+
+ // accessors
+ bool empty() const { return root_node == 0; }
+ bool exists(int n) const { return n < alloc && node_nested[n]; }
+ int nested(int n) const { return exists(n) ? node_nested[n]:0; }
+ float weight(int n) const { return exists(n) ? node_weight[n]:0; }
+ bool complete(int n) const { return exists(n) ? node_complete[n]:false; }
+
+ int root() const { return root_node; }
+
+ void realloc(int n) {
+ /*
+ while (alloc <= n) {
+ node_nested.push_back(0);
+ node_weight.push_back(0);
+ node_complete.push_back(0);
+ alloc++;
+ }
+ */
+ if (alloc <= n) {
+ int add = n - alloc + 1;
+ node_nested.insert(node_nested.end(), add, 0);
+ node_weight.insert(node_weight.end(), add, 0);
+ node_complete.insert(node_complete.end(), add, 0);
+ alloc = n+1;
+ }
+ }
+
+ // tree navigation
+ bool terminal(int n) const { return n & 1; } // odd nodes are leaves.
+ int height(int n) const {
+ assert(n);
+ int h = 0;
+ while ((n & 1) == 0) {
+ assert(n > 0);
+ h++; n = n >> 1;
+ }
+ return h;
+ }
+ int left(int n) const {
+ int h = height(n);
+ //cout << "left of " << n << " is " << (n - (1 << h)) << std::endl;
+ return n - (1 << (h-1));
+ }
+ int right(int n) const {
+ int h = height(n);
+ //cout << "right of " << n << " is " << (n + (1 << h)) << std::endl;
+ return n + (1 << (h-1));
+ }
+ bool on_right(int n, int h = -1) const {
+ if (h < 0) h = height(n);
+ return n & (1 << (h+1));
+ }
+ bool on_left(int n) const { return !on_right(n); }
+ int parent(int n) const {
+ int h = height(n);
+ if (on_right(n, h))
+ return n - (1<<h);
+ else
+ return n + (1<<h);
+ }
+
+ // modifiers
+ void adjust_node_weight(int n, float w) {
+ assert(exists(n));
+ node_weight[n] += w;
+
+ int p = n;
+ while (p != root_node) {
+ p = parent(p);
+ node_weight[p] += w;
+ }
+ }
+
+ void remove_node(int n) {
+ assert(exists(n));
+
+ // erase node
+ node_nested[n] = 0;
+ node_weight[n] = 0;
+
+ // adjust parents (!complete, -weight)
+ int p = n;
+ while (p != root_node) {
+ p = parent(p);
+
+ node_complete[p] = 0;
+ node_weight[p] = weight(left(p)) + weight(right(p));
+ node_nested[p]--;
+
+ if (nested(p) == 0) {
+ node_weight[p] = 0;
+ node_nested[p] = 0;
+ }
+ }
+
+ // hose root?
+ while (!terminal(root_node) &&
+ (nested(left(root_node)) == 0 ||
+ nested(right(root_node)) == 0)) {
+ // root now one child..
+ node_weight[root_node] = 0;
+ node_nested[root_node] = 0;
+ if (nested(left(root_node)) == 0)
+ root_node = right(root_node);
+ else
+ root_node = left(root_node);
+ }
+
+ if (terminal(root_node) &&
+ nested(root_node) == 0) {
+ // empty!
+ node_weight[root_node] = 0;
+ node_nested[root_node] = 0;
+ root_node = 0;
+ }
+
+ }
+
+ int add_node_root(float w) {
+ return add_node(w, true);
+ }
+
+ int add_node(float w, bool force_root=false) {
+ int n;
+ if (!root_node) {
+ // empty tree!
+ root_node = n = 1;
+ } else {
+ // existing tree.
+ // expand tree?
+ if (force_root || complete(root_node)) {
+ // add new root
+ int newroot = parent(root_node);
+ realloc(newroot);
+ node_weight[newroot] = node_weight[root_node];
+ node_nested[newroot] = nested(root_node);
+
+ // go right or left?
+ if (left(newroot) == root_node)
+ n = right(newroot);
+ else
+ n = left(newroot);
+ root_node = newroot;
+
+ // then go left until terminal
+ while (!terminal(n))
+ n = left(n);
+ }
+ else {
+ // tree isn't complete.
+ n = root_node;
+ while (!terminal(n)) {
+ if (!exists(left(n)) || !complete(left(n))) {
+ // left isn't complete
+ n = left(n);
+ } else {
+ assert(!exists(right(n)) || !complete(right(n)));
+ // right isn't complete
+ n = right(n);
+ }
+ }
+ }
+ }
+
+ // create at n
+ //cout << "creating " << n << std::endl;
+ realloc(n);
+ node_weight[n] = w;
+ node_nested[n] = 1;
+ node_complete[n] = 1;
+
+ // ancestors: create, adjust weight, complete as appropriate
+ int p = n;
+ while (p != root_node) {
+ p = parent(p);
+ realloc(p);
+
+ // complete?
+ if (!complete(p) &&
+ complete(left(p)) &&
+ complete(right(p)))
+ node_complete[p] = 1;
+
+ // weight (and implicitly create)
+ node_weight[p] += w;
+ node_nested[p]++;
+ }
+
+ return n;
+
+ }
+
+
+ };
+
+
+ // print it out
+ inline void print_binary_tree_node(ostream& out, const BinaryTree& tree, int n, int i) {
+ for (int t=i; t>0; t--) out << " ";
+ if (tree.root() == n)
+ out << "root ";
+ else {
+ if (tree.on_left(n))
+ out << "left ";
+ else
+ out << "right ";
+ }
+ out << n << " : nested " << tree.nested(n) << " weight " << tree.weight(n);
+ if (tree.complete(n)) out << " complete";
+ out << std::endl;
+ if (!tree.terminal(n)) {
+ if (tree.exists(tree.left(n)))
+ print_binary_tree_node(out, tree, tree.left(n), i+2);
+ if (tree.exists(tree.right(n)))
+ print_binary_tree_node(out, tree, tree.right(n), i+2);
+ }
+ }
+
+ inline ostream& operator<<(ostream& out, const BinaryTree& tree) {
+ if (tree.empty())
+ return out << "tree is empty";
+ print_binary_tree_node(out, tree, tree.root(), 0);
+ return out;
+ }
+
+}
+
+#endif
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#ifndef __crush_BUCKET_H
+#define __crush_BUCKET_H
+
+#include "BinaryTree.h"
+#include "Hash.h"
+
+#include <list>
+#include <vector>
+#include <map>
+#include <set>
+using namespace std;
+
+#include <math.h>
+
+#include "include/buffer.h"
+
+namespace crush {
+
+
+ const int CRUSH_BUCKET_UNIFORM = 1;
+ const int CRUSH_BUCKET_TREE = 2;
+ const int CRUSH_BUCKET_LIST = 3;
+ const int CRUSH_BUCKET_STRAW = 4;
+
+ /** abstract bucket **/
+ class Bucket {
+ protected:
+ int id;
+ int parent;
+ int type;
+ float weight;
+
+ public:
+ Bucket(int _type,
+ float _weight) :
+ id(0), parent(0),
+ type(_type),
+ weight(_weight) { }
+
+ Bucket(bufferlist& bl, int& off) {
+ bl.copy(off, sizeof(id), (char*)&id);
+ off += sizeof(id);
+ bl.copy(off, sizeof(parent), (char*)&parent);
+ off += sizeof(parent);
+ bl.copy(off, sizeof(type), (char*)&type);
+ off += sizeof(type);
+ bl.copy(off, sizeof(weight), (char*)&weight);
+ off += sizeof(weight);
+ }
+
+ virtual ~Bucket() { }
+
+ virtual const char *get_bucket_type() const = 0;
+ virtual bool is_uniform() const = 0;
+
+ int get_id() const { return id; }
+ int get_type() const { return type; }
+ float get_weight() const { return weight; }
+ int get_parent() const { return parent; }
+ virtual int get_size() const = 0;
+
+ void set_id(int i) { id = i; }
+ void set_parent(int p) { parent = p; }
+ void set_weight(float w) { weight = w; }
+
+ virtual void get_items(vector<int>& i) const = 0;
+ virtual float get_item_weight(int item) const = 0;
+ virtual void add_item(int item, float w, bool back=false) = 0;
+ virtual void adjust_item_weight(int item, float w) = 0;
+ virtual void set_item_weight(int item, float w) {
+ adjust_item_weight(item, w - get_item_weight(item));
+ }
+
+ virtual int choose_r(int x, int r, Hash& h) const = 0;
+
+ virtual void _encode(bufferlist& bl) = 0;
+ };
+
+
+
+
+ /** uniform bucket **/
+ class UniformBucket : public Bucket {
+ protected:
+ public:
+ vector<int> items;
+ int item_type;
+ float item_weight;
+
+ // primes
+ vector<unsigned> primes;
+
+ int get_prime(int j) const {
+ return primes[ j % primes.size() ];
+ }
+ void make_primes() {
+ if (items.empty()) return;
+
+ //cout << "make_primes " << get_id() << " " << items.size() << endl;
+ Hash h(123+get_id());
+ primes.clear();
+
+ // start with odd number > num_items
+ unsigned x = items.size() + 1; // this is the minimum!
+ x += h(items.size()) % (3*items.size()); // bump it up some
+ x |= 1; // make it odd
+
+ while (primes.size() < items.size()) {
+ unsigned j;
+ for (j=2; j*j<=x; j++)
+ if (x % j == 0) break;
+ if (j*j > x) {
+ primes.push_back(x);
+ //cout << "prime " << x << endl;
+ }
+ x += 2;
+ }
+ }
+
+ public:
+ UniformBucket(int _type, int _item_type) :
+ Bucket(_type, 0),
+ item_type(_item_type) { }
+ UniformBucket(int _type, int _item_type,
+ float _item_weight, vector<int>& _items) :
+ Bucket(_type, _item_weight*_items.size()),
+ item_type(_item_type),
+ item_weight(_item_weight) {
+ items = _items;
+ make_primes();
+ }
+
+ UniformBucket(bufferlist& bl, int& off) : Bucket(bl, off) {
+ bl.copy(off, sizeof(item_type), (char*)&item_type);
+ off += sizeof(item_type);
+ bl.copy(off, sizeof(item_weight), (char*)&item_weight);
+ off += sizeof(item_weight);
+ ::_decode(items, bl, off);
+ make_primes();
+ }
+
+ void _encode(bufferlist& bl) {
+ char t = CRUSH_BUCKET_UNIFORM;
+ bl.append((char*)&t, sizeof(t));
+ bl.append((char*)&id, sizeof(id));
+ bl.append((char*)&parent, sizeof(parent));
+ bl.append((char*)&type, sizeof(type));
+ bl.append((char*)&weight, sizeof(weight));
+
+ bl.append((char*)&item_type, sizeof(item_type));
+ bl.append((char*)&item_weight, sizeof(item_weight));
+
+ ::_encode(items, bl);
+ }
+
+ const char *get_bucket_type() const { return "uniform"; }
+ bool is_uniform() const { return true; }
+
+ int get_size() const { return items.size(); }
+
+ // items
+ void get_items(vector<int>& i) const {
+ i = items;
+ }
+ int get_item_type() const { return item_type; }
+ float get_item_weight(int item) const { return item_weight; }
+
+ void add_item(int item, float w, bool back=false) {
+ if (items.empty())
+ item_weight = w;
+ items.push_back(item);
+ weight += item_weight;
+ make_primes();
+ }
+
+ void adjust_item_weight(int item, float w) {
+ assert(0);
+ }
+
+ int choose_r(int x, int r, Hash& hash) const {
+ //cout << "uniformbucket.choose_r(" << x << ", " << r << ")" << endl;
+ //if (r >= get_size()) cout << "warning: r " << r << " >= " << get_size() << " uniformbucket.size" << endl;
+
+ unsigned v = hash(x, get_id());// % get_size();
+ unsigned p = get_prime( hash(get_id(), x) ); // choose a prime based on hash(x, get_id(), 2)
+ unsigned s = (x + v + (r+1)*p) % get_size();
+ return items[s];
+ }
+
+ };
+
+
+
+
+
+ // list bucket.. RUSH_P sorta
+
+ class ListBucket : public Bucket {
+ protected:
+ list<int> items;
+ list<float> item_weight;
+ list<float> sum_weight;
+
+ public:
+ ListBucket(int _type) : Bucket(_type, 0) { }
+
+ ListBucket(bufferlist& bl, int& off) : Bucket(bl, off) {
+ ::_decode(items, bl, off);
+ ::_decode(item_weight, bl, off);
+ ::_decode(sum_weight, bl, off);
+ }
+
+ void _encode(bufferlist& bl) {
+ char t = CRUSH_BUCKET_LIST;
+ bl.append((char*)&t, sizeof(t));
+ bl.append((char*)&id, sizeof(id));
+ bl.append((char*)&parent, sizeof(parent));
+ bl.append((char*)&type, sizeof(type));
+ bl.append((char*)&weight, sizeof(weight));
+
+ ::_encode(items, bl);
+ ::_encode(item_weight, bl);
+ ::_encode(sum_weight, bl);
+ }
+
+ const char *get_bucket_type() const { return "list"; }
+ bool is_uniform() const { return false; }
+
+ int get_size() const { return items.size(); }
+
+ void get_items(vector<int>& i) const {
+ for (list<int>::const_iterator it = items.begin();
+ it != items.end();
+ it++)
+ i.push_back(*it);
+ }
+ float get_item_weight(int item) const {
+ list<int>::const_iterator i = items.begin();
+ list<float>::const_iterator w = item_weight.begin();
+ while (i != items.end()) {
+ if (*i == item) return *w;
+ i++; w++;
+ }
+ assert(0);
+ return 0;
+ }
+
+ void add_item(int item, float w, bool back=false) {
+ if (back) {
+ items.push_back(item);
+ item_weight.push_back(w);
+ sum_weight.clear();
+ float s = 0.0;
+ for (list<float>::reverse_iterator i = item_weight.rbegin();
+ i != item_weight.rend();
+ i++) {
+ s += *i;
+ sum_weight.push_front(s);
+ }
+ weight += w;
+ assert(weight == s);
+ } else {
+ items.push_front(item);
+ item_weight.push_front(w);
+ weight += w;
+ sum_weight.push_front(weight);
+ }
+ }
+
+ void adjust_item_weight(int item, float dw) {
+ // find it
+ list<int>::iterator p = items.begin();
+ list<float>::iterator pw = item_weight.begin();
+ list<float>::iterator ps = sum_weight.begin();
+
+ while (*p != item) {
+ *ps += dw;
+ p++; pw++; ps++; // next!
+ assert(p != items.end());
+ }
+
+ assert(*p == item);
+ *pw += dw;
+ *ps += dw;
+ }
+
+
+ int choose_r(int x, int r, Hash& h) const {
+ //cout << "linearbucket.choose_r(" << x << ", " << r << ")" << endl;
+
+ list<int>::const_iterator p = items.begin();
+ list<float>::const_iterator pw = item_weight.begin();
+ list<float>::const_iterator ps = sum_weight.begin();
+
+ while (p != items.end()) {
+ const int item = *p;
+ const float iw = *pw;
+ const float tw = *ps;
+ const float f = (float)(h(x, item, r, get_id()) % 10000) * tw / 10000.0;
+ //cout << "item " << item << " iw = " << iw << " tw = " << tw << " f = " << f << endl;
+ if (f < iw) {
+ //cout << "linearbucket.choose_r(" << x << ", " << r << ") = " << item << endl;
+ return item;
+ }
+ p++; pw++; ps++; // next!
+ }
+ assert(0);
+ return 0;
+ }
+
+
+ };
+
+
+
+
+ // mixed bucket, based on RUSH_T type binary tree
+
+ class TreeBucket : public Bucket {
+ protected:
+ //vector<float> item_weight;
+
+ // public:
+ BinaryTree tree;
+ map<int,int> node_item; // node id -> item
+ vector<int> node_item_vec; // fast version of above
+ map<int,int> item_node; // item -> node id
+ map<int,float> item_weight;
+
+ public:
+ TreeBucket(int _type) : Bucket(_type, 0) { }
+
+ TreeBucket(bufferlist& bl, int& off) : Bucket(bl, off) {
+ tree._decode(bl, off);
+
+ ::_decode(node_item, bl, off);
+ ::_decode(node_item_vec, bl, off);
+ ::_decode(item_node, bl, off);
+ ::_decode(item_weight, bl, off);
+ }
+
+ void _encode(bufferlist& bl) {
+ char t = CRUSH_BUCKET_TREE;
+ bl.append((char*)&t, sizeof(t));
+ bl.append((char*)&id, sizeof(id));
+ bl.append((char*)&parent, sizeof(parent));
+ bl.append((char*)&type, sizeof(type));
+ bl.append((char*)&weight, sizeof(weight));
+
+ tree._encode(bl);
+
+ ::_encode(node_item, bl);
+ ::_encode(node_item_vec, bl);
+ ::_encode(item_node, bl);
+ ::_encode(item_weight, bl);
+ }
+
+ const char *get_bucket_type() const { return "tree"; }
+ bool is_uniform() const { return false; }
+
+ int get_size() const { return node_item.size(); }
+
+ // items
+ void get_items(vector<int>& i) const {
+ for (map<int,int>::const_iterator it = node_item.begin();
+ it != node_item.end();
+ it++)
+ i.push_back(it->second);
+ }
+ float get_item_weight(int i) const {
+ assert(item_weight.count(i));
+ return ((map<int,float>)item_weight)[i];
+ }
+
+
+ void add_item(int item, float w, bool back=false) {
+ item_weight[item] = w;
+ weight += w;
+
+ unsigned n = tree.add_node(w);
+ node_item[n] = item;
+ item_node[item] = n;
+
+ while (node_item_vec.size() <= n)
+ node_item_vec.push_back(0);
+ node_item_vec[n] = item;
+ }
+
+ void adjust_item_weight(int item, float dw) {
+ // adjust my weight
+ weight += dw;
+ item_weight[item] += dw;
+
+ // adjust tree weights
+ tree.adjust_node_weight(item_node[item], dw);
+ }
+
+ int choose_r(int x, int r, Hash& h) const {
+ //cout << "mixedbucket.choose_r(" << x << ", " << r << ")" << endl;
+ int n = tree.root();
+ while (!tree.terminal(n)) {
+ // pick a point in [0,w)
+ float w = tree.weight(n);
+ float f = (float)(h(x, n, r, get_id()) % 10000) * w / 10000.0;
+
+ // left or right?
+ int l = tree.left(n);
+ if (tree.exists(l) &&
+ f < tree.weight(l))
+ n = l;
+ else
+ n = tree.right(n);
+ }
+ //assert(node_item.count(n));
+ //return ((map<int,int>)node_item)[n];
+ return node_item_vec[n];
+ }
+ };
+
+
+
+
+
+ // straw bucket.. new thing!
+
+ class StrawBucket : public Bucket {
+ protected:
+ map<int, float> item_weight;
+ map<int, float> item_straw;
+
+ list<int> _items;
+ list<float> _straws;
+
+ public:
+ StrawBucket(int _type) : Bucket(_type, 0) { }
+
+ StrawBucket(bufferlist& bl, int& off) : Bucket(bl, off) {
+ ::_decode(item_weight, bl, off);
+ calc_straws();
+ }
+
+ void _encode(bufferlist& bl) {
+ char t = CRUSH_BUCKET_TREE;
+ bl.append((char*)&t, sizeof(t));
+ bl.append((char*)&id, sizeof(id));
+ bl.append((char*)&parent, sizeof(parent));
+ bl.append((char*)&type, sizeof(type));
+ bl.append((char*)&weight, sizeof(weight));
+
+ ::_encode(item_weight, bl);
+ }
+
+ const char *get_bucket_type() const { return "straw"; }
+ bool is_uniform() const { return false; }
+
+ int get_size() const { return item_weight.size(); }
+
+
+ // items
+ void get_items(vector<int>& i) const {
+ for (map<int,float>::const_iterator it = item_weight.begin();
+ it != item_weight.end();
+ it++)
+ i.push_back(it->first);
+ }
+ float get_item_weight(int item) const {
+ assert(item_weight.count(item));
+ return ((map<int,float>)item_weight)[item];
+ }
+
+ void add_item(int item, float w, bool back=false) {
+ item_weight[item] = w;
+ weight += w;
+ calc_straws();
+ }
+
+ void adjust_item_weight(int item, float dw) {
+ //cout << "adjust " << item << " " << dw << endl;
+ weight += dw;
+ item_weight[item] += dw;
+ calc_straws();
+ }
+
+
+ /* calculate straw lengths.
+ this is kind of ugly. not sure if there's a closed form way to calculate this or not!
+ */
+ void calc_straws() {
+ //cout << get_id() << ": calc_straws ============" << endl;
+
+ item_straw.clear();
+ _items.clear();
+ _straws.clear();
+
+ // reverse sort by weight; skip zero weight items
+ map<float, set<int> > reverse;
+ for (map<int, float>::iterator p = item_weight.begin();
+ p != item_weight.end();
+ p++) {
+ //cout << get_id() << ":" << p->first << " " << p->second << endl;
+ if (p->second > 0) {
+ //p->second /= minw;
+ reverse[p->second].insert(p->first);
+ }
+ }
+
+ /* 1:2:7
+ item_straw[0] = 1.0;
+ item_straw[1] = item_straw[0]*sqrt(1.0/.6);
+ item_straw[2] = item_straw[1]*2.0;
+ */
+
+ // work from low to high weights
+ float straw = 1.0;
+ float numleft = item_weight.size();
+ float wbelow = 0.0;
+ float lastw = 0.0;
+
+ map<float, set<int> >::iterator next = reverse.begin();
+ //while (next != reverse.end()) {
+ while (1) {
+ //cout << "hi " << next->first << endl;
+ map<float, set<int> >::iterator cur = next;
+
+ // set straw length for this set
+ for (set<int>::iterator s = cur->second.begin();
+ s != cur->second.end();
+ s++) {
+ item_straw[*s] = straw;
+ //cout << "straw " << *s << " w " << item_weight[*s] << " -> " << straw << endl;
+ _items.push_back(*s);
+ _straws.push_back(straw);
+ }
+
+ next++;
+ if (next == reverse.end()) break;
+
+ wbelow += (cur->first-lastw) * numleft;
+ //cout << "wbelow " << wbelow << endl;
+
+ numleft -= 1.0 * (float)cur->second.size();
+ //cout << "numleft now " << numleft << endl;
+
+ float wnext = numleft * (next->first - cur->first);
+ //cout << "wnext " << wnext << endl;
+
+ float pbelow = wbelow / (wbelow+wnext);
+ //cout << "pbelow " << pbelow << endl;
+
+ straw *= pow((double)(1.0/pbelow), (double)1.0/numleft);
+
+ lastw = cur->first;
+ }
+ //cout << "============" << endl;
+ }
+
+ int choose_r(int x, int r, Hash& h) const {
+ //cout << "strawbucket.choose_r(" << x << ", " << r << ")" << endl;
+
+ float high_draw = -1;
+ int high = 0;
+
+ list<int>::const_iterator pi = _items.begin();
+ list<float>::const_iterator ps = _straws.begin();
+ while (pi != _items.end()) {
+ const int item = *pi;
+ const float rnd = (float)(h(x, item, r) % 1000000) / 1000000.0;
+ const float straw = *ps * rnd;
+
+ if (high_draw < 0 ||
+ straw > high_draw) {
+ high = *pi;
+ high_draw = straw;
+ }
+
+ pi++;
+ ps++;
+ }
+ return high;
+ }
+ };
+
+
+
+
+
+ inline Bucket* decode_bucket(bufferlist& bl, int& off) {
+ char t;
+ bl.copy(off, sizeof(t), (char*)&t);
+ off += sizeof(t);
+
+ switch (t) {
+ case CRUSH_BUCKET_UNIFORM:
+ return new UniformBucket(bl, off);
+ case CRUSH_BUCKET_LIST:
+ return new ListBucket(bl, off);
+ case CRUSH_BUCKET_TREE:
+ return new TreeBucket(bl, off);
+ case CRUSH_BUCKET_STRAW:
+ return new StrawBucket(bl, off);
+ default:
+ assert(0);
+ }
+ return 0;
+ }
+
+
+
+}
+
+
+
+
+
+
+
+
+#endif
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+
+// Robert Jenkins' function for mixing 32-bit values
+// http://burtleburtle.net/bob/hash/evahash.html
+// a, b = random bits, c = input and output
+#define hashmix(a,b,c) \
+ a=a-b; a=a-c; a=a^(c>>13); \
+ b=b-c; b=b-a; b=b^(a<<8); \
+ c=c-a; c=c-b; c=c^(b>>13); \
+ a=a-b; a=a-c; a=a^(c>>12); \
+ b=b-c; b=b-a; b=b^(a<<16); \
+ c=c-a; c=c-b; c=c^(b>>5); \
+ a=a-b; a=a-c; a=a^(c>>3); \
+ b=b-c; b=b-a; b=b^(a<<10); \
+ c=c-a; c=c-b; c=c^(b>>15);
+
+namespace crush {
+
+ class Hash {
+ int seed;
+
+ public:
+ int get_seed() { return seed; }
+ void set_seed(int s) { seed = s; }
+
+ Hash(int s) {
+ unsigned int hash = 1315423911;
+ int x = 231232;
+ int y = 1232;
+ hashmix(s, x, hash);
+ hashmix(y, s, hash);
+ seed = s;
+ }
+
+ inline int operator()(int a) {
+ unsigned int hash = seed ^ a;
+ int b = a;
+ int x = 231232;
+ int y = 1232;
+ hashmix(b, x, hash);
+ hashmix(y, a, hash);
+ return (hash & 0x7FFFFFFF);
+ }
+
+ inline int operator()(int a, int b) {
+ unsigned int hash = seed ^ a ^ b;
+ int x = 231232;
+ int y = 1232;
+ hashmix(a, b, hash);
+ hashmix(x, a, hash);
+ hashmix(b, y, hash);
+ return (hash & 0x7FFFFFFF);
+ }
+
+ inline int operator()(int a, int b, int c) {
+ unsigned int hash = seed ^ a ^ b ^ c;
+ int x = 231232;
+ int y = 1232;
+ hashmix(a, b, hash);
+ hashmix(c, x, hash);
+ hashmix(y, a, hash);
+ hashmix(b, x, hash);
+ hashmix(y, c, hash);
+ return (hash & 0x7FFFFFFF);
+ }
+
+ inline int operator()(int a, int b, int c, int d) {
+ unsigned int hash = seed ^a ^ b ^ c ^ d;
+ int x = 231232;
+ int y = 1232;
+ hashmix(a, b, hash);
+ hashmix(c, d, hash);
+ hashmix(a, x, hash);
+ hashmix(y, b, hash);
+ hashmix(c, x, hash);
+ hashmix(y, d, hash);
+ return (hash & 0x7FFFFFFF);
+ }
+
+ inline int operator()(int a, int b, int c, int d, int e) {
+ unsigned int hash = seed ^ a ^ b ^ c ^ d ^ e;
+ int x = 231232;
+ int y = 1232;
+ hashmix(a, b, hash);
+ hashmix(c, d, hash);
+ hashmix(e, x, hash);
+ hashmix(y, a, hash);
+ hashmix(b, x, hash);
+ hashmix(y, c, hash);
+ hashmix(d, x, hash);
+ hashmix(y, e, hash);
+ return (hash & 0x7FFFFFFF);
+ }
+ };
+
+}
+
+
+
+#if 0
+
+
+ //return myhash(a) ^ seed;
+ return myhash(a, seed);
+ }
+ int operator()(int a, int b) {
+ //return myhash( myhash(a) ^ myhash(b) ^ seed );
+ return myhash(a, b, seed);
+ }
+ int operator()(int a, int b, int c) {
+ //return myhash( myhash(a ^ seed) ^ myhash(b ^ seed) ^ myhash(c ^ seed) ^ seed );
+ return myhash(a, b, c, seed);
+ }
+ int operator()(int a, int b, int c, int d) {
+ //return myhash( myhash(a ^ seed) ^ myhash(b ^ seed) ^ myhash(c ^ seed) ^ myhash(d ^ seed) ^ seed );
+ return myhash(a, b, c, d, seed);
+ }
+
+ // ethan's rush hash?
+ if (0)
+ return (n ^ 0xdead1234) * (884811920 * 3 + 1);
+
+ if (1) {
+
+ // before
+ hash ^= ((hash << 5) + (n&255) + (hash >> 2));
+ hashmix(a, b, hash);
+ n = n >> 8;
+ hash ^= ((hash << 5) + (n&255) + (hash >> 2));
+ hashmix(a, b, hash);
+ n = n >> 8;
+ hash ^= ((hash << 5) + (n&255) + (hash >> 2));
+ hashmix(a, b, hash);
+ n = n >> 8;
+ hash ^= ((hash << 5) + (n&255) + (hash >> 2));
+ hashmix(a, b, hash);
+ n = n >> 8;
+
+ //return hash;
+ return (hash & 0x7FFFFFFF);
+ }
+
+ // JS
+ // a little better than RS
+ // + jenkin's mixing thing (which sucks on its own but helps tons here)
+ // best so far
+ if (1) {
+ unsigned int hash = 1315423911;
+ int a = 231232;
+ int b = 1232;
+
+ for(unsigned int i = 0; i < 4; i++)
+ {
+ hash ^= ((hash << 5) + (n&255) + (hash >> 2));
+ hashmix(a, b, hash);
+ n = n >> 8;
+ }
+
+ return (hash & 0x7FFFFFFF);
+ }
+
+
+ // Robert jenkins' 96 bit mix
+ // sucks
+ if (0) {
+ int c = n;
+ int a = 12378912;
+ int b = 2982827;
+ a=a-b; a=a-c; a=a^(c>>13);
+ b=b-c; b=b-a; b=b^(a<<8);
+ c=c-a; c=c-b; c=c^(b>>13);
+ a=a-b; a=a-c; a=a^(c>>12);
+ b=b-c; b=b-a; b=b^(a<<16);
+ c=c-a; c=c-b; c=c^(b>>5);
+ a=a-b; a=a-c; a=a^(c>>3);
+ b=b-c; b=b-a; b=b^(a<<10);
+ c=c-a; c=c-b; c=c^(b>>15);
+ return c;
+ }
+ // robert jenkins 32-bit
+ // sucks
+ if (0) {
+ n += (n << 12);
+ n ^= (n >> 22);
+ n += (n << 4);
+ n ^= (n >> 9);
+ n += (n << 10);
+ n ^= (n >> 2);
+ n += (n << 7);
+ n ^= (n >> 12);
+ return n;
+ }
+
+ // djb2
+ if (0) {
+ unsigned int hash = 5381;
+ for (int i=0; i<4; i++) {
+ hash = ((hash << 5) + hash) + ((n&255) ^ 123);
+ n = n >> 8;
+ }
+ return hash;
+ }
+
+
+ // SDBM
+ if (1) {
+ unsigned int hash = 0;
+
+ for(unsigned int i = 0; i < 4; i++)
+ {
+ hash = (n&255) + (hash << 6) + (hash << 16) - hash;
+ n = n >> 8;
+ }
+
+ return (hash & 0x7FFFFFFF);
+ }
+
+ // PJW
+ // horrid
+ if (0) {
+ unsigned int BitsInUnsignedInt = (unsigned int)(sizeof(unsigned int) * 8);
+ unsigned int ThreeQuarters = (unsigned int)((BitsInUnsignedInt * 3) / 4);
+ unsigned int OneEighth = (unsigned int)(BitsInUnsignedInt / 8);
+ unsigned int HighBits = (unsigned int)(0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth);
+ unsigned int hash = 0;
+ unsigned int test = 0;
+
+ for(unsigned int i = 0; i < 4; i++)
+ {
+ hash = (hash << OneEighth) + (n&255);
+
+ if((test = hash & HighBits) != 0)
+ {
+ hash = (( hash ^ (test >> ThreeQuarters)) & (~HighBits));
+ }
+ n = n >> 8;
+ }
+
+ return (hash & 0x7FFFFFFF);
+ }
+
+ // RS Hash function, from Robert Sedgwicks Algorithms in C book, w/ some changes.
+ if (0) {
+ unsigned int b = 378551;
+ unsigned int a = 63689;
+ unsigned int hash = 0;
+
+ for(unsigned int i=0; i<4; i++)
+ {
+ hash = hash * a + (n&0xff);
+ a = a * b;
+ n = n >> 8;
+ }
+
+ return (hash & 0x7FFFFFFF);
+ }
+
+ // DJB
+ // worse than rs
+ if (0) {
+ unsigned int hash = 5381;
+
+ for(unsigned int i = 0; i < 4; i++)
+ {
+ hash = ((hash << 5) + hash) + (n&255);
+ n = n >> 8;
+ }
+
+ return (hash & 0x7FFFFFFF);
+ }
+
+ // AP
+ // even worse
+ if (1) {
+ unsigned int hash = 0;
+
+ for(unsigned int i = 0; i < 4; i++)
+ {
+ hash ^= ((i & 1) == 0) ? ( (hash << 7) ^ (n&255) ^ (hash >> 3)) :
+ (~((hash << 11) ^ (n&255) ^ (hash >> 5)));
+ n = n >> 8;
+ }
+
+ return (hash & 0x7FFFFFFF);
+ }
+
+
+#endif
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#ifndef __crush_CRUSH_H
+#define __crush_CRUSH_H
+
+#include <iostream>
+#include <list>
+#include <vector>
+#include <set>
+#include <map>
+using std::set;
+using std::map;
+using std::vector;
+using std::list;
+#include <ext/hash_map>
+#include <ext/hash_set>
+using namespace __gnu_cxx;
+
+
+#include "Bucket.h"
+
+#include "include/buffer.h"
+
+
+namespace crush {
+
+
+ // *** RULES ***
+
+ class RuleStep {
+ public:
+ int cmd;
+ vector<int> args;
+
+ RuleStep(int c) : cmd(c) {}
+ RuleStep(int c, int a) : cmd(c) {
+ args.push_back(a);
+ }
+ RuleStep(int c, int a, int b) : cmd(c) {
+ args.push_back(a);
+ args.push_back(b);
+ }
+ RuleStep(int o, int a, int b, int c) : cmd(o) {
+ args.push_back(a);
+ args.push_back(b);
+ args.push_back(c);
+ }
+
+ void _encode(bufferlist& bl) {
+ bl.append((char*)&cmd, sizeof(cmd));
+ ::_encode(args, bl);
+ }
+ void _decode(bufferlist& bl, int& off) {
+ bl.copy(off, sizeof(cmd), (char*)&cmd);
+ off += sizeof(cmd);
+ ::_decode(args, bl, off);
+ }
+ };
+
+
+ // Rule operations
+ const int CRUSH_RULE_TAKE = 0;
+ const int CRUSH_RULE_CHOOSE = 1; // first n by default
+ const int CRUSH_RULE_CHOOSE_FIRSTN = 1;
+ const int CRUSH_RULE_CHOOSE_INDEP = 2;
+ const int CRUSH_RULE_EMIT = 3;
+
+ class Rule {
+ public:
+ vector< RuleStep > steps;
+
+ void _encode(bufferlist& bl) {
+ int n = steps.size();
+ bl.append((char*)&n, sizeof(n));
+ for (int i=0; i<n; i++)
+ steps[i]._encode(bl);
+ }
+ void _decode(bufferlist& bl, int& off) {
+ steps.clear();
+ int n;
+ bl.copy(off, sizeof(n), (char*)&n);
+ off += sizeof(n);
+ for (int i=0; i<n; i++) {
+ steps.push_back(RuleStep(0));
+ steps[i]._decode(bl, off);
+ }
+ }
+ };
+
+
+
+
+ // *** CRUSH ***
+
+ class Crush {
+ protected:
+ map<int, Bucket*> buckets;
+ int bucketno;
+ Hash h;
+
+ hash_map<int, int> parent_map; // what bucket each leaf/bucket lives in
+
+ public:
+ map<int, Rule> rules;
+
+ //map<int,int> collisions;
+ //map<int,int> bumps;
+
+ void _encode(bufferlist& bl) {
+ // buckets
+ int n = buckets.size();
+ bl.append((char*)&n, sizeof(n));
+ for (map<int, Bucket*>::const_iterator it = buckets.begin();
+ it != buckets.end();
+ it++) {
+ bl.append((char*)&it->first, sizeof(it->first));
+ it->second->_encode(bl);
+ }
+ bl.append((char*)&bucketno, sizeof(bucketno));
+
+ // hash
+ int s = h.get_seed();
+ bl.append((char*)&s, sizeof(s));
+
+ //::_encode(out, bl);
+ //::_encode(overload, bl);
+
+ // rules
+ n = rules.size();
+ bl.append((char*)&n, sizeof(n));
+ for(map<int, Rule>::iterator it = rules.begin();
+ it != rules.end();
+ it++) {
+ bl.append((char*)&it->first, sizeof(it->first));
+ it->second._encode(bl);
+ }
+
+ }
+
+ void _decode(bufferlist& bl, int& off) {
+ int n;
+ bl.copy(off, sizeof(n), (char*)&n);
+ off += sizeof(n);
+ for (int i=0; i<n; i++) {
+ int bid;
+ bl.copy(off, sizeof(bid), (char*)&bid);
+ off += sizeof(bid);
+ Bucket *b = decode_bucket(bl, off);
+ buckets[bid] = b;
+ }
+ bl.copy(off, sizeof(bucketno), (char*)&bucketno);
+ off += sizeof(bucketno);
+
+ int s;
+ bl.copy(off, sizeof(s), (char*)&s);
+ off += sizeof(s);
+ h.set_seed(s);
+
+ //::_decode(out, bl, off);
+ //::_decode(overload, bl, off);
+
+ // rules
+ bl.copy(off, sizeof(n), (char*)&n);
+ off += sizeof(n);
+ for (int i=0; i<n; i++) {
+ int r;
+ bl.copy(off, sizeof(r), (char*)&r);
+ off += sizeof(r);
+ rules[r]._decode(bl,off);
+ }
+
+ // index
+ build_parent_map();
+ }
+
+ void build_parent_map() {
+ parent_map.clear();
+
+ // index every bucket
+ for (map<int, Bucket*>::iterator bp = buckets.begin();
+ bp != buckets.end();
+ ++bp) {
+ // index bucket items
+ vector<int> items;
+ bp->second->get_items(items);
+ for (vector<int>::iterator ip = items.begin();
+ ip != items.end();
+ ++ip)
+ parent_map[*ip] = bp->first;
+ }
+ }
+
+
+
+ public:
+ Crush(int seed=123) : bucketno(-1), h(seed) {}
+ ~Crush() {
+ // hose buckets
+ for (map<int, Bucket*>::iterator it = buckets.begin();
+ it != buckets.end();
+ it++) {
+ delete it->second;
+ }
+ }
+
+ int print(ostream& out, int root, int indent=0) {
+ for (int i=0; i<indent; i++) out << " ";
+ Bucket *b = buckets[root];
+ assert(b);
+ out << b->get_weight() << "\t" << b->get_id() << "\t";
+ for (int i=0; i<indent; i++) out << " ";
+ out << b->get_bucket_type() << ": ";
+
+ vector<int> items;
+ b->get_items(items);
+
+ if (buckets.count(items[0])) {
+ out << std::endl;
+ for (unsigned i=0; i<items.size(); i++)
+ print(out, items[i], indent+1);
+ } else {
+ out << "[";
+ for (unsigned i=0; i<items.size(); i++) {
+ if (i) out << " ";
+ out << items[i];
+ }
+ out << "]";
+ }
+ return 0;
+ }
+
+
+ int add_bucket( Bucket *b ) {
+ int n = bucketno;
+ bucketno--;
+ b->set_id(n);
+ buckets[n] = b;
+ return n;
+ }
+
+ void add_item(int parent, int item, float w, bool back=false) {
+ // add item
+ assert(!buckets[parent]->is_uniform());
+ Bucket *p = buckets[parent];
+
+ p->add_item(item, w, back);
+
+ // set item's parent
+ Bucket *n = buckets[item];
+ if (n)
+ n->set_parent(parent);
+
+ // update weights
+ while (buckets.count(p->get_parent())) {
+ int child = p->get_id();
+ p = buckets[p->get_parent()];
+ p->adjust_item_weight(child, w);
+ }
+ }
+
+
+ /*
+ this is a hack, fix me! weights should be consistent throughout hierarchy!
+
+ */
+ void set_bucket_weight(int item, float w) {
+ Bucket *b = buckets[item];
+ float adj = w - b->get_weight();
+
+ while (buckets.count(b->get_parent())) {
+ Bucket *p = buckets[b->get_parent()];
+ p->adjust_item_weight(b->get_id(), adj);
+ b = p;
+ }
+ }
+
+
+ /*
+ * choose numrep distinct items of type type
+ */
+ void choose(int x,
+ int numrep,
+ int type,
+ Bucket *inbucket,
+ vector<int>& outvec,
+ bool firstn,
+ set<int>& outset, map<int,float>& overloadmap,
+ bool forcefeed=false,
+ int forcefeedval=-1) {
+ int off = outvec.size();
+
+ // for each replica
+ for (int rep=0; rep<numrep; rep++) {
+ int outv = -1; // my result
+
+ // forcefeed?
+ if (forcefeed) {
+ forcefeed = false;
+ outvec.push_back(forcefeedval);
+ continue;
+ }
+
+ // keep trying until we get a non-out, non-colliding item
+ int ftotal = 0;
+ bool skip_rep = false;
+
+ while (1) {
+ // start with the input bucket
+ Bucket *in = inbucket;
+
+ // choose through intervening buckets
+ int flocal = 0;
+ bool retry_rep = false;
+
+ while (1) {
+ // r may be twiddled to (try to) avoid past collisions
+ int r = rep;
+ if (in->is_uniform()) {
+ // uniform bucket; be careful!
+ if (firstn || numrep >= in->get_size()) {
+ // uniform bucket is too small; just walk thru elements
+ r += ftotal; // r' = r + f_total (first n)
+ } else {
+ // make sure numrep is not a multple of bucket size
+ int add = numrep*flocal; // r' = r + n*f_local
+ if (in->get_size() % numrep == 0) {
+ add += add/in->get_size(); // shift seq once per pass through the bucket
+ }
+ r += add;
+ }
+ } else {
+ // mixed bucket; just make a distinct-ish r sequence
+ if (firstn)
+ r += ftotal; // r' = r + f_total
+ else
+ r += numrep * flocal; // r' = r + n*f_local
+ }
+
+ // choose
+ outv = in->choose_r(x, r, h);
+
+ // did we get the type we want?
+ int itemtype = 0; // 0 is terminal type
+ Bucket *newin = 0; // remember bucket we hit
+ if (in->is_uniform()) {
+ itemtype = ((UniformBucket*)in)->get_item_type();
+ } else {
+ if (buckets.count(outv)) { // another bucket
+ newin = buckets[outv];
+ itemtype = newin->get_type();
+ }
+ }
+ if (itemtype == type) { // this is what we want!
+ // collision?
+ bool collide = false;
+ for (int prep=0; prep<rep; prep++) {
+ if (outvec[off+prep] == outv) {
+ collide = true;
+ break;
+ }
+ }
+
+ // ok choice?
+ bool bad = false;
+ if (type == 0 && outset.count(outv))
+ bad = true;
+ if (overloadmap.count(outv)) {
+ float f = (float)(h(x, outv) % 1000) / 1000.0;
+ if (f > overloadmap[outv])
+ bad = true;
+ }
+
+ if (collide || bad) {
+ ftotal++;
+ flocal++;
+
+ if (collide && flocal < 3)
+ continue; // try locally a few times!
+
+ if (ftotal >= 10) {
+ // ok fine, just ignore dup. FIXME.
+ skip_rep = true;
+ break;
+ }
+
+ retry_rep = true;
+ }
+
+ break; // ok then!
+ }
+
+ // next
+ in = newin;
+ }
+
+ if (retry_rep) continue; // try again
+
+ break;
+ }
+
+ // skip this rep? (e.g. too many collisions, we give up)
+ if (skip_rep) continue;
+
+ // output this value
+ outvec.push_back(outv);
+ } // for rep
+
+ // double check!
+ if (0) {
+ for (unsigned i=1; i<outvec.size(); i++)
+ for (unsigned j=0; j<i; j++)
+ assert(outvec[i] != outvec[j]);
+ }
+ }
+
+
+ void do_rule(Rule& rule, int x, vector<int>& result,
+ set<int>& outset, map<int,float>& overloadmap,
+ int forcefeed=-1) {
+ //int numresult = 0;
+ result.clear();
+
+ // determine hierarchical context for forcefeed (if any)
+ list<int> force_stack;
+ if (forcefeed >= 0 && parent_map.count(forcefeed)) {
+ int t = forcefeed;
+ while (1) {
+ force_stack.push_front(t);
+ //cout << "push " << t << " onto force_stack" << std::endl;
+ if (parent_map.count(t) == 0) break; // reached root, presumably.
+ //cout << " " << t << " parent is " << parent_map[t] << std::endl;
+ t = parent_map[t];
+ }
+ }
+
+ // working vector
+ vector<int> w; // working variable
+
+ // go through each statement
+ for (vector<RuleStep>::iterator pc = rule.steps.begin();
+ pc != rule.steps.end();
+ pc++) {
+ // move input?
+
+ // do it
+ switch (pc->cmd) {
+ case CRUSH_RULE_TAKE:
+ {
+ const int arg = pc->args[0];
+ //cout << "take " << arg << std::endl;
+
+ if (!force_stack.empty()) {
+ assert(force_stack.front() == arg);
+ force_stack.pop_front();
+ }
+
+ w.clear();
+ w.push_back(arg);
+ }
+ break;
+
+ case CRUSH_RULE_CHOOSE_FIRSTN:
+ case CRUSH_RULE_CHOOSE_INDEP:
+ {
+ const bool firstn = pc->cmd == CRUSH_RULE_CHOOSE_FIRSTN;
+ const int numrep = pc->args[0];
+ const int type = pc->args[1];
+
+ //cout << "choose " << numrep << " of type " << type << std::endl;
+
+ assert(!w.empty());
+
+ // reset output
+ vector<int> out;
+
+ // forcefeeding?
+ bool forcing = false;
+ int forceval = -1;
+ if (!force_stack.empty()) {
+ forceval = force_stack.front();
+ force_stack.pop_front();
+ //cout << "priming out with " << forceval << std::endl;
+ forcing = true;
+ } else if (forcefeed >= 0 && type == 0) {
+ //cout << "forcing context-less " << forcefeed << std::endl;
+ forceval = forcefeed;
+ forcefeed = -1;
+ forcing = true;
+ }
+
+ // do each row independently
+ for (vector<int>::iterator i = w.begin();
+ i != w.end();
+ i++) {
+ assert(buckets.count(*i));
+ Bucket *b = buckets[*i];
+ choose(x, numrep, type, b, out, firstn,
+ outset, overloadmap,
+ forcing,
+ forceval);
+ forcing = false; // only once
+ } // for inrow
+
+ // put back into w
+ w.swap(out);
+ out.clear();
+ }
+ break;
+
+ case CRUSH_RULE_EMIT:
+ {
+ for (unsigned i=0; i<w.size(); i++)
+ result.push_back(w[i]);
+ //result[numresult++] = w[i];
+ w.clear();
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+
+ }
+
+
+ };
+
+}
+
+#endif
--- /dev/null
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
+{
+ vector<int> v(numrep);
+ map<int,int> ocount;
+
+ for (int x=1; x<=numpg; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ bool bad = false;
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
+ }
+ //if (bad)
+ // cout << "bad set " << x << ": " << v << endl;
+
+ placement[x] = v;
+
+ //cout << v << "\t" << ocount << endl;
+ }
+
+ if (0)
+ for (map<int,int>::iterator it = ocount.begin();
+ it != ocount.end();
+ it++)
+ cout << it->first << "\t" << it->second << endl;
+
+}
+
+
+float testmovement(int n, float f, int buckettype)
+{
+ Hash h(73232313);
+
+ // crush
+ Crush c;
+
+ int ndisks = 0;
+
+ // bucket
+ Bucket *b;
+ if (buckettype == 0)
+ b = new TreeBucket(1);
+ else if (buckettype == 1 || buckettype == 2)
+ b = new ListBucket(1);
+ else if (buckettype == 3)
+ b = new StrawBucket(1);
+ else if (buckettype == 4)
+ b = new UniformBucket(0,0);
+
+ for (int i=0; i<n; i++)
+ b->add_item(ndisks++,1);
+
+ c.add_bucket(b);
+ int root = b->get_id();
+
+ //c.print(cout,root);
+
+ // rule
+ int numrep = 2;
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+ //c.overload[10] = .1;
+
+
+ int pg_per = 1000;
+ int numpg = pg_per*ndisks/numrep;
+
+ vector<int> ocount(ndisks);
+
+ /*
+ cout << ndisks << " disks, " << endl;
+ cout << pg_per << " pgs per disk" << endl;
+ cout << numpg << " logical pgs" << endl;
+ cout << "numrep is " << numrep << endl;
+ */
+ map<int, vector<int> > placement1, placement2;
+
+ //c.print(cout, root);
+
+
+ // ORIGINAL
+ place(c, rule, numpg, numrep, placement1);
+
+ int olddisks = ndisks;
+
+ // add item
+ if (buckettype == 2) {
+ // start over!
+ ndisks = 0;
+ b = new ListBucket(1);
+ for (int i=0; i<=n; i++)
+ b->add_item(ndisks++,1);
+ c.add_bucket(b);
+ root = b->get_id();
+
+ rule.steps.clear();
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+ }
+ else
+ b->add_item(ndisks++, 1);
+
+
+ // ADDED
+ //c.print(cout, root);
+ place(c, rule, numpg, numrep, placement2);
+
+ int moved = 0;
+ for (int x=1; x<=numpg; x++)
+ if (placement1[x] != placement2[x])
+ for (int j=0; j<numrep; j++)
+ if (placement1[x][j] != placement2[x][j])
+ moved++;
+
+ int total = numpg*numrep;
+ float actual = (float)moved / (float)(total);
+ float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
+ float fac = actual/ideal;
+ //cout << add << "\t" << olddisks << "\t" << ndisks << "\t" << moved << "\t" << total << "\t" << actual << "\t" << ideal << "\t" << fac << endl;
+ cout << "\t" << fac;
+ return fac;
+}
+
+
+int main()
+{
+ //cout << "// " << depth << ", modifydepth " << modifydepth << ", branching " << branching << ", disks " << n << endl;
+ cout << "n\ttree\tlhead\tltail\tstraw\tuniform" << endl;
+
+ //for (int s=2; s<=64; s+= (s<4?1:(s<16?2:4))) {
+ for (int s=2; s<=64; s+= (s<4?1:4)) {
+ float f = 1.0 / (float)s;
+ //cout << f << "\t" << s;
+ cout << s;
+ for (int buckettype=0; buckettype<5; buckettype++)
+ testmovement(s, f, buckettype);
+ cout << endl;
+ }
+}
+
--- /dev/null
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+ if (h == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+ for (int i=0; i<wid[h]; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 10, disks);
+ b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+ return b;
+ } else {
+ // mixed
+ //Bucket *b = new MixedBucket(h+1);
+ Bucket *b = new StrawBucket(h+1);
+ for (int i=0; i<wid[h]; i++) {
+ Bucket *n = make_bucket(c, wid, h-1, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ }
+ c.add_bucket(b);
+ //cout << h << " mixedbucket with " << wid[h] << endl;
+ return b;
+ }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+ Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+ return b->get_id();
+}
+
+
+float go(int dep)
+{
+ Hash h(73232313);
+
+ // crush
+ Crush c;
+
+
+ // buckets
+ int root = -1;
+ int ndisks = 0;
+
+ vector<int> wid;
+ if (0) {
+ for (int d=0; d<dep; d++)
+ wid.push_back(10);
+ }
+ if (1) {
+ if (dep == 0)
+ wid.push_back(1000);
+ if (dep == 1) {
+ wid.push_back(1);
+ wid.push_back(1000);
+ }
+ if (dep == 2) {
+ wid.push_back(5);
+ wid.push_back(5);
+ wid.push_back(8);
+ wid.push_back(5);
+ }
+ }
+
+ if (1) {
+ root = make_hierarchy(c, wid, ndisks);
+ }
+ if (0) {
+ MixedBucket *b = new MixedBucket(1);
+ for (int i=0; i<10000; i++)
+ b->add_item(ndisks++, 10);
+ root = c.add_bucket(b);
+ }
+ if (0) {
+ vector<int> disks;
+ for (int i=0; i<10000; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 10000, disks);
+ Hash h(123);
+ b->make_primes(h);
+ root = c.add_bucket(b);
+ }
+
+
+
+ // rule
+ int numrep = 1;
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+ //c.overload[10] = .1;
+
+
+ int pg_per = 100;
+ int numpg = pg_per*ndisks/numrep;
+
+ vector<int> ocount(ndisks);
+ //cout << ndisks << " disks, " << endl;
+ //cout << pg_per << " pgs per disk" << endl;
+ // cout << numpg << " logical pgs" << endl;
+ //cout << "numrep is " << numrep << endl;
+
+
+ int place = 100000;
+ int times = place / numpg;
+ if (!times) times = 1;
+
+ cout << "#looping " << times << " times" << endl;
+
+ float tvar = 0;
+ int tvarnum = 0;
+
+ int x = 0;
+ for (int t=0; t<times; t++) {
+ vector<int> v(numrep);
+
+ for (int z=0; z<ndisks; z++) ocount[z] = 0;
+
+ for (int xx=1; xx<numpg; xx++) {
+ x++;
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ bool bad = false;
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
+ }
+ if (bad)
+ cout << "bad set " << x << ": " << v << endl;
+
+ //cout << v << "\t" << ocount << endl;
+ }
+
+ /*
+ for (int i=0; i<ocount.size(); i++) {
+ cout << "disk " << i << " has " << ocount[i] << endl;
+ }
+ */
+
+ //cout << "collisions: " << c.collisions << endl;
+ //cout << "r bumps: " << c.bumps << endl;
+
+
+ float avg = 0.0;
+ for (int i=0; i<ocount.size(); i++)
+ avg += ocount[i];
+ avg /= ocount.size();
+ float var = 0.0;
+ for (int i=0; i<ocount.size(); i++)
+ var += (ocount[i] - avg) * (ocount[i] - avg);
+ var /= ocount.size();
+
+ //cout << "avg " << avg << " var " << var << " sd " << sqrt(var) << endl;
+ //cout << avg << "\t";
+
+ tvar += var;
+ tvarnum++;
+ }
+
+ tvar /= tvarnum;
+
+ //cout << "total variance " << tvar << endl;
+
+ return tvar;
+}
+
+
+int main()
+{
+ for (int d=0; d<=2; d++) {
+ float var = go(d);
+ //cout << "## depth = " << d << endl;
+ cout << d << "\t" << var << "\t" << sqrt(var) << endl;
+ }
+}
--- /dev/null
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+int buckettype = 0;
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+ if (h == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+ for (int i=0; i<wid[h]; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+ //b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+ buckets[h].push_back(b);
+ return b;
+ } else {
+ // mixed
+ //Bucket *b = new TreeBucket(h+1);
+ //Bucket *b = new ListBucket(h+1);
+ //Bucket *b = new StrawBucket(h+1);
+ Bucket *b;
+ if (buckettype == 0)
+ b = new TreeBucket(h+1);
+ else if (buckettype == 1 || buckettype == 2)
+ b = new ListBucket(h+1);
+ else if (buckettype == 3)
+ b = new StrawBucket(h+1);
+
+ c.add_bucket(b);
+ for (int i=0; i<wid[h]; i++) {
+ Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ n->set_parent(b->get_id());
+ }
+ buckets[h].push_back(b);
+ //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
+ return b;
+ }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+ Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
+ return b->get_id();
+}
+
+
+void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
+{
+ vector<int> v(numrep);
+ map<int,int> ocount;
+
+ for (int x=1; x<=numpg; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ bool bad = false;
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
+ }
+
+ placement[x] = v;
+
+ //cout << v << "\t" << ocount << endl;
+ }
+
+ if (0)
+ for (map<int,int>::iterator it = ocount.begin();
+ it != ocount.end();
+ it++)
+ cout << it->first << "\t" << it->second << endl;
+
+}
+
+
+float testmovement(int depth, int branching, int udisks, int add, int modifydepth)
+{
+ Hash h(73232313);
+
+ // crush
+ Crush c;
+
+
+ // buckets
+ int root = -1;
+ int ndisks = 0;
+
+ vector<int> wid;
+ wid.push_back(udisks);
+ for (int d=1; d<depth; d++)
+ wid.push_back(branching);
+
+ map< int, list<Bucket*> > buckets;
+
+ root = make_hierarchy(c, wid, buckets, ndisks);
+
+ //c.print(cout,root);
+
+ // rule
+ int numrep = 2;
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+ //c.overload[10] = .1;
+
+
+ int pg_per = 100;
+ int numpg = pg_per*ndisks/numrep;
+
+ vector<int> ocount(ndisks);
+
+ /*
+ cout << ndisks << " disks, " << endl;
+ cout << pg_per << " pgs per disk" << endl;
+ cout << numpg << " logical pgs" << endl;
+ cout << "numrep is " << numrep << endl;
+ */
+ map<int, vector<int> > placement1, placement2;
+
+ //c.print(cout, root);
+
+
+ // ORIGINAL
+ place(c, rule, numpg, numrep, placement1);
+
+ int olddisks = ndisks;
+
+ // add disks
+ //cout << " adding " << add << " disks" << endl;
+ vector<int> disks;
+ for (int i=0; i<add; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+ //b->make_primes(h);
+
+ //Bucket *o = buckets[2].back();
+ Bucket *o;
+ if (buckettype == 2)
+ o = buckets[modifydepth].front();
+ else
+ o = buckets[modifydepth].back();
+
+ c.add_bucket(b);
+ //cout << " adding under " << o->get_id() << endl;
+ c.add_item(o->get_id(), b->get_id(), b->get_weight());
+ //((MixedBucket*)o)->add_item(b->get_id(), b->get_weight());
+ //newbucket = b;
+
+
+ // ADDED
+ //c.print(cout, root);
+ place(c, rule, numpg, numrep, placement2);
+
+ int moved = 0;
+ for (int x=1; x<=numpg; x++)
+ if (placement1[x] != placement2[x])
+ for (int j=0; j<numrep; j++)
+ if (placement1[x][j] != placement2[x][j])
+ moved++;
+
+ int total = numpg*numrep;
+ float actual = (float)moved / (float)(total);
+ float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
+ float fac = actual/ideal;
+ //cout << add << "\t" << olddisks << "\t" << ndisks << "\t" << moved << "\t" << total << "\t" << actual << "\t" << ideal << "\t" << fac << endl;
+ cout << "\t" << fac;
+ return fac;
+}
+
+
+int main()
+{
+
+ int udisks = 10;
+ int add = udisks;
+
+ //int depth = 3;
+ //int branching = 25;
+ int depth = 4;
+ int branching = 9;
+
+ int modifydepth = 1;
+ int bfac = (int)(sqrt((double)branching));
+ int n = (int)(udisks * pow((float)branching, (float)depth-1));
+
+ cout << "// depth " << depth << ", modifydepth " << modifydepth << ", branching " << branching << ", disks " << n << endl;
+ cout << "n\ttree\tlhead\tltail\tstraw" << endl;
+ for (int add = udisks; add <= n; add *= bfac) {
+ cout << add;
+ for (buckettype=0; buckettype<4; buckettype++)
+ testmovement(depth, branching, udisks, add, modifydepth);
+ cout << endl;
+ }
+}
+
--- /dev/null
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+int buckettype = 2; // 0 = mixed, 1 = linear, 2 = straw
+
+int big_one_skip = 255;
+int big_one_size;
+Bucket *big_one = 0;
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+ if (h == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+
+ int s = wid[h];
+ if (big_one_skip > 0)
+ big_one_skip--;
+ if (!big_one_skip && !big_one)
+ s = big_one_size;
+
+
+ for (int i=0; i<s; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+ if (!big_one_skip && !big_one) big_one = b;
+ b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks " << disks.size()<< endl;
+ buckets[h].push_back(b);
+ return b;
+ } else {
+ // mixed
+ Bucket *b;
+ if (buckettype == 0)
+ b = new TreeBucket(h+1);
+ else if (buckettype == 1)
+ b = new ListBucket(h+1);
+ else if (buckettype == 2)
+ b = new StrawBucket(h+1);
+ c.add_bucket(b);
+ for (int i=0; i<wid[h]; i++) {
+ Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ n->set_parent(b->get_id());
+ }
+ buckets[h].push_back(b);
+ //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
+ return b;
+ }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+ Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
+ return b->get_id();
+}
+
+
+void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
+{
+ vector<int> v(numrep);
+ map<int,int> ocount;
+
+ for (int x=1; x<=numpg; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ bool bad = false;
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
+ }
+ if (bad)
+ cout << "bad set " << x << ": " << v << endl;
+
+ placement[x] = v;
+
+ //cout << v << "\t" << ocount << endl;
+ }
+
+ if (0)
+ for (map<int,int>::iterator it = ocount.begin();
+ it != ocount.end();
+ it++)
+ cout << it->first << "\t" << it->second << endl;
+
+}
+
+
+float testmovement(int depth, int branching, int udisks, int add)
+{
+ Hash h(73232313);
+
+ // crush
+ Crush c;
+
+
+ // buckets
+ int root = -1;
+ int ndisks = 0;
+
+ vector<int> wid;
+ wid.push_back(udisks);
+ for (int d=1; d<depth; d++)
+ wid.push_back(branching + ((d==2)?1:0));
+
+ map< int, list<Bucket*> > buckets;
+
+ big_one_size = add;
+ big_one = 0;
+
+ //cout << "making tree" << endl;
+ root = make_hierarchy(c, wid, buckets, ndisks);
+
+ //c.print(cout, root);
+
+
+ // rule
+ int numrep = 2;
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+ //c.overload[10] = .1;
+
+
+ int pg_per = 100;
+ int numpg = pg_per*ndisks/numrep;
+
+ vector<int> ocount(ndisks);
+
+ /*
+ cout << ndisks << " disks, " << endl;
+ cout << pg_per << " pgs per disk" << endl;
+ cout << numpg << " logical pgs" << endl;
+ cout << "numrep is " << numrep << endl;
+ */
+ map<int, vector<int> > placement1, placement2;
+
+ //c.print(cout, root);
+
+ int olddisks = ndisks;
+
+
+ place(c, rule, numpg, numrep, placement1);
+
+ if (1) {
+ // remove disks
+ assert(big_one);
+ c.adjust_item(big_one->get_id(), 0);
+ }
+
+ int newdisks = ndisks - add;
+
+ //c.print(cout, root);
+ place(c, rule, numpg, numrep, placement2);
+
+ int moved = 0;
+ for (int x=1; x<=numpg; x++)
+ if (placement1[x] != placement2[x])
+ for (int j=0; j<numrep; j++)
+ if (placement1[x][j] != placement2[x][j])
+ moved++;
+
+ int total = numpg*numrep;
+ float actual = (float)moved / (float)(total);
+ //float ideal = (float)(newdisks-olddisks) / (float)(ndisks);
+ float ideal = (float)(olddisks-newdisks) / (float)(olddisks);
+ float fac = actual/ideal;
+ cout << add << "\t" << olddisks << "\t" << ndisks << "\t" << moved << "\t" << total << "\t" << actual << "\t" << ideal << "\t" << fac << endl;
+ return fac;
+}
+
+
+int main()
+{
+
+ int udisks = 10;
+ int ndisks = 10;
+ int depth = 4;
+ int branching = 9;
+ int add = udisks;
+
+ //cout << "\t" << n;
+ // cout << endl;
+
+ buckettype = 2; // 0 = tree, 1 = linear, 2 = straw
+
+ int n = udisks * pow((float)branching, (float)depth-1);
+ for (int add = udisks; add <= n; add *= 3) {
+ big_one_skip = 0;
+ big_one_skip = 9;
+ testmovement(depth, branching, udisks, add);
+ }
+
+ /*
+ cout << "##" << endl;
+ for (map<int, map<float,float> >::iterator i = r.begin();
+ i != r.end();
+ i++) {
+ cout << i->first;
+ for (map<float,float>::iterator j = i->second.begin();
+ j != i->second.end();
+ j++)
+ cout << "\t" << j->first << "\t" << j->second;
+ cout << endl;
+ }
+ */
+}
+
--- /dev/null
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+int buckettype = 0;
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+ if (h == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+ for (int i=0; i<wid[h]; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+ //b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+ buckets[h].push_back(b);
+ return b;
+ } else {
+ // mixed
+ //Bucket *b = new TreeBucket(h+1);
+ //Bucket *b = new ListBucket(h+1);
+ //Bucket *b = new StrawBucket(h+1);
+ Bucket *b;
+ if (buckettype == 0)
+ b = new TreeBucket(h+1);
+ else if (buckettype == 1 || buckettype == 2)
+ b = new ListBucket(h+1);
+ else if (buckettype == 3)
+ b = new StrawBucket(h+1);
+
+ c.add_bucket(b);
+ for (int i=0; i<wid[h]; i++) {
+ Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ n->set_parent(b->get_id());
+ }
+ buckets[h].push_back(b);
+ //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
+ return b;
+ }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+ Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
+ return b->get_id();
+}
+
+
+void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
+{
+ vector<int> v(numrep);
+ map<int,int> ocount;
+
+ for (int x=1; x<=numpg; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ bool bad = false;
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
+ }
+
+ placement[x] = v;
+
+ //cout << v << "\t" << ocount << endl;
+ }
+
+ if (0)
+ for (map<int,int>::iterator it = ocount.begin();
+ it != ocount.end();
+ it++)
+ cout << it->first << "\t" << it->second << endl;
+
+}
+
+
+float testmovement(int depth, int branching, int udisks, int add, int modifydepth)
+{
+ Hash h(73232313);
+
+ // crush
+ Crush c;
+
+
+ // buckets
+ int root = -1;
+ int ndisks = 0;
+
+ vector<int> wid;
+ wid.push_back(udisks);
+ for (int d=1; d<depth; d++)
+ wid.push_back(branching);
+
+ map< int, list<Bucket*> > buckets;
+
+ root = make_hierarchy(c, wid, buckets, ndisks);
+
+ //c.print(cout,root);
+
+ // rule
+ int numrep = 2;
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+ //c.overload[10] = .1;
+
+
+ int pg_per = 100;
+ int numpg = pg_per*ndisks/numrep;
+
+ vector<int> ocount(ndisks);
+
+ /*
+ cout << ndisks << " disks, " << endl;
+ cout << pg_per << " pgs per disk" << endl;
+ cout << numpg << " logical pgs" << endl;
+ cout << "numrep is " << numrep << endl;
+ */
+ map<int, vector<int> > placement1, placement2;
+
+ //c.print(cout, root);
+
+
+ // ORIGINAL
+ place(c, rule, numpg, numrep, placement1);
+
+ int olddisks = ndisks;
+
+ // add disks
+ //cout << " adding " << add << " disks" << endl;
+ vector<int> disks;
+ for (int i=0; i<add; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+ //b->make_primes(h);
+
+ //Bucket *o = buckets[2].back();
+ Bucket *o;
+ if (buckettype == 2)
+ o = buckets[modifydepth].front();
+ else
+ o = buckets[modifydepth].back();
+
+ c.add_bucket(b);
+ //cout << " adding under " << o->get_id() << endl;
+ c.add_item(o->get_id(), b->get_id(), b->get_weight(), buckettype == 2);
+ //((MixedBucket*)o)->add_item(b->get_id(), b->get_weight());
+ //newbucket = b;
+
+
+ // ADDED
+ //c.print(cout, root);
+ place(c, rule, numpg, numrep, placement2);
+
+ int moved = 0;
+ for (int x=1; x<=numpg; x++)
+ if (placement1[x] != placement2[x])
+ for (int j=0; j<numrep; j++)
+ if (placement1[x][j] != placement2[x][j])
+ moved++;
+
+ int total = numpg*numrep;
+ float actual = (float)moved / (float)(total);
+ float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
+ float fac = actual/ideal;
+ //cout << add << "\t" << olddisks << "\t" << ndisks << "\t" << moved << "\t" << total << "\t" << actual << "\t" << ideal << "\t" << fac << endl;
+ cout << "\t" << fac;
+ return fac;
+}
+
+
+int main()
+{
+
+ int udisks = 10;
+ int add = udisks;
+
+ //int depth = 3;
+ //int branching = 25;
+ int depth = 2;
+ int branching = 9*9*9;
+
+ int modifydepth = 1;
+ int bfac = (int)(sqrt((double)branching));
+ bfac = 3;
+ int n = (int)(udisks * pow((float)branching, (float)depth-1));
+
+ cout << "// depth " << depth << ", modifydepth " << modifydepth << ", branching " << branching << ", disks " << n << endl;
+ cout << "n\ttree\tlhead\tltail\tstraw" << endl;
+ for (int add = udisks; add <= n; add *= bfac) {
+ cout << add;
+ for (buckettype=0; buckettype<3; buckettype++)
+ testmovement(depth, branching, udisks, add, modifydepth);
+ cout << endl;
+ }
+}
+
--- /dev/null
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include "../../common/Clock.h"
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Clock g_clock;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+ if (h == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+ for (int i=0; i<wid[h]; i++)
+ disks.push_back(ndisks++);
+ float w = 10;//((ndisks-1)/100+1)*10;
+ UniformBucket *b = new UniformBucket(1, 0, w, disks);
+ //b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks weight " << w << endl;
+ return b;
+ } else {
+ // mixed
+ Bucket *b = new TreeBucket(h+1);
+ for (int i=0; i<wid[h]; i++) {
+ Bucket *n = make_bucket(c, wid, h-1, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ }
+ c.add_bucket(b);
+ //cout << h << " mixedbucket with " << wid[h] << endl;
+ return b;
+ }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+ Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+ return b->get_id();
+}
+
+
+
+float go(int dep, int failpc)
+{
+ Hash h(73232313);
+
+ //int overloadcutoff = (int)((float)10000.0 / (float)utilization);
+
+ //cout << "util " << utilization << " cutoff " << overloadcutoff << endl;
+ // crush
+ Crush c;
+
+
+ // buckets
+ int root = -1;
+ int ndisks = 0;
+
+ vector<int> wid;
+ for (int d=0; d<dep; d++)
+ wid.push_back(10);
+
+ if (1) {
+ root = make_hierarchy(c, wid, ndisks);
+ }
+
+ //cout << ndisks << " disks" << endl;
+
+
+ int numf = ndisks * failpc / 100;
+
+
+
+
+ // rule
+ int numrep = 1;
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+ //c.overload[10] = .1;
+
+ int pg_per_base = 100;//20;
+ int pg_med = 10*pg_per_base;
+ int pg_per = pg_per_base*5.5;//100;
+ int numpg = pg_per*ndisks/numrep;
+
+ vector<int> ocount(ndisks);
+ //cout << ndisks << " disks, " << endl;
+ //cout << pg_per << " pgs per disk" << endl;
+ // cout << numpg << " logical pgs" << endl;
+ //cout << "numrep is " << numrep << endl;
+
+
+ int place = 1000000;
+ int times = place / numpg;
+ if (!times) times = 1;
+
+
+ //cout << "looping " << times << " times" << endl;
+
+ float tavg[10];
+ float tvar[10];
+ for (int j=0;j<10;j++) {
+ tvar[j] = 0;
+ tavg[j] = 0;
+ }
+ int tvarnum = 0;
+ float trvar = 0.0;
+
+ float overloadsum = 0.0;
+ float adjustsum = 0.0;
+ float afteroverloadsum = 0.0;
+ float aslowdown = 0.0;
+ int chooses = 0;
+ int xs = 1;
+ for (int t=0; t<times; t++) {
+ vector<int> v(numrep);
+
+ c.out.clear();
+
+ for (int z=0; z<ndisks; z++) ocount[z] = 0;
+
+ utime_t t1a = g_clock.now();
+ for (int x=xs; x<numpg+xs; x++) {
+ c.do_rule(rule, x, v);
+ //chooses += numrep;
+ for (int i=0; i<v.size(); i++) {
+ //if (v[i] >= ndisks) cout << "v[i] " << i << " is " << v[i] << " .. x = " << x << endl;
+ //assert(v[i] < ndisks);
+ ocount[v[i]]++;
+ }
+ }
+ utime_t t1b = g_clock.now();
+
+ // add in numf failed disks
+ for (int f = 0; f < numf; f++) {
+ int d = rand() % ndisks;
+ while (c.out.count(d)) d = rand() % ndisks;
+ c.out.insert(d);
+ }
+
+ utime_t t3a = g_clock.now();
+ for (int x=xs; x<numpg+xs; x++) {
+ c.do_rule(rule, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ for (int i=0; i<v.size(); i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ }
+
+ //cout << v << "\t" << ocount << endl;
+ }
+ xs += numpg;
+
+ utime_t t3b = g_clock.now();
+
+ t1b -= t1a;
+ double t1 = (double)t1b;
+ t3b -= t3a;
+ double t3 = (double)t3b;
+ double slowdown = t3/t1;
+ //cout << "slowdown " << slowdown << endl;
+ aslowdown += slowdown;
+
+ //cout << "collisions: " << c.collisions << endl;
+ //cout << "r bumps: " << c.bumps << endl;
+
+ // stair var calc
+ int n = ndisks/10;
+ float avg[10];
+ float var[10];
+ for (int i=0;i<10;i++) {
+ int s = n*i;
+ avg[i] = 0.0;
+ int nf = 0;
+ for (int j=0; j<n; j++) {
+ if (c.out.count(j+s)) { nf++; continue; }
+ avg[i] += ocount[j+s];
+ }
+ avg[i] /= (n-nf);//ocount.size();
+ var[i] = 0.0;
+ for (int j=0; j<n; j++) {
+ if (c.out.count(j+s)) continue;
+ var[i] += (ocount[j+s] - avg[i]) * (ocount[j+s] - avg[i]);
+ }
+ var[i] /= (n-nf);//ocount.size();
+
+ tvar[i] += var[i];
+ tavg[i] += avg[i];
+ }
+ //cout << "avg " << avg << " var " << var << " sd " << sqrt(var) << endl;
+
+ tvarnum++;
+
+ // flat var calc
+ int na = ndisks - numf; // num active
+ float ravg = 0.0;
+ for (int i=0;i<ndisks;i++) {
+ if (c.out.count(i)) continue;
+ ravg += ocount[i];
+ }
+ ravg /= (float)na;
+ float rvar = 0.0;
+ for (int i=0; i<ndisks; i++) {
+ if (c.out.count(i)) continue;
+ rvar += (ravg-(float)ocount[i])*(ravg-(float)ocount[i]);
+ }
+ rvar /= (float)na;
+
+ trvar += rvar;
+ }
+
+
+ trvar /= (float)tvarnum;
+
+ //overloadsum /= tvarnum;
+ //adjustsum /= tvarnum;
+ float avar = 0.0;
+ for (int j=0;j<10;j++) {
+ tvar[j] /= tvarnum;
+ tavg[j] /= tvarnum;
+ avar += tvar[j];
+ }
+ avar /= 10;
+ avar = sqrt(avar);
+ avar /= /*5.5 **/ (float)pg_per_base;
+ //afteroverloadsum /= tvarnum;
+ aslowdown /= tvarnum;
+
+ //int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
+ //float crate = (float) collisions / (float)chooses;
+ //cout << "collisions: " << c.collisions << endl;
+
+
+ //cout << "total variance " << tvar << endl;
+ //cout << " overlaod " << overloadsum << endl;
+
+ cout << failpc
+ << "\t" << numf
+ //<< "\t" << adjustsum
+ //<< "\t" << afteroverloadsum
+ << "\t" << aslowdown
+ << "\t" << trvar
+ << "\t" << sqrt(trvar) / (float)pg_per_base
+ << "\t..\t" << avar
+ << "\t-";
+
+ for (int i=0;i<10;i++)
+ cout << "\t" << tavg[i] << "\t" << sqrt(tvar[i]);// << "\t" << tvar[i]/tavg[i];
+
+ cout << endl;
+ return tvar[0];
+}
+
+
+int main()
+{
+ for (int pc = 0; pc < 90; pc += 5) {
+ float var = go(3, pc);
+ }
+
+
+}
--- /dev/null
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+ if (h == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+ for (int i=0; i<wid[h]; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 10, disks);
+ //b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+ return b;
+ } else {
+ // mixed
+ MixedBucket *b = new MixedBucket(h+1);
+ for (int i=0; i<wid[h]; i++) {
+ Bucket *n = make_bucket(c, wid, h-1, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ }
+ c.add_bucket(b);
+ //cout << h << " mixedbucket with " << wid[h] << endl;
+ return b;
+ }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+ Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+ return b->get_id();
+}
+
+
+Bucket *make_random(Crush& c, int wid, int height, int& ndisks)
+{
+ int w = rand() % (wid-1) + 2;
+
+ if (height == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+ for (int i=0; i<w; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 10, disks);
+ b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+ return b;
+ } else {
+ // mixed
+ int h = rand() % height + 1;
+ MixedBucket *b = new MixedBucket(h+1);
+ for (int i=0; i<w; i++) {
+ Bucket *n = make_random(c, wid, h-1, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ }
+ c.add_bucket(b);
+ //cout << h << " mixedbucket with " << wid[h] << endl;
+ return b;
+ }
+
+}
+
+
+float go(int dep, int overloadcutoff)
+{
+ Hash h(73232313);
+
+ // crush
+ Crush c;
+
+
+ // buckets
+ int root = -1;
+ int ndisks = 0;
+
+ vector<int> wid;
+ for (int d=0; d<dep; d++)
+ wid.push_back(10);
+
+ if (1) {
+ root = make_hierarchy(c, wid, ndisks);
+ }
+ if (0) {
+ Bucket *r = make_random(c, 20, 4, ndisks);
+ root = r->get_id();
+ //c.print(cout, root);
+ }
+ if (0) {
+ MixedBucket *b = new MixedBucket(1);
+ for (int i=0; i<10000; i++)
+ b->add_item(ndisks++, 10);
+ root = c.add_bucket(b);
+ }
+ if (0) {
+ vector<int> disks;
+ for (int i=0; i<10000; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 10000, disks);
+ Hash h(123);
+ b->make_primes(h);
+ root = c.add_bucket(b);
+ }
+ //cout << ndisks << " disks" << endl;
+
+
+
+ // rule
+ int numrep = 1;
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+ //c.overload[10] = .1;
+
+
+ int pg_per = 100;
+ int numpg = pg_per*ndisks/numrep;
+
+ vector<int> ocount(ndisks);
+ //cout << ndisks << " disks, " << endl;
+ //cout << pg_per << " pgs per disk" << endl;
+ // cout << numpg << " logical pgs" << endl;
+ //cout << "numrep is " << numrep << endl;
+
+
+ int place = 1000000;
+ int times = place / numpg;
+ if (!times) times = 1;
+
+
+ //cout << "looping " << times << " times" << endl;
+
+ float tvar = 0;
+ int tvarnum = 0;
+
+ float overloadsum = 0.0;
+ float adjustsum = 0.0;
+ float afteroverloadsum = 0.0;
+ int chooses = 0;
+ int xs = 1;
+ for (int t=0; t<times; t++) {
+ vector<int> v(numrep);
+
+ c.overload.clear();
+
+ for (int z=0; z<ndisks; z++) ocount[z] = 0;
+
+ for (int x=xs; x<numpg+xs; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ chooses += numrep;
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ bool bad = false;
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
+ }
+ if (bad)
+ cout << "bad set " << x << ": " << v << endl;
+
+ //cout << v << "\t" << ocount << endl;
+ }
+
+ // overloaded?
+ int overloaded = 0;
+ int adjusted = 0;
+ for (int i=0; i<ocount.size(); i++) {
+ if (ocount[i] > overloadcutoff)
+ overloaded++;
+
+ if (ocount[i] > 100+(overloadcutoff-100)/2) {
+ adjusted++;
+ c.overload[i] = 100.0 / (float)ocount[i];
+ //cout << "disk " << i << " has " << ocount[i] << endl;
+ }
+ ocount[i] = 0;
+ }
+ //cout << overloaded << " overloaded" << endl;
+ overloadsum += (float)overloaded / (float)ndisks;
+ adjustsum += (float)adjusted / (float)ndisks;
+
+
+ for (int x=xs; x<numpg+xs; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ bool bad = false;
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
+ }
+ if (bad)
+ cout << "bad set " << x << ": " << v << endl;
+
+ //cout << v << "\t" << ocount << endl;
+ }
+ xs += numpg;
+
+ int still = 0;
+ for (int i=0; i<ocount.size(); i++) {
+ if (ocount[i] > overloadcutoff) {
+ still++;
+ //c.overload[ocount[i]] = 100.0 / (float)ocount[i];
+ //cout << "disk " << i << " has " << ocount[i] << endl;
+ }
+ }
+ //if (still) cout << "overload was " << overloaded << " now " << still << endl;
+ afteroverloadsum += (float)still / (float)ndisks;
+
+ //cout << "collisions: " << c.collisions << endl;
+ //cout << "r bumps: " << c.bumps << endl;
+
+ float avg = 0.0;
+ for (int i=0; i<ocount.size(); i++)
+ avg += ocount[i];
+ avg /= ocount.size();
+ float var = 0.0;
+ for (int i=0; i<ocount.size(); i++)
+ var += (ocount[i] - avg) * (ocount[i] - avg);
+ var /= ocount.size();
+
+ //cout << "avg " << avg << " var " << var << " sd " << sqrt(var) << endl;
+
+ tvar += var;
+ tvarnum++;
+ }
+
+ overloadsum /= tvarnum;
+ adjustsum /= tvarnum;
+ tvar /= tvarnum;
+ afteroverloadsum /= tvarnum;
+
+ int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
+ float crate = (float) collisions / (float)chooses;
+ //cout << "collisions: " << c.collisions << endl;
+
+
+ //cout << "total variance " << tvar << endl;
+ //cout << " overlaod " << overloadsum << endl;
+
+ cout << overloadcutoff << "\t" << (10000.0 / (float)overloadcutoff) << "\t" << tvar << "\t" << overloadsum << "\t" << adjustsum << "\t" << afteroverloadsum << "\t" << crate << endl;
+ return tvar;
+}
+
+
+int main()
+{
+ for (int d=140; d>100; d -= 5) {
+ float var = go(3,d);
+ //cout << "## depth = " << d << endl;
+ //cout << d << "\t" << var << endl;
+ }
+}
--- /dev/null
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+ if (h == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+ for (int i=0; i<wid[h]; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 10, disks);
+ //b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+ return b;
+ } else {
+ // mixed
+ Bucket *b = new TreeBucket(h+1);
+ for (int i=0; i<wid[h]; i++) {
+ Bucket *n = make_bucket(c, wid, h-1, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ }
+ c.add_bucket(b);
+ //cout << h << " mixedbucket with " << wid[h] << endl;
+ return b;
+ }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+ Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+ return b->get_id();
+}
+
+
+float go(int dep)
+{
+ Hash h(73232313);
+
+ // crush
+ Crush c;
+
+
+ // buckets
+ int root = -1;
+ int ndisks = 0;
+
+ vector<int> wid;
+ if (1) {
+ for (int d=0; d<dep; d++)
+ wid.push_back(10);
+ }
+ if (0) {
+ if (dep == 0)
+ wid.push_back(1000);
+ if (dep == 1) {
+ wid.push_back(1);
+ wid.push_back(1000);
+ }
+ if (dep == 2) {
+ wid.push_back(5);
+ wid.push_back(5);
+ wid.push_back(8);
+ wid.push_back(5);
+ }
+ }
+
+ if (1) {
+ root = make_hierarchy(c, wid, ndisks);
+ }
+
+
+
+ // rule
+ int numrep = 1;
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+ //c.overload[10] = .1;
+
+
+ int pg_per = 100;
+ int numpg = pg_per*ndisks/numrep;
+
+ vector<int> ocount(ndisks);
+ //cout << ndisks << " disks, " << endl;
+ //cout << pg_per << " pgs per disk" << endl;
+ // cout << numpg << " logical pgs" << endl;
+ //cout << "numrep is " << numrep << endl;
+
+
+ int place = 100000;
+ int times = place / numpg;
+ if (!times) times = 1;
+
+ cout << "#looping " << times << " times" << endl;
+
+ float tvar = 0;
+ int tvarnum = 0;
+ float tavg = 0;
+
+ int x = 0;
+ for (int t=0; t<times; t++) {
+ vector<int> v(numrep);
+
+ for (int z=0; z<ndisks; z++) ocount[z] = 0;
+
+ for (int xx=1; xx<numpg; xx++) {
+ x++;
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ bool bad = false;
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
+ }
+
+ //cout << v << "\t" << ocount << endl;
+ }
+
+ /*
+ for (int i=0; i<ocount.size(); i++) {
+ cout << "disk " << i << " has " << ocount[i] << endl;
+ }
+ */
+
+ //cout << "collisions: " << c.collisions << endl;
+ //cout << "r bumps: " << c.bumps << endl;
+
+
+ float avg = 0.0;
+ for (int i=0; i<ocount.size(); i++)
+ avg += ocount[i];
+ avg /= ocount.size();
+ float var = 0.0;
+ for (int i=0; i<ocount.size(); i++)
+ var += (ocount[i] - avg) * (ocount[i] - avg);
+ var /= ocount.size();
+
+ if (times < 10)
+ cout << "avg " << avg << " evar " << sqrt(avg) << " sd " << sqrt(var) << endl;
+ //cout << avg << "\t";
+
+ tvar += var;
+ tavg += avg;
+ tvarnum++;
+ }
+
+ tavg /= tvarnum;
+ tvar /= tvarnum;
+
+ cout << "total variance " << sqrt(tvar) << " expected " << sqrt(tavg) << endl;
+
+ return tvar;
+}
+
+
+int main()
+{
+ for (int d=2; d<=5; d++) {
+ float var = go(d);
+ //cout << "## depth = " << d << endl;
+ //cout << d << "\t" << var << "\t" << sqrt(var) << endl;
+ }
+}
--- /dev/null
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+ if (h == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+ for (int i=0; i<wid[h]; i++)
+ disks.push_back(ndisks++);
+ float w = ((ndisks-1)/100+1)*10;
+ UniformBucket *b = new UniformBucket(1, 0, w, disks);
+ //b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks weight " << w << endl;
+ return b;
+ } else {
+ // mixed
+ Bucket *b = new TreeBucket(h+1);
+ //Bucket *b = new StrawBucket(h+1);
+ for (int i=0; i<wid[h]; i++) {
+ Bucket *n = make_bucket(c, wid, h-1, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ }
+ c.add_bucket(b);
+ //cout << h << " mixedbucket with " << wid[h] << endl;
+ return b;
+ }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+ Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+ return b->get_id();
+}
+
+
+
+float go(int dep, int overloadcutoff)
+{
+ Hash h(73232313);
+
+ // crush
+ Crush c;
+
+
+ // buckets
+ int root = -1;
+ int ndisks = 0;
+
+ vector<int> wid;
+ for (int d=0; d<dep; d++)
+ wid.push_back(10);
+
+ if (1) {
+ root = make_hierarchy(c, wid, ndisks);
+ }
+
+
+ // rule
+ int numrep = 1;
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+ //c.overload[10] = .1;
+
+
+ int pg_per_base = 10;
+ int pg_per = pg_per_base*5.5;//100;
+ int numpg = pg_per*ndisks/numrep;
+
+ vector<int> ocount(ndisks);
+ //cout << ndisks << " disks, " << endl;
+ //cout << pg_per << " pgs per disk" << endl;
+ // cout << numpg << " logical pgs" << endl;
+ //cout << "numrep is " << numrep << endl;
+
+
+ int place = 100000;
+ int times = place / numpg;
+ if (!times) times = 1;
+
+
+ //cout << "looping " << times << " times" << endl;
+
+ float tavg[10];
+ float tvar[10];
+ for (int j=0;j<10;j++) {
+ tvar[j] = 0;
+ tavg[j] = 0;
+ }
+ int tvarnum = 0;
+
+ float overloadsum = 0.0;
+ float adjustsum = 0.0;
+ float afteroverloadsum = 0.0;
+ int chooses = 0;
+ int xs = 1;
+ for (int t=0; t<times; t++) {
+ vector<int> v(numrep);
+
+ c.overload.clear();
+
+ for (int z=0; z<ndisks; z++) ocount[z] = 0;
+
+ for (int x=xs; x<numpg+xs; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ chooses += numrep;
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ bool bad = false;
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
+ }
+ //if (bad)
+ //cout << "bad set " << x << ": " << v << endl;
+
+ //cout << v << "\t" << ocount << endl;
+ }
+
+ // overloaded?
+ int overloaded = 0;
+ int adjusted = 0;
+ for (int i=0; i<ocount.size(); i++) {
+ int target = (i/100+1)*10;
+ int cutoff = target * overloadcutoff / 100;
+ int adjoff = target + (cutoff - target)*3/4;
+ if (ocount[i] > cutoff)
+ overloaded++;
+
+ if (ocount[i] > adjoff) {
+ adjusted++;
+ c.overload[i] = (float)target / (float)ocount[i];
+ //cout << "setting overload " << i << " to " << c.overload[i] << endl;
+ //cout << "disk " << i << " has " << ocount[i] << endl;
+ }
+ ocount[i] = 0;
+ }
+ //cout << overloaded << " overloaded" << endl;
+ overloadsum += (float)overloaded / (float)ndisks;
+ adjustsum += (float)adjusted / (float)ndisks;
+
+
+
+ if (1) {
+ // second pass
+ for (int x=xs; x<numpg+xs; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ bool bad = false;
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
+ }
+
+ //cout << v << "\t" << ocount << endl;
+ }
+
+ for (int i=0; i<ocount.size(); i++) {
+ int target = (i/100+1)*10;
+ int cutoff = target * overloadcutoff / 100;
+ int adjoff = cutoff;//target + (cutoff - target)*3/4;
+
+ if (ocount[i] >= adjoff) {
+ adjusted++;
+ if (c.overload.count(i) == 0) {
+ c.overload[i] = 1.0;
+ adjusted++;
+ }
+ //else cout << "(re)adjusting " << i << endl;
+ c.overload[i] *= (float)target / (float)ocount[i];
+ //cout << "setting overload " << i << " to " << c.overload[i] << endl;
+ //cout << "disk " << i << " has " << ocount[i] << endl;
+ }
+ ocount[i] = 0;
+ }
+ }
+
+ for (int x=xs; x<numpg+xs; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ bool bad = false;
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
+ }
+ //cout << v << "\t" << ocount << endl;
+ }
+ xs += numpg;
+
+ int still = 0;
+ for (int i=0; i<ocount.size(); i++) {
+ int target = (i/100+1)*10;
+ int cutoff = target * overloadcutoff / 100;
+ int adjoff = target + (cutoff - target)/3;
+
+ if (ocount[i] > cutoff) {
+ still++;
+ //c.overload[ocount[i]] = 100.0 / (float)ocount[i];
+ if (c.overload.count(i)) cout << "[adjusted] ";
+ cout << "disk " << i << " has " << ocount[i] << endl;
+ }
+ }
+ //if (still) cout << "overload was " << overloaded << " now " << still << endl;
+ afteroverloadsum += (float)still / (float)ndisks;
+
+ //cout << "collisions: " << c.collisions << endl;
+ //cout << "r bumps: " << c.bumps << endl;
+
+ int n = ndisks/10;
+ float avg[10];
+ float var[10];
+ for (int i=0;i<10;i++) {
+ int s = n*i;
+ avg[i] = 0.0;
+ for (int j=0; j<n; j++)
+ avg[i] += ocount[j+s];
+ avg[i] /= n;//ocount.size();
+ var[i] = 0.0;
+ for (int j=0; j<n; j++)
+ var[i] += (ocount[j+s] - avg[i]) * (ocount[j+s] - avg[i]);
+ var[i] /= n;//ocount.size();
+
+ tvar[i] += var[i];
+ tavg[i] += avg[i];
+ }
+ //cout << "avg " << avg << " var " << var << " sd " << sqrt(var) << endl;
+
+ tvarnum++;
+ }
+
+ overloadsum /= tvarnum;
+ adjustsum /= tvarnum;
+ for (int j=0;j<10;j++) {
+ tvar[j] /= tvarnum;
+ tavg[j] /= tvarnum;
+ }
+ afteroverloadsum /= tvarnum;
+
+ //int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
+ //float crate = (float) collisions / (float)chooses;
+ //cout << "collisions: " << c.collisions << endl;
+
+
+ //cout << "total variance " << tvar << endl;
+ //cout << " overlaod " << overloadsum << endl;
+
+ cout << overloadcutoff << "\t" << (10000.0 / (float)overloadcutoff) << "\t" << overloadsum << "\t" << adjustsum << "\t" << afteroverloadsum;
+ for (int i=0;i<10;i++)
+ cout << "\t" << tavg[i] << "\t" << tvar[i];// << "\t" << tvar[i]/tavg[i];
+ cout << endl;
+ return tvar[0];
+}
+
+
+int main()
+{
+ float var = go(3,200);
+ for (int d=140; d>100; d -= 5) {
+ float var = go(3,d);
+ //cout << "## depth = " << d << endl;
+ //cout << d << "\t" << var << endl;
+ }
+}
--- /dev/null
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+ if (h == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+ for (int i=0; i<wid[h]; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+ b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+ buckets[h].push_back(b);
+ return b;
+ } else {
+ // mixed
+ MixedBucket *b = new MixedBucket(h+1);
+ c.add_bucket(b);
+ for (int i=0; i<wid[h]; i++) {
+ Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ n->set_parent(b->get_id());
+ }
+ buckets[h].push_back(b);
+ //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
+ return b;
+ }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+ Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
+ return b->get_id();
+}
+
+
+void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
+{
+ vector<int> v(numrep);
+ map<int,int> ocount;
+
+ for (int x=1; x<=numpg; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ bool bad = false;
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
+ }
+ if (bad)
+ cout << "bad set " << x << ": " << v << endl;
+
+ placement[x] = v;
+
+ //cout << v << "\t" << ocount << endl;
+ }
+
+ if (0)
+ for (map<int,int>::iterator it = ocount.begin();
+ it != ocount.end();
+ it++)
+ cout << it->first << "\t" << it->second << endl;
+
+}
+
+
+float testmovement(int depth, int branching, int udisks)
+{
+ Hash h(73232313);
+
+ // crush
+ Crush c;
+
+
+ // buckets
+ int root = -1;
+ int ndisks = 0;
+
+ vector<int> wid;
+ wid.push_back(udisks);
+ for (int d=1; d<depth; d++)
+ wid.push_back(branching);
+
+ map< int, list<Bucket*> > buckets;
+
+ if (1) {
+ root = make_hierarchy(c, wid, buckets, ndisks);
+ }
+ if (0) {
+ MixedBucket *b = new MixedBucket(1);
+ for (int i=0; i<10000; i++)
+ b->add_item(ndisks++, 10);
+ root = c.add_bucket(b);
+ }
+ if (0) {
+ vector<int> disks;
+ for (int i=0; i<10000; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+ Hash h(123);
+ b->make_primes(h);
+ root = c.add_bucket(b);
+ }
+
+
+
+ // rule
+ int numrep = 2;
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+ //c.overload[10] = .1;
+
+
+ int pg_per = 100;
+ int numpg = pg_per*ndisks/numrep;
+
+ vector<int> ocount(ndisks);
+
+ /*
+ cout << ndisks << " disks, " << endl;
+ cout << pg_per << " pgs per disk" << endl;
+ cout << numpg << " logical pgs" << endl;
+ cout << "numrep is " << numrep << endl;
+ */
+ map<int, vector<int> > placement1, placement2;
+
+ //c.print(cout, root);
+
+ place(c, rule, numpg, numrep, placement1);
+
+ if (1) {
+ // failed
+
+ //for (int i=500; i<1000; i++)
+ //c.failed.insert(i);
+ c.failed.insert(0);
+ }
+
+ int olddisks = ndisks;
+
+ if (1) {
+ int n = udisks;
+ //cout << " adding " << n << " disks" << endl;
+ vector<int> disks;
+ for (int i=0; i<n; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+ Hash h(123);
+ b->make_primes(h);
+ Bucket *o = buckets[1].back();
+ c.add_bucket(b);
+ //cout << " adding under " << o->get_id() << endl;
+ c.add_item(o->get_id(), b->get_id(), b->get_weight());
+ //((MixedBucket*)o)->add_item(b->get_id(), b->get_weight());
+ }
+
+ //c.print(cout, root);
+ place(c, rule, numpg, numrep, placement2);
+
+ int moved = 0;
+ for (int x=1; x<=numpg; x++) {
+ if (placement1[x] != placement2[x]) {
+ for (int j=0; j<numrep; j++)
+ if (placement1[x][j] != placement2[x][j])
+ moved++;
+
+ }
+ }
+
+ float f = (float)moved / (float)(numpg*numrep);
+ float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
+ float fac = f/ideal;
+ //cout << moved << " moved or " << f << ", ideal " << ideal << ", factor of " << fac << endl;
+ return fac;
+}
+
+
+int main()
+{
+
+ int udisks = 10;
+ int ndisks = 10;
+ for (int depth = 2; depth <= 4; depth++) {
+ vector<float> v;
+ cout << depth;
+ for (int branching = 3; branching < 16; branching += 1) {
+ float fac = testmovement(depth, branching, udisks);
+ v.push_back(fac);
+ int n = udisks * pow((float)branching, (float)depth-1);
+ cout << "\t" << n;
+ cout << "\t" << fac;
+ }
+ //for (int i=0; i<v.size(); i++)
+ //cout << "\t" << v[i];
+ cout << endl;
+
+ }
+
+}
+
--- /dev/null
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+ if (h == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+ for (int i=0; i<wid[h]; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+ b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+ buckets[h].push_back(b);
+ return b;
+ } else {
+ // mixed
+ MixedBucket *b = new MixedBucket(h+1);
+ c.add_bucket(b);
+ for (int i=0; i<wid[h]; i++) {
+ Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ n->set_parent(b->get_id());
+ }
+ buckets[h].push_back(b);
+ //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
+ return b;
+ }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+ Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
+ return b->get_id();
+}
+
+
+void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, set<int> >& placement)
+{
+ vector<int> v(numrep);
+ map<int,int> ocount;
+
+ for (int x=1; x<=numpg; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ bool bad = false;
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
+ placement[v[i]].insert(x);
+ }
+ if (bad)
+ cout << "bad set " << x << ": " << v << endl;
+
+
+ //cout << v << "\t" << ocount << endl;
+ }
+
+ if (0)
+ for (map<int,int>::iterator it = ocount.begin();
+ it != ocount.end();
+ it++)
+ cout << it->first << "\t" << it->second << endl;
+
+}
+
+
+float testmovement(int depth, int branching, int udisks)
+{
+ Hash h(73232313);
+
+ // crush
+ Crush c;
+
+
+ // buckets
+ int root = -1;
+ int ndisks = 0;
+
+ vector<int> wid;
+ wid.push_back(udisks);
+ for (int d=1; d<depth; d++)
+ wid.push_back(branching);
+
+ map< int, list<Bucket*> > buckets;
+
+ if (1) {
+ root = make_hierarchy(c, wid, buckets, ndisks);
+ }
+ if (0) {
+ MixedBucket *b = new MixedBucket(1);
+ for (int i=0; i<10000; i++)
+ b->add_item(ndisks++, 10);
+ root = c.add_bucket(b);
+ }
+ if (0) {
+ vector<int> disks;
+ for (int i=0; i<10000; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+ Hash h(123);
+ b->make_primes(h);
+ root = c.add_bucket(b);
+ }
+
+
+
+ // rule
+ int numrep = 2;
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+ //c.overload[10] = .1;
+
+
+ int pg_per = 100;
+ int numpg = pg_per*ndisks/numrep;
+
+ vector<int> ocount(ndisks);
+
+ /*
+ cout << ndisks << " disks, " << endl;
+ cout << pg_per << " pgs per disk" << endl;
+ cout << numpg << " logical pgs" << endl;
+ cout << "numrep is " << numrep << endl;
+ */
+ map<int, set<int> > placement1, placement2;
+
+ //c.print(cout, root);
+
+ place(c, rule, numpg, numrep, placement1);
+
+ float over = .5;
+
+ if (1) {
+ // failed
+
+ //for (int i=500; i<1000; i++)
+ //c.failed.insert(i);
+ //c.failed.insert(0);
+ c.overload[0] = over;
+ }
+
+ int olddisks = ndisks;
+
+
+
+ if (0) {
+ int n = udisks;
+ //cout << " adding " << n << " disks" << endl;
+ vector<int> disks;
+ for (int i=0; i<n; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+ Hash h(123);
+ b->make_primes(h);
+ Bucket *o = buckets[1].back();
+ c.add_bucket(b);
+ //cout << " adding under " << o->get_id() << endl;
+ c.add_item(o->get_id(), b->get_id(), b->get_weight());
+ //((MixedBucket*)o)->add_item(b->get_id(), b->get_weight());
+ }
+
+ //c.print(cout, root);
+ place(c, rule, numpg, numrep, placement2);
+
+ vector<int> moved(ndisks);
+
+ //int moved = 0;
+ for (int d=0; d<ndisks; d++) {
+ for (set<int>::iterator it = placement1[d].begin();
+ it != placement1[d].end();
+ it++) {
+ placement2[d].erase(*it);
+ }
+ }
+
+ float avg = 0;
+ for (int d=0; d<ndisks; d++) {
+ moved[d] = placement2[d].size();
+ avg += moved[d];
+ }
+ avg /= (float)ndisks;
+ float var = 0;
+ for (int d=0; d<ndisks; d++) {
+ var += (moved[d]-avg)*(moved[d]-avg);
+ }
+ var /= (float)ndisks;
+
+ float expected = over * 100.0 / (float)(ndisks-1);
+
+ cout << ndisks << "\t" << expected << "\t" << avg << "\t" << var << endl;
+ /*
+ float f = (float)moved / (float)(numpg*numrep);
+ float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
+ float fac = f/ideal;
+ //cout << moved << " moved or " << f << ", ideal " << ideal << ", factor of " << fac << endl;
+ return fac;
+ */
+}
+
+
+int main()
+{
+
+ int udisks = 10;
+ int ndisks = 10;
+ for (int depth = 2; depth <= 4; depth++) {
+ vector<float> v;
+ cout << depth;
+ for (int branching = 3; branching < 16; branching += 1) {
+ float fac = testmovement(depth, branching, udisks);
+ v.push_back(fac);
+ int n = udisks * pow((float)branching, (float)depth-1);
+ //cout << "\t" << n;
+ //cout << "\t" << fac;
+ }
+ //for (int i=0; i<v.size(); i++)
+ //cout << "\t" << v[i];
+ //cout << endl;
+
+ }
+
+}
+
--- /dev/null
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include "../../common/Clock.h"
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Clock g_clock;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+ if (h == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+ for (int i=0; i<wid[h]; i++)
+ disks.push_back(ndisks++);
+ float w = ((ndisks-1)/100+1)*10;
+ UniformBucket *b = new UniformBucket(1, 0, w, disks);
+ //b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks weight " << w << endl;
+ return b;
+ } else {
+ // mixed
+ Bucket *b = new TreeBucket(h+1);
+ for (int i=0; i<wid[h]; i++) {
+ Bucket *n = make_bucket(c, wid, h-1, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ }
+ c.add_bucket(b);
+ //cout << h << " mixedbucket with " << wid[h] << endl;
+ return b;
+ }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+ Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+ return b->get_id();
+}
+
+
+
+float go(int dep, int utilization )
+{
+ Hash h(73232313);
+
+ int overloadcutoff = (int)((float)10000.0 / (float)utilization);
+
+ //cout << "util " << utilization << " cutoff " << overloadcutoff << endl;
+ // crush
+ Crush c;
+
+
+ // buckets
+ int root = -1;
+ int ndisks = 0;
+
+ vector<int> wid;
+ for (int d=0; d<dep; d++)
+ wid.push_back(10);
+
+ if (1) {
+ root = make_hierarchy(c, wid, ndisks);
+ }
+
+ //cout << ndisks << " disks" << endl;
+
+
+
+ // rule
+ int numrep = 1;
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+ //c.overload[10] = .1;
+
+ int pg_per_base = 20;
+ int pg_med = 10*pg_per_base;
+ int pg_per = pg_per_base*5.5;//100;
+ int numpg = pg_per*ndisks/numrep;
+
+ vector<int> ocount(ndisks);
+ //cout << ndisks << " disks, " << endl;
+ //cout << pg_per << " pgs per disk" << endl;
+ // cout << numpg << " logical pgs" << endl;
+ //cout << "numrep is " << numrep << endl;
+
+
+ int place = 100000;
+ int times = place / numpg;
+ if (!times) times = 1;
+
+
+ //cout << "looping " << times << " times" << endl;
+
+ float tavg[10];
+ float tvar[10];
+ for (int j=0;j<10;j++) {
+ tvar[j] = 0;
+ tavg[j] = 0;
+ }
+ int tvarnum = 0;
+
+ float overloadsum = 0.0;
+ float adjustsum = 0.0;
+ float afteroverloadsum = 0.0;
+ float aslowdown = 0.0;
+ int chooses = 0;
+ int xs = 1;
+ for (int t=0; t<times; t++) {
+ vector<int> v(numrep);
+
+ c.overload.clear();
+
+ for (int z=0; z<ndisks; z++) ocount[z] = 0;
+
+
+ utime_t t1a = g_clock.now();
+
+ for (int x=xs; x<numpg+xs; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ chooses += numrep;
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ }
+
+ //cout << v << "\t" << ocount << endl;
+ }
+
+ utime_t t1b = g_clock.now();
+
+ // overloaded?
+ int overloaded = 0;
+ int adjusted = 0;
+ for (int i=0; i<ocount.size(); i++) {
+ int target = (i/100+1)*pg_per_base;
+ int cutoff = target * overloadcutoff / 100;
+ int adjoff = target + (cutoff - target)*3/4;
+ if (ocount[i] > cutoff)
+ overloaded++;
+
+ if (ocount[i] > adjoff) {
+ adjusted++;
+ c.overload[i] = (float)target / (float)ocount[i];
+ //cout << "setting overload " << i << " to " << c.overload[i] << endl;
+ //cout << "disk " << i << " has " << ocount[i] << endl;
+ }
+ ocount[i] = 0;
+ }
+ //cout << overloaded << " overloaded" << endl;
+ overloadsum += (float)overloaded / (float)ndisks;
+ adjustsum += (float)adjusted / (float)ndisks;
+
+
+
+ // keep adjusting!
+ for (int bla=0; bla<5; bla++) {
+ utime_t t2a = g_clock.now();
+
+ // second pass
+ for (int x=xs; x<numpg+xs; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ }
+
+ //cout << v << "\t" << ocount << endl;
+ }
+
+ utime_t t2b = g_clock.now();
+
+ int numover = 0;
+ for (int i=0; i<ocount.size(); i++) {
+ int target = (i/100+1)*pg_per_base;
+ int cutoff = target * overloadcutoff / 100;
+ int adjoff = cutoff;//target + (cutoff - target)*3/4;
+
+ if (ocount[i] >= adjoff) {
+ numover++;
+ if (c.overload.count(i) == 0) {
+ c.overload[i] = 1.0;
+ adjusted++;
+ }
+ //else cout << "(re)adjusting " << i << endl;
+ c.overload[i] *= (float)target / (float)ocount[i];
+ //cout << "setting overload " << i << " to " << c.overload[i] << endl;
+ //cout << "disk " << i << " has " << ocount[i] << endl;
+ }
+ ocount[i] = 0;
+ }
+ if (!numover) break;
+ cout << "readjusting" << endl;
+ }
+
+ utime_t t3a = g_clock.now();
+
+ for (int x=xs; x<numpg+xs; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ }
+
+ //cout << v << "\t" << ocount << endl;
+ }
+ xs += numpg;
+
+ utime_t t3b = g_clock.now();
+
+ t1b -= t1a;
+ double t1 = (double)t1b;
+ t3b -= t3a;
+ double t3 = (double)t3b;
+ double slowdown = t3/t1;
+ //cout << "slowdown " << slowdown << endl;
+ aslowdown += slowdown;
+
+ int still = 0;
+ for (int i=0; i<ocount.size(); i++) {
+ int target = (i/100+1)*pg_per_base;
+ int cutoff = target * overloadcutoff / 100;
+ //int adjoff = target + (cutoff - target)/3;
+
+ if (ocount[i] > cutoff) {
+ still++;
+ //c.overload[ocount[i]] = 100.0 / (float)ocount[i];
+ if (c.overload.count(i)) cout << "[adjusted] ";
+ cout << "disk " << i << " has " << ocount[i] << endl;
+ }
+ }
+ //if (still) cout << "overload was " << overloaded << " now " << still << endl;
+ afteroverloadsum += (float)still / (float)ndisks;
+
+ //cout << "collisions: " << c.collisions << endl;
+ //cout << "r bumps: " << c.bumps << endl;
+
+ int n = ndisks/10;
+ float avg[10];
+ float var[10];
+ for (int i=0;i<10;i++) {
+ int s = n*i;
+ avg[i] = 0.0;
+ for (int j=0; j<n; j++)
+ avg[i] += ocount[j+s];
+ avg[i] /= n;//ocount.size();
+ var[i] = 0.0;
+ for (int j=0; j<n; j++)
+ var[i] += (ocount[j+s] - avg[i]) * (ocount[j+s] - avg[i]);
+ var[i] /= n;//ocount.size();
+
+ tvar[i] += var[i];
+ tavg[i] += avg[i];
+ }
+ //cout << "avg " << avg << " var " << var << " sd " << sqrt(var) << endl;
+
+ tvarnum++;
+ }
+
+ overloadsum /= tvarnum;
+ adjustsum /= tvarnum;
+ float avar = 0.0;
+ for (int j=0;j<10;j++) {
+ tvar[j] /= tvarnum;
+ tavg[j] /= tvarnum;
+ avar += tvar[j];
+ }
+ avar /= 10;
+ avar = sqrt(avar);
+ avar /= 5.5 * (float)pg_per_base;
+ afteroverloadsum /= tvarnum;
+ aslowdown /= tvarnum;
+
+ //int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
+ //float crate = (float) collisions / (float)chooses;
+ //cout << "collisions: " << c.collisions << endl;
+
+
+ //cout << "total variance " << tvar << endl;
+ //cout << " overlaod " << overloadsum << endl;
+
+ cout << overloadcutoff << "\t" << utilization
+ << "\t" << overloadsum << "\t" << adjustsum << "\t" << afteroverloadsum
+ << "\t" << aslowdown << "\t" << avar << "\t-";
+
+ for (int i=0;i<10;i++)
+ cout << "\t" << tavg[i] << "\t" << tvar[i];// << "\t" << tvar[i]/tavg[i];
+ cout << endl;
+ return tvar[0];
+}
+
+
+int main()
+{
+ float var = go(3,50);
+ /* for (int d=70; d<100; d += 5) {
+ float var = go(3,d);
+ //cout << "## depth = " << d << endl;
+ //cout << d << "\t" << var << endl;
+ }*/
+ go(3,96);
+ go(3,97);
+ go(3,98);
+ go(3,99);
+
+
+}
--- /dev/null
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+ if (h == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+ for (int i=0; i<wid[h]; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 10, disks);
+ b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+ return b;
+ } else {
+ // mixed
+ MixedBucket *b = new MixedBucket(h+1);
+ for (int i=0; i<wid[h]; i++) {
+ Bucket *n = make_bucket(c, wid, h-1, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ }
+ c.add_bucket(b);
+ //cout << h << " mixedbucket with " << wid[h] << endl;
+ return b;
+ }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+ Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+ return b->get_id();
+}
+
+
+Bucket *make_random(Crush& c, int wid, int height, int& ndisks)
+{
+ int w = rand() % (wid-1) + 2;
+
+ if (height == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+ for (int i=0; i<w; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 10, disks);
+ b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+ return b;
+ } else {
+ // mixed
+ int h = rand() % height + 1;
+ MixedBucket *b = new MixedBucket(h+1);
+ for (int i=0; i<w; i++) {
+ Bucket *n = make_random(c, wid, h-1, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ }
+ c.add_bucket(b);
+ //cout << h << " mixedbucket with " << wid[h] << endl;
+ return b;
+ }
+
+}
+
+
+float go(int dep, int overloadcutoff)
+{
+ Hash h(73232313);
+
+ // crush
+ Crush c;
+
+
+ // buckets
+ int root = -1;
+ int ndisks = 0;
+
+ vector<int> wid;
+ for (int d=0; d<dep; d++)
+ wid.push_back(10);
+
+ if (1) {
+ root = make_hierarchy(c, wid, ndisks);
+ }
+ if (0) {
+ Bucket *r = make_random(c, 20, 4, ndisks);
+ root = r->get_id();
+ //c.print(cout, root);
+ }
+ if (0) {
+ MixedBucket *b = new MixedBucket(1);
+ for (int i=0; i<10000; i++)
+ b->add_item(ndisks++, 10);
+ root = c.add_bucket(b);
+ }
+ if (0) {
+ vector<int> disks;
+ for (int i=0; i<10000; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 10000, disks);
+ Hash h(123);
+ b->make_primes(h);
+ root = c.add_bucket(b);
+ }
+ //cout << ndisks << " disks" << endl;
+
+
+
+ // rule
+ int numrep = 1;
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+ //c.overload[10] = .1;
+
+
+ int pg_per = 100;
+ int numpg = pg_per*ndisks/numrep;
+
+ vector<int> ocount(ndisks);
+ //cout << ndisks << " disks, " << endl;
+ //cout << pg_per << " pgs per disk" << endl;
+ // cout << numpg << " logical pgs" << endl;
+ //cout << "numrep is " << numrep << endl;
+
+
+ int place = 1000000;
+ int times = place / numpg;
+ if (!times) times = 1;
+
+
+ //cout << "looping " << times << " times" << endl;
+
+ float tvar = 0;
+ int tvarnum = 0;
+
+ float overloadsum = 0.0;
+ float adjustsum = 0.0;
+ float afteroverloadsum = 0.0;
+ int chooses = 0;
+ int xs = 1;
+ for (int t=0; t<times; t++) {
+ vector<int> v(numrep);
+
+ c.overload.clear();
+
+ for (int z=0; z<ndisks; z++) ocount[z] = 0;
+
+ for (int x=xs; x<numpg+xs; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ chooses += numrep;
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ bool bad = false;
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
+ }
+ if (bad)
+ cout << "bad set " << x << ": " << v << endl;
+
+ //cout << v << "\t" << ocount << endl;
+ }
+
+ // overloaded?
+ int overloaded = 0;
+ int adjusted = 0;
+ for (int i=0; i<ocount.size(); i++) {
+ if (ocount[i] > overloadcutoff)
+ overloaded++;
+
+ if (ocount[i] > 100+(overloadcutoff-100)/2) {
+ adjusted++;
+ c.overload[i] = 100.0 / (float)ocount[i];
+ //cout << "disk " << i << " has " << ocount[i] << endl;
+ }
+ ocount[i] = 0;
+ }
+ //cout << overloaded << " overloaded" << endl;
+ overloadsum += (float)overloaded / (float)ndisks;
+ adjustsum += (float)adjusted / (float)ndisks;
+
+
+ for (int x=xs; x<numpg+xs; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ bool bad = false;
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
+ }
+ if (bad)
+ cout << "bad set " << x << ": " << v << endl;
+
+ //cout << v << "\t" << ocount << endl;
+ }
+ xs += numpg;
+
+ int still = 0;
+ for (int i=0; i<ocount.size(); i++) {
+ if (ocount[i] > overloadcutoff) {
+ still++;
+ //c.overload[ocount[i]] = 100.0 / (float)ocount[i];
+ //cout << "disk " << i << " has " << ocount[i] << endl;
+ }
+ }
+ //if (still) cout << "overload was " << overloaded << " now " << still << endl;
+ afteroverloadsum += (float)still / (float)ndisks;
+
+ //cout << "collisions: " << c.collisions << endl;
+ //cout << "r bumps: " << c.bumps << endl;
+
+ float avg = 0.0;
+ for (int i=0; i<ocount.size(); i++)
+ avg += ocount[i];
+ avg /= ocount.size();
+ float var = 0.0;
+ for (int i=0; i<ocount.size(); i++)
+ var += (ocount[i] - avg) * (ocount[i] - avg);
+ var /= ocount.size();
+
+ //cout << "avg " << avg << " var " << var << " sd " << sqrt(var) << endl;
+
+ tvar += var;
+ tvarnum++;
+ }
+
+ overloadsum /= tvarnum;
+ adjustsum /= tvarnum;
+ tvar /= tvarnum;
+ afteroverloadsum /= tvarnum;
+
+ int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
+ float crate = (float) collisions / (float)chooses;
+ //cout << "collisions: " << c.collisions << endl;
+
+
+ //cout << "total variance " << tvar << endl;
+ //cout << " overlaod " << overloadsum << endl;
+
+ cout << overloadcutoff << "\t" << (10000.0 / (float)overloadcutoff) << "\t" << tvar << "\t" << overloadsum << "\t" << adjustsum << "\t" << afteroverloadsum << "\t" << crate << endl;
+ return tvar;
+}
+
+
+int main()
+{
+ for (int d=140; d>100; d -= 5) {
+ float var = go(3,d);
+ //cout << "## depth = " << d << endl;
+ //cout << d << "\t" << var << endl;
+ }
+}
--- /dev/null
+
+#include "include/types.h"
+#include "include/Distribution.h"
+#include "osd/OSDMap.h"
+
+
+Distribution file_size_distn; //kb
+
+
+list<int> object_queue;
+int max_object_size = 1024*1024*100; //kb
+
+off_t no;
+
+int get_object() //kb
+{
+ if (object_queue.empty()) {
+ int max = file_size_distn.sample();
+ no++;
+ int filesize = max/2 + (rand() % 100) * max/200 + 1;
+ //cout << "file " << filesize << endl;
+ while (filesize > max_object_size) {
+ object_queue.push_back(max_object_size);
+ filesize -= max_object_size;
+ }
+ object_queue.push_back(filesize);
+ }
+ int s = object_queue.front();
+ object_queue.pop_front();
+ //cout << "object " << s << endl;
+ return s;
+}
+
+void getdist(vector<off_t>& v, float& avg, float& var)
+{
+ avg = 0.0;
+ for (int i=0; i<v.size(); i++)
+ avg += v[i];
+ avg /= v.size();
+
+ var = 0.0;
+ for (int i=0; i<v.size(); i++)
+ var += (v[i] - avg) * (v[i] - avg);
+ var /= v.size();
+}
+
+
+void testpgs(int n, // numpg
+ off_t pggb,
+ float& avg,
+ float& var,
+ off_t& numo
+ )
+{
+ off_t dist = (off_t)n * 1024LL*1024LL * (off_t)pggb; //kb
+ vector<off_t> pgs(n);
+ off_t did = 0;
+
+ no = 0;
+ while (did < dist) {
+ off_t s = get_object();
+ pgs[rand()%n] += s;
+ did += s;
+ }
+ while (!object_queue.empty())
+ pgs[rand()%n] += get_object();
+
+ numo = no;
+ //cout << did/n << endl;
+
+ //for (int i=0; i<n; i++) cout << pgs[i] << endl;
+
+ getdist(pgs, avg, var);
+ //cout << "avg " << avg << " var " << var << " dev " << sqrt(var) << endl;
+
+}
+
+
+
+int main()
+{
+ /*
+
+// File Size
+//cate count_mean size_mean
+1b -0.5 0.65434375 0
+1k 0.5 19.0758125 0.00875
+512K 1.5 35.6566 2.85875
+1M 2.5 27.7271875 25.0084375
+2M 3.5 16.63503125 20.8046875
+4M 4.5 106.82384375 296.053125
+8M 5.5 81.493375 335.77625
+16M 6.5 14.13553125 185.9775
+32M 7.5 2.176 52.921875
+256M 8.5 0.655938 47.8066
+512M 9.5 0.1480625 57.83375
+2G 10.5 0.020125 19.2888
+ */
+ file_size_distn.add(1, 19.0758125+0.65434375);
+ file_size_distn.add(512, 35.6566);
+ file_size_distn.add(1024, 27.7271875);
+ file_size_distn.add(2*1024, 16.63503125);
+ file_size_distn.add(4*1024, 106.82384375);
+ file_size_distn.add(8*1024, 81.493375);
+ file_size_distn.add(16*1024, 14.13553125);
+ file_size_distn.add(32*1024, 2.176);
+ file_size_distn.add(256*1024, 0.655938);
+ file_size_distn.add(512*1024, 0.1480625);
+ file_size_distn.add(1*1024*1024, 0.020125); // actually 2, but 32bit
+ file_size_distn.normalize();
+
+
+ for (int pggb = 1; pggb < 16; pggb++) {
+ cout << pggb;
+ for (int max = 1; max <= 1024; max *= 2) {
+ float avg, var, var2, var3;
+ off_t no;
+ max_object_size = max*1024;
+ testpgs(100, pggb, avg, var, no);
+ testpgs(100, pggb, avg, var2, no);
+ testpgs(100, pggb, avg, var3, no);
+ float dev = sqrt((var+var2+var3)/3.0);
+ cout << "\t" << no << "\t" << max << "\t" << dev;
+ }
+ cout << endl;
+ }
+
+
+
+
+}
--- /dev/null
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+ if (h == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+ for (int i=0; i<wid[h]; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+ b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+ buckets[h].push_back(b);
+ return b;
+ } else {
+ // mixed
+ Bucket *b = new TreeBucket(h+1);
+ c.add_bucket(b);
+ for (int i=0; i<wid[h]; i++) {
+ Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ n->set_parent(b->get_id());
+ }
+ buckets[h].push_back(b);
+ //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
+ return b;
+ }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+ Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
+ return b->get_id();
+}
+
+
+void place(Crush& c, Rule& rule, int numpg, int numrep, vector<int>& ocount)
+{
+ vector<int> v(numrep);
+ //map<int,int> ocount;
+
+ for (int x=1; x<=numpg; x++) {
+
+ //cout << H(x) << "\t" << h(x) << endl;
+ c.do_rule(rule, x, v);
+ //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
+
+ bool bad = false;
+ for (int i=0; i<numrep; i++) {
+ //int d = b.choose_r(x, i, h);
+ //v[i] = d;
+ ocount[v[i]]++;
+ for (int j=i+1; j<numrep; j++) {
+ if (v[i] == v[j])
+ bad = true;
+ }
+ }
+ if (bad)
+ cout << "bad set " << x << ": " << v << endl;
+
+ //placement[x] = v;
+
+ //cout << v << "\t" << ocount << endl;
+ }
+
+
+}
+
+
+int main()//float testmovement(int depth, int branching, int udisks)
+{
+ Hash h(73232313);
+
+ // crush
+ Crush c;
+
+
+ // buckets
+ int root = -1;
+ int ndisks = 0;
+
+ vector<int> wid;
+ wid.push_back(10);
+ wid.push_back(2);
+
+ map< int, list<Bucket*> > buckets;
+ root = make_hierarchy(c, wid, buckets, ndisks);
+
+ // add small bucket
+ vector<int> disks;
+ for (int i=0; i<3; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+ b->make_primes(h);
+ Bucket *o = buckets[1].back();
+ c.add_bucket(b);
+ //cout << " adding under " << o->get_id() << endl;
+ c.add_item(o->get_id(), b->get_id(), b->get_weight());
+
+
+ // rule
+ int numrep = 6;
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+ //c.overload[10] = .1;
+
+ int pg_per = 10000;
+ int numpg = pg_per*ndisks/numrep;
+
+ vector<int> ocount(ndisks);
+
+ c.print(cout, root);
+
+ place(c, rule, numpg, numrep, ocount);
+
+ for (int i=0; i<ocount.size(); i++) {
+ cout << "disk " << i << " = " << ocount[i] << endl;
+ }
+
+ return 0;
+}
+
+
--- /dev/null
+
+#include "../../common/Clock.h"
+#include "../crush.h"
+using namespace crush;
+
+
+Clock g_clock;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+int numrep = 1;
+
+
+double go(int n, int bucket)
+{
+ Hash h(73232313);
+
+ // crush
+ Crush c;
+
+
+ // buckets
+ int root = -1;
+ int ndisks = 0;
+
+ Bucket *b;
+ vector<int> items;
+ if (bucket == 0) b = new UniformBucket(1,0,10,items);
+ if (bucket == 1) b = new TreeBucket(1);
+ if (bucket == 2) b = new ListBucket(1);
+ if (bucket == 3) b = new StrawBucket(1);
+
+ for (int d=0; d<n; d++)
+ b->add_item(ndisks++, 1);
+
+ //if (!bucket) ((UniformBucket*)b)->make_primes(h);
+
+ root = c.add_bucket(b);
+
+ // rule
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+
+ int place = 1000000;
+
+
+ vector<int> v(numrep);
+ set<int> out;
+ map<int,float> overload;
+
+ utime_t start = g_clock.now();
+
+ for (int x=1; x <= place; x++)
+ c.do_rule(rule, x, v, out, overload);
+
+ utime_t end = g_clock.now();
+
+ end -= start;
+ double el = (double)end;
+
+ //cout << "\t" << ndisks;
+
+ return el;
+}
+
+
+int main()
+{
+
+ for (int n=4; n<=50; n += 4) {
+ cout << n;
+ for (int b=0; b<4; b++) {
+ double el = go(n,b);
+ cout << "\t" << el;
+ }
+ cout << endl;
+ }
+}
--- /dev/null
+
+#include "../../common/Clock.h"
+#include "../crush.h"
+using namespace crush;
+
+
+Clock g_clock;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+int uniform = 10;
+int branching = 10;
+int buckettype = 0;
+int numrep = 1;
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+ if (h == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+ for (int i=0; i<wid[h]; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 10, disks);
+ //b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+ return b;
+ } else {
+ // mixed
+ Bucket *b;
+ if (buckettype == 0)
+ b = new TreeBucket(h+1);
+ else if (buckettype == 1 || buckettype == 2)
+ b = new ListBucket(h+1);
+ else if (buckettype == 3)
+ b = new StrawBucket(h+1);
+ for (int i=0; i<wid[h]; i++) {
+ Bucket *n = make_bucket(c, wid, h-1, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ }
+ c.add_bucket(b);
+ //cout << h << " mixedbucket with " << wid[h] << endl;
+ return b;
+ }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+ Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+ return b->get_id();
+}
+
+
+double go(int dep, int per)
+{
+ Hash h(73232313);
+
+ // crush
+ Crush c;
+
+
+ // buckets
+ int root = -1;
+ int ndisks = 0;
+
+ vector<int> wid;
+ if (1) {
+ wid.push_back(uniform);
+ for (int d=1; d<dep; d++)
+ wid.push_back(per);
+ }
+ if (0) {
+ if (dep == 0)
+ wid.push_back(1000);
+ if (dep == 1) {
+ wid.push_back(1);
+ wid.push_back(1000);
+ }
+ if (dep == 2) {
+ wid.push_back(5);
+ wid.push_back(5);
+ wid.push_back(8);
+ wid.push_back(5);
+ }
+ }
+
+ if (1) {
+ root = make_hierarchy(c, wid, ndisks);
+ }
+
+
+
+ // rule
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+
+ int place = 1000000;
+
+
+ vector<int> v(numrep);
+
+ utime_t start = g_clock.now();
+
+ set<int> out;
+ map<int,float> overload;
+
+ for (int x=1; x <= place; x++)
+ c.do_rule(rule, x, v, out, overload);
+
+ utime_t end = g_clock.now();
+
+ end -= start;
+ double el = (double)end;
+
+ //cout << "\t" << ndisks;
+
+ return el;
+}
+
+
+int main()
+{
+ uniform = branching = 8;
+
+ cout << "// dep\tuniform\tbranch\tndisks" << endl;
+
+ for (int d=2; d<=5; d++) {
+ cout << d;// << "\t" << branching;
+ cout << "\t" << uniform;
+ cout << "\t" << branching;
+
+ int n = 1;
+ for (int i=0; i<d; i++)
+ n *= branching;
+ cout << "\t" << n;
+
+ numrep = 2;
+
+ // crush
+ for (buckettype = 0; buckettype <= 3; buckettype++) {
+ switch (buckettype) {
+ case 0: cout << "\ttree"; break;
+ case 1: cout << "\tlist"; break;
+ case 2: continue;
+ case 3: cout << "\tstraw"; break;
+ }
+
+ //for (numrep = 1; numrep <= 3; numrep++) {
+ //cout << "\t" << numrep;
+
+ double el = go(d, branching);
+ cout << "\t" << el;
+ }
+
+ // rush
+
+ buckettype = 0;
+ cout << "\trush_T\t" << go(2, n/uniform);
+
+ buckettype = 1;
+ cout << "\trush_P\t" << go(2, n/uniform);
+
+ cout << endl;
+ }
+}
--- /dev/null
+
+#include "../../common/Clock.h"
+#include "../crush.h"
+using namespace crush;
+
+
+Clock g_clock;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+int branching = 10;
+bool linear = false;
+int numrep = 1;
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+ if (h == 0) {
+ // uniform
+ Hash hash(123);
+ vector<int> disks;
+ for (int i=0; i<wid[h]; i++)
+ disks.push_back(ndisks++);
+ UniformBucket *b = new UniformBucket(1, 0, 10, disks);
+ //b->make_primes(hash);
+ c.add_bucket(b);
+ //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+ return b;
+ } else {
+ // mixed
+ Bucket *b;
+ if (linear)
+ b = new ListBucket(h+1);
+ else
+ b = new TreeBucket(h+1);
+ for (int i=0; i<wid[h]; i++) {
+ Bucket *n = make_bucket(c, wid, h-1, ndisks);
+ b->add_item(n->get_id(), n->get_weight());
+ }
+ c.add_bucket(b);
+ //cout << h << " mixedbucket with " << wid[h] << endl;
+ return b;
+ }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+ Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+ return b->get_id();
+}
+
+
+double go(int s)
+{
+ int dep = 2;
+ Hash h(73232313);
+
+ // crush
+ Crush c;
+
+
+ // buckets
+ int root = -1;
+ int ndisks = 0;
+
+ vector<int> wid;
+ if (1) {
+ //for (int d=0; d<dep; d++)
+ wid.push_back(8);
+ wid.push_back(s/8);
+ }
+ if (0) {
+ if (dep == 0)
+ wid.push_back(1000);
+ if (dep == 1) {
+ wid.push_back(1);
+ wid.push_back(1000);
+ }
+ if (dep == 2) {
+ wid.push_back(5);
+ wid.push_back(5);
+ wid.push_back(8);
+ wid.push_back(5);
+ }
+ }
+
+ if (1) {
+ root = make_hierarchy(c, wid, ndisks);
+ }
+
+
+
+ // rule
+ Rule rule;
+ rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+ rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+
+ int place = 1000000;
+
+
+ vector<int> v(numrep);
+
+ utime_t start = g_clock.now();
+
+ for (int x=1; x <= place; x++)
+ c.do_rule(rule, x, v);
+
+ utime_t end = g_clock.now();
+
+ end -= start;
+ double el = (double)end;
+
+ cout << "\t" << ndisks;
+
+ return el;
+}
+
+
+int main()
+{
+ branching = 8;
+
+ int d = 2;
+ numrep = 2;
+
+ for (int s = 64; s <= 32768; s *= 8) {
+ cout << "t";
+ linear = false;
+ double el = go(s, d);
+ cout << "\t" << el;
+
+ cout << "\tp";
+ linear = true;
+ el = go(s, d);
+ cout << "\t" << el;
+
+ cout << endl;
+ }
+}
--- /dev/null
+
+#include "../../common/Clock.h"
+#include "../crush.h"
+using namespace crush;
+
+
+Clock g_clock;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+int branching = 10;
+bool linear = false;
+int numrep = 1;
+
+int main() {
+
+ Bucket *b = new UniformBucket(1, 0);
+ //b = new TreeBucket(1);
+}
+
--- /dev/null
+
+
+#include "../Bucket.h"
+using namespace crush;
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+ostream& operator<<(ostream& out, vector<int>& v)
+{
+ out << "[";
+ for (int i=0; i<v.size(); i++) {
+ if (i) out << " ";
+ out << v[i];
+ }
+ out << "]";
+ return out;
+}
+
+
+int main()
+{
+ Hash h(73);
+
+ int ndisks = 0;
+ int numrep = 3;
+
+ StrawBucket mb(1);
+ /*for (int i=0;i<10;i++)
+ mb.add_item(ndisks++, 10);
+ */
+ mb.add_item(ndisks++, 1);
+ mb.add_item(ndisks++, 1);
+ mb.add_item(ndisks++, 10);
+ mb.add_item(ndisks++, 10);
+ mb.add_item(ndisks++, 100);
+ mb.add_item(ndisks++, 1000);
+
+ vector<int> ocount(ndisks);
+
+ vector<int> v(numrep);
+ int nplace = 0;
+ for (int x=1; x<1000000; x++) {
+ //cout << H(x) << "\t" << h(x) << endl;
+ for (int i=0; i<numrep; i++) {
+ int d = mb.choose_r(x, i, h);
+ v[i] = d;
+ ocount[d]++;
+ nplace++;
+ }
+ //cout << v << "\t" << endl;//ocount << endl;
+ }
+
+ for (int i=0; i<ocount.size(); i++) {
+ float f = ocount[i] / (float)nplace;
+ cout << "disk " << i << " has " << ocount[i] << " " << f << endl;
+ }
+
+}
--- /dev/null
+
+#include <vector>
+#include <iostream>
+using namespace std;
+
+
+void getdist(vector<int>& v, float& avg, float& var)
+{
+ avg = 0.0;
+ for (int i=0; i<v.size(); i++)
+ avg += v[i];
+ avg /= v.size();
+
+ var = 0.0;
+ for (int i=0; i<v.size(); i++)
+ var += (v[i] - avg) * (v[i] - avg);
+ var /= v.size();
+}
+
+int main()
+{
+ int n = 50;
+ vector<int> a(n);
+ vector<int> b(n);
+
+ for (int i=0; i<n*n; i++)
+ a[rand()%n]++;
+
+ float aavg, avar;
+ getdist(a, aavg, avar);
+
+ for (int i=0; i<7*n*n; i++)
+ b[rand()%n]++;
+
+ float bavg, bvar;
+ getdist(b, bavg, bvar);
+
+ cout << "a avg " << aavg << " var " << avar << endl;
+ cout << "b avg " << bavg << " var " << bvar << endl;
+
+
+ vector<int> c(n);
+ for (int i=0; i<n; i++)
+ c[i] = a[i] * b[i];
+
+ float cavg, cvar;
+ getdist(c, cavg, cvar);
+
+ cout << "c avg " << cavg << " var " << cvar << endl;
+
+}
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation. See file COPYING.
- *
- */
-
-#ifndef __crush_BINARYTREE_H
-#define __crush_BINARYTREE_H
-
-#include <cassert>
-#include <iostream>
-#include <map>
-#include <vector>
-using std::map;
-using std::vector;
-
-#include "include/buffer.h"
-
-namespace crush {
-
- class BinaryTree {
- private:
- // tree def
- int root_node; // 0 for empty tree.
- int alloc;
- vector<int> node_nested; // all existing nodes in this map
- vector<float> node_weight; // and this one
- vector<int> node_complete; // only nodes with all possible children
-
- public:
- BinaryTree() : root_node(0), alloc(0) {}
-
- void _encode(bufferlist& bl) {
- bl.append((char*)&root_node, sizeof(root_node));
- bl.append((char*)&alloc, sizeof(alloc));
- ::_encode(node_nested, bl);
- ::_encode(node_weight, bl);
- ::_encode(node_complete, bl);
- }
- void _decode(bufferlist& bl, int& off) {
- bl.copy(off, sizeof(root_node), (char*)&root_node);
- off += sizeof(root_node);
- bl.copy(off, sizeof(alloc), (char*)&alloc);
- off += sizeof(alloc);
- ::_decode(node_nested, bl, off);
- ::_decode(node_weight, bl, off);
- ::_decode(node_complete, bl, off);
- }
-
- // accessors
- bool empty() const { return root_node == 0; }
- bool exists(int n) const { return n < alloc && node_nested[n]; }
- int nested(int n) const { return exists(n) ? node_nested[n]:0; }
- float weight(int n) const { return exists(n) ? node_weight[n]:0; }
- bool complete(int n) const { return exists(n) ? node_complete[n]:false; }
-
- int root() const { return root_node; }
-
- void realloc(int n) {
- /*
- while (alloc <= n) {
- node_nested.push_back(0);
- node_weight.push_back(0);
- node_complete.push_back(0);
- alloc++;
- }
- */
- if (alloc <= n) {
- int add = n - alloc + 1;
- node_nested.insert(node_nested.end(), add, 0);
- node_weight.insert(node_weight.end(), add, 0);
- node_complete.insert(node_complete.end(), add, 0);
- alloc = n+1;
- }
- }
-
- // tree navigation
- bool terminal(int n) const { return n & 1; } // odd nodes are leaves.
- int height(int n) const {
- assert(n);
- int h = 0;
- while ((n & 1) == 0) {
- assert(n > 0);
- h++; n = n >> 1;
- }
- return h;
- }
- int left(int n) const {
- int h = height(n);
- //cout << "left of " << n << " is " << (n - (1 << h)) << std::endl;
- return n - (1 << (h-1));
- }
- int right(int n) const {
- int h = height(n);
- //cout << "right of " << n << " is " << (n + (1 << h)) << std::endl;
- return n + (1 << (h-1));
- }
- bool on_right(int n, int h = -1) const {
- if (h < 0) h = height(n);
- return n & (1 << (h+1));
- }
- bool on_left(int n) const { return !on_right(n); }
- int parent(int n) const {
- int h = height(n);
- if (on_right(n, h))
- return n - (1<<h);
- else
- return n + (1<<h);
- }
-
- // modifiers
- void adjust_node_weight(int n, float w) {
- assert(exists(n));
- node_weight[n] += w;
-
- int p = n;
- while (p != root_node) {
- p = parent(p);
- node_weight[p] += w;
- }
- }
-
- void remove_node(int n) {
- assert(exists(n));
-
- // erase node
- node_nested[n] = 0;
- node_weight[n] = 0;
-
- // adjust parents (!complete, -weight)
- int p = n;
- while (p != root_node) {
- p = parent(p);
-
- node_complete[p] = 0;
- node_weight[p] = weight(left(p)) + weight(right(p));
- node_nested[p]--;
-
- if (nested(p) == 0) {
- node_weight[p] = 0;
- node_nested[p] = 0;
- }
- }
-
- // hose root?
- while (!terminal(root_node) &&
- (nested(left(root_node)) == 0 ||
- nested(right(root_node)) == 0)) {
- // root now one child..
- node_weight[root_node] = 0;
- node_nested[root_node] = 0;
- if (nested(left(root_node)) == 0)
- root_node = right(root_node);
- else
- root_node = left(root_node);
- }
-
- if (terminal(root_node) &&
- nested(root_node) == 0) {
- // empty!
- node_weight[root_node] = 0;
- node_nested[root_node] = 0;
- root_node = 0;
- }
-
- }
-
- int add_node_root(float w) {
- return add_node(w, true);
- }
-
- int add_node(float w, bool force_root=false) {
- int n;
- if (!root_node) {
- // empty tree!
- root_node = n = 1;
- } else {
- // existing tree.
- // expand tree?
- if (force_root || complete(root_node)) {
- // add new root
- int newroot = parent(root_node);
- realloc(newroot);
- node_weight[newroot] = node_weight[root_node];
- node_nested[newroot] = nested(root_node);
-
- // go right or left?
- if (left(newroot) == root_node)
- n = right(newroot);
- else
- n = left(newroot);
- root_node = newroot;
-
- // then go left until terminal
- while (!terminal(n))
- n = left(n);
- }
- else {
- // tree isn't complete.
- n = root_node;
- while (!terminal(n)) {
- if (!exists(left(n)) || !complete(left(n))) {
- // left isn't complete
- n = left(n);
- } else {
- assert(!exists(right(n)) || !complete(right(n)));
- // right isn't complete
- n = right(n);
- }
- }
- }
- }
-
- // create at n
- //cout << "creating " << n << std::endl;
- realloc(n);
- node_weight[n] = w;
- node_nested[n] = 1;
- node_complete[n] = 1;
-
- // ancestors: create, adjust weight, complete as appropriate
- int p = n;
- while (p != root_node) {
- p = parent(p);
- realloc(p);
-
- // complete?
- if (!complete(p) &&
- complete(left(p)) &&
- complete(right(p)))
- node_complete[p] = 1;
-
- // weight (and implicitly create)
- node_weight[p] += w;
- node_nested[p]++;
- }
-
- return n;
-
- }
-
-
- };
-
-
- // print it out
- inline void print_binary_tree_node(ostream& out, const BinaryTree& tree, int n, int i) {
- for (int t=i; t>0; t--) out << " ";
- if (tree.root() == n)
- out << "root ";
- else {
- if (tree.on_left(n))
- out << "left ";
- else
- out << "right ";
- }
- out << n << " : nested " << tree.nested(n) << " weight " << tree.weight(n);
- if (tree.complete(n)) out << " complete";
- out << std::endl;
- if (!tree.terminal(n)) {
- if (tree.exists(tree.left(n)))
- print_binary_tree_node(out, tree, tree.left(n), i+2);
- if (tree.exists(tree.right(n)))
- print_binary_tree_node(out, tree, tree.right(n), i+2);
- }
- }
-
- inline ostream& operator<<(ostream& out, const BinaryTree& tree) {
- if (tree.empty())
- return out << "tree is empty";
- print_binary_tree_node(out, tree, tree.root(), 0);
- return out;
- }
-
-}
-
-#endif
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation. See file COPYING.
- *
- */
-
-#ifndef __crush_BUCKET_H
-#define __crush_BUCKET_H
-
-#include "BinaryTree.h"
-#include "Hash.h"
-
-#include <list>
-#include <vector>
-#include <map>
-#include <set>
-using namespace std;
-
-#include <math.h>
-
-#include "include/buffer.h"
-
-namespace crush {
-
-
- const int CRUSH_BUCKET_UNIFORM = 1;
- const int CRUSH_BUCKET_TREE = 2;
- const int CRUSH_BUCKET_LIST = 3;
- const int CRUSH_BUCKET_STRAW = 4;
-
- /** abstract bucket **/
- class Bucket {
- protected:
- int id;
- int parent;
- int type;
- float weight;
-
- public:
- Bucket(int _type,
- float _weight) :
- id(0), parent(0),
- type(_type),
- weight(_weight) { }
-
- Bucket(bufferlist& bl, int& off) {
- bl.copy(off, sizeof(id), (char*)&id);
- off += sizeof(id);
- bl.copy(off, sizeof(parent), (char*)&parent);
- off += sizeof(parent);
- bl.copy(off, sizeof(type), (char*)&type);
- off += sizeof(type);
- bl.copy(off, sizeof(weight), (char*)&weight);
- off += sizeof(weight);
- }
-
- virtual ~Bucket() { }
-
- virtual const char *get_bucket_type() const = 0;
- virtual bool is_uniform() const = 0;
-
- int get_id() const { return id; }
- int get_type() const { return type; }
- float get_weight() const { return weight; }
- int get_parent() const { return parent; }
- virtual int get_size() const = 0;
-
- void set_id(int i) { id = i; }
- void set_parent(int p) { parent = p; }
- void set_weight(float w) { weight = w; }
-
- virtual void get_items(vector<int>& i) const = 0;
- virtual float get_item_weight(int item) const = 0;
- virtual void add_item(int item, float w, bool back=false) = 0;
- virtual void adjust_item_weight(int item, float w) = 0;
- virtual void set_item_weight(int item, float w) {
- adjust_item_weight(item, w - get_item_weight(item));
- }
-
- virtual int choose_r(int x, int r, Hash& h) const = 0;
-
- virtual void _encode(bufferlist& bl) = 0;
- };
-
-
-
-
- /** uniform bucket **/
- class UniformBucket : public Bucket {
- protected:
- public:
- vector<int> items;
- int item_type;
- float item_weight;
-
- // primes
- vector<unsigned> primes;
-
- int get_prime(int j) const {
- return primes[ j % primes.size() ];
- }
- void make_primes() {
- if (items.empty()) return;
-
- //cout << "make_primes " << get_id() << " " << items.size() << endl;
- Hash h(123+get_id());
- primes.clear();
-
- // start with odd number > num_items
- unsigned x = items.size() + 1; // this is the minimum!
- x += h(items.size()) % (3*items.size()); // bump it up some
- x |= 1; // make it odd
-
- while (primes.size() < items.size()) {
- unsigned j;
- for (j=2; j*j<=x; j++)
- if (x % j == 0) break;
- if (j*j > x) {
- primes.push_back(x);
- //cout << "prime " << x << endl;
- }
- x += 2;
- }
- }
-
- public:
- UniformBucket(int _type, int _item_type) :
- Bucket(_type, 0),
- item_type(_item_type) { }
- UniformBucket(int _type, int _item_type,
- float _item_weight, vector<int>& _items) :
- Bucket(_type, _item_weight*_items.size()),
- item_type(_item_type),
- item_weight(_item_weight) {
- items = _items;
- make_primes();
- }
-
- UniformBucket(bufferlist& bl, int& off) : Bucket(bl, off) {
- bl.copy(off, sizeof(item_type), (char*)&item_type);
- off += sizeof(item_type);
- bl.copy(off, sizeof(item_weight), (char*)&item_weight);
- off += sizeof(item_weight);
- ::_decode(items, bl, off);
- make_primes();
- }
-
- void _encode(bufferlist& bl) {
- char t = CRUSH_BUCKET_UNIFORM;
- bl.append((char*)&t, sizeof(t));
- bl.append((char*)&id, sizeof(id));
- bl.append((char*)&parent, sizeof(parent));
- bl.append((char*)&type, sizeof(type));
- bl.append((char*)&weight, sizeof(weight));
-
- bl.append((char*)&item_type, sizeof(item_type));
- bl.append((char*)&item_weight, sizeof(item_weight));
-
- ::_encode(items, bl);
- }
-
- const char *get_bucket_type() const { return "uniform"; }
- bool is_uniform() const { return true; }
-
- int get_size() const { return items.size(); }
-
- // items
- void get_items(vector<int>& i) const {
- i = items;
- }
- int get_item_type() const { return item_type; }
- float get_item_weight(int item) const { return item_weight; }
-
- void add_item(int item, float w, bool back=false) {
- if (items.empty())
- item_weight = w;
- items.push_back(item);
- weight += item_weight;
- make_primes();
- }
-
- void adjust_item_weight(int item, float w) {
- assert(0);
- }
-
- int choose_r(int x, int r, Hash& hash) const {
- //cout << "uniformbucket.choose_r(" << x << ", " << r << ")" << endl;
- //if (r >= get_size()) cout << "warning: r " << r << " >= " << get_size() << " uniformbucket.size" << endl;
-
- unsigned v = hash(x, get_id());// % get_size();
- unsigned p = get_prime( hash(get_id(), x) ); // choose a prime based on hash(x, get_id(), 2)
- unsigned s = (x + v + (r+1)*p) % get_size();
- return items[s];
- }
-
- };
-
-
-
-
-
- // list bucket.. RUSH_P sorta
-
- class ListBucket : public Bucket {
- protected:
- list<int> items;
- list<float> item_weight;
- list<float> sum_weight;
-
- public:
- ListBucket(int _type) : Bucket(_type, 0) { }
-
- ListBucket(bufferlist& bl, int& off) : Bucket(bl, off) {
- ::_decode(items, bl, off);
- ::_decode(item_weight, bl, off);
- ::_decode(sum_weight, bl, off);
- }
-
- void _encode(bufferlist& bl) {
- char t = CRUSH_BUCKET_LIST;
- bl.append((char*)&t, sizeof(t));
- bl.append((char*)&id, sizeof(id));
- bl.append((char*)&parent, sizeof(parent));
- bl.append((char*)&type, sizeof(type));
- bl.append((char*)&weight, sizeof(weight));
-
- ::_encode(items, bl);
- ::_encode(item_weight, bl);
- ::_encode(sum_weight, bl);
- }
-
- const char *get_bucket_type() const { return "list"; }
- bool is_uniform() const { return false; }
-
- int get_size() const { return items.size(); }
-
- void get_items(vector<int>& i) const {
- for (list<int>::const_iterator it = items.begin();
- it != items.end();
- it++)
- i.push_back(*it);
- }
- float get_item_weight(int item) const {
- list<int>::const_iterator i = items.begin();
- list<float>::const_iterator w = item_weight.begin();
- while (i != items.end()) {
- if (*i == item) return *w;
- i++; w++;
- }
- assert(0);
- return 0;
- }
-
- void add_item(int item, float w, bool back=false) {
- if (back) {
- items.push_back(item);
- item_weight.push_back(w);
- sum_weight.clear();
- float s = 0.0;
- for (list<float>::reverse_iterator i = item_weight.rbegin();
- i != item_weight.rend();
- i++) {
- s += *i;
- sum_weight.push_front(s);
- }
- weight += w;
- assert(weight == s);
- } else {
- items.push_front(item);
- item_weight.push_front(w);
- weight += w;
- sum_weight.push_front(weight);
- }
- }
-
- void adjust_item_weight(int item, float dw) {
- // find it
- list<int>::iterator p = items.begin();
- list<float>::iterator pw = item_weight.begin();
- list<float>::iterator ps = sum_weight.begin();
-
- while (*p != item) {
- *ps += dw;
- p++; pw++; ps++; // next!
- assert(p != items.end());
- }
-
- assert(*p == item);
- *pw += dw;
- *ps += dw;
- }
-
-
- int choose_r(int x, int r, Hash& h) const {
- //cout << "linearbucket.choose_r(" << x << ", " << r << ")" << endl;
-
- list<int>::const_iterator p = items.begin();
- list<float>::const_iterator pw = item_weight.begin();
- list<float>::const_iterator ps = sum_weight.begin();
-
- while (p != items.end()) {
- const int item = *p;
- const float iw = *pw;
- const float tw = *ps;
- const float f = (float)(h(x, item, r, get_id()) % 10000) * tw / 10000.0;
- //cout << "item " << item << " iw = " << iw << " tw = " << tw << " f = " << f << endl;
- if (f < iw) {
- //cout << "linearbucket.choose_r(" << x << ", " << r << ") = " << item << endl;
- return item;
- }
- p++; pw++; ps++; // next!
- }
- assert(0);
- return 0;
- }
-
-
- };
-
-
-
-
- // mixed bucket, based on RUSH_T type binary tree
-
- class TreeBucket : public Bucket {
- protected:
- //vector<float> item_weight;
-
- // public:
- BinaryTree tree;
- map<int,int> node_item; // node id -> item
- vector<int> node_item_vec; // fast version of above
- map<int,int> item_node; // item -> node id
- map<int,float> item_weight;
-
- public:
- TreeBucket(int _type) : Bucket(_type, 0) { }
-
- TreeBucket(bufferlist& bl, int& off) : Bucket(bl, off) {
- tree._decode(bl, off);
-
- ::_decode(node_item, bl, off);
- ::_decode(node_item_vec, bl, off);
- ::_decode(item_node, bl, off);
- ::_decode(item_weight, bl, off);
- }
-
- void _encode(bufferlist& bl) {
- char t = CRUSH_BUCKET_TREE;
- bl.append((char*)&t, sizeof(t));
- bl.append((char*)&id, sizeof(id));
- bl.append((char*)&parent, sizeof(parent));
- bl.append((char*)&type, sizeof(type));
- bl.append((char*)&weight, sizeof(weight));
-
- tree._encode(bl);
-
- ::_encode(node_item, bl);
- ::_encode(node_item_vec, bl);
- ::_encode(item_node, bl);
- ::_encode(item_weight, bl);
- }
-
- const char *get_bucket_type() const { return "tree"; }
- bool is_uniform() const { return false; }
-
- int get_size() const { return node_item.size(); }
-
- // items
- void get_items(vector<int>& i) const {
- for (map<int,int>::const_iterator it = node_item.begin();
- it != node_item.end();
- it++)
- i.push_back(it->second);
- }
- float get_item_weight(int i) const {
- assert(item_weight.count(i));
- return ((map<int,float>)item_weight)[i];
- }
-
-
- void add_item(int item, float w, bool back=false) {
- item_weight[item] = w;
- weight += w;
-
- unsigned n = tree.add_node(w);
- node_item[n] = item;
- item_node[item] = n;
-
- while (node_item_vec.size() <= n)
- node_item_vec.push_back(0);
- node_item_vec[n] = item;
- }
-
- void adjust_item_weight(int item, float dw) {
- // adjust my weight
- weight += dw;
- item_weight[item] += dw;
-
- // adjust tree weights
- tree.adjust_node_weight(item_node[item], dw);
- }
-
- int choose_r(int x, int r, Hash& h) const {
- //cout << "mixedbucket.choose_r(" << x << ", " << r << ")" << endl;
- int n = tree.root();
- while (!tree.terminal(n)) {
- // pick a point in [0,w)
- float w = tree.weight(n);
- float f = (float)(h(x, n, r, get_id()) % 10000) * w / 10000.0;
-
- // left or right?
- int l = tree.left(n);
- if (tree.exists(l) &&
- f < tree.weight(l))
- n = l;
- else
- n = tree.right(n);
- }
- //assert(node_item.count(n));
- //return ((map<int,int>)node_item)[n];
- return node_item_vec[n];
- }
- };
-
-
-
-
-
- // straw bucket.. new thing!
-
- class StrawBucket : public Bucket {
- protected:
- map<int, float> item_weight;
- map<int, float> item_straw;
-
- list<int> _items;
- list<float> _straws;
-
- public:
- StrawBucket(int _type) : Bucket(_type, 0) { }
-
- StrawBucket(bufferlist& bl, int& off) : Bucket(bl, off) {
- ::_decode(item_weight, bl, off);
- calc_straws();
- }
-
- void _encode(bufferlist& bl) {
- char t = CRUSH_BUCKET_TREE;
- bl.append((char*)&t, sizeof(t));
- bl.append((char*)&id, sizeof(id));
- bl.append((char*)&parent, sizeof(parent));
- bl.append((char*)&type, sizeof(type));
- bl.append((char*)&weight, sizeof(weight));
-
- ::_encode(item_weight, bl);
- }
-
- const char *get_bucket_type() const { return "straw"; }
- bool is_uniform() const { return false; }
-
- int get_size() const { return item_weight.size(); }
-
-
- // items
- void get_items(vector<int>& i) const {
- for (map<int,float>::const_iterator it = item_weight.begin();
- it != item_weight.end();
- it++)
- i.push_back(it->first);
- }
- float get_item_weight(int item) const {
- assert(item_weight.count(item));
- return ((map<int,float>)item_weight)[item];
- }
-
- void add_item(int item, float w, bool back=false) {
- item_weight[item] = w;
- weight += w;
- calc_straws();
- }
-
- void adjust_item_weight(int item, float dw) {
- //cout << "adjust " << item << " " << dw << endl;
- weight += dw;
- item_weight[item] += dw;
- calc_straws();
- }
-
-
- /* calculate straw lengths.
- this is kind of ugly. not sure if there's a closed form way to calculate this or not!
- */
- void calc_straws() {
- //cout << get_id() << ": calc_straws ============" << endl;
-
- item_straw.clear();
- _items.clear();
- _straws.clear();
-
- // reverse sort by weight; skip zero weight items
- map<float, set<int> > reverse;
- for (map<int, float>::iterator p = item_weight.begin();
- p != item_weight.end();
- p++) {
- //cout << get_id() << ":" << p->first << " " << p->second << endl;
- if (p->second > 0) {
- //p->second /= minw;
- reverse[p->second].insert(p->first);
- }
- }
-
- /* 1:2:7
- item_straw[0] = 1.0;
- item_straw[1] = item_straw[0]*sqrt(1.0/.6);
- item_straw[2] = item_straw[1]*2.0;
- */
-
- // work from low to high weights
- float straw = 1.0;
- float numleft = item_weight.size();
- float wbelow = 0.0;
- float lastw = 0.0;
-
- map<float, set<int> >::iterator next = reverse.begin();
- //while (next != reverse.end()) {
- while (1) {
- //cout << "hi " << next->first << endl;
- map<float, set<int> >::iterator cur = next;
-
- // set straw length for this set
- for (set<int>::iterator s = cur->second.begin();
- s != cur->second.end();
- s++) {
- item_straw[*s] = straw;
- //cout << "straw " << *s << " w " << item_weight[*s] << " -> " << straw << endl;
- _items.push_back(*s);
- _straws.push_back(straw);
- }
-
- next++;
- if (next == reverse.end()) break;
-
- wbelow += (cur->first-lastw) * numleft;
- //cout << "wbelow " << wbelow << endl;
-
- numleft -= 1.0 * (float)cur->second.size();
- //cout << "numleft now " << numleft << endl;
-
- float wnext = numleft * (next->first - cur->first);
- //cout << "wnext " << wnext << endl;
-
- float pbelow = wbelow / (wbelow+wnext);
- //cout << "pbelow " << pbelow << endl;
-
- straw *= pow((double)(1.0/pbelow), (double)1.0/numleft);
-
- lastw = cur->first;
- }
- //cout << "============" << endl;
- }
-
- int choose_r(int x, int r, Hash& h) const {
- //cout << "strawbucket.choose_r(" << x << ", " << r << ")" << endl;
-
- float high_draw = -1;
- int high = 0;
-
- list<int>::const_iterator pi = _items.begin();
- list<float>::const_iterator ps = _straws.begin();
- while (pi != _items.end()) {
- const int item = *pi;
- const float rnd = (float)(h(x, item, r) % 1000000) / 1000000.0;
- const float straw = *ps * rnd;
-
- if (high_draw < 0 ||
- straw > high_draw) {
- high = *pi;
- high_draw = straw;
- }
-
- pi++;
- ps++;
- }
- return high;
- }
- };
-
-
-
-
-
- inline Bucket* decode_bucket(bufferlist& bl, int& off) {
- char t;
- bl.copy(off, sizeof(t), (char*)&t);
- off += sizeof(t);
-
- switch (t) {
- case CRUSH_BUCKET_UNIFORM:
- return new UniformBucket(bl, off);
- case CRUSH_BUCKET_LIST:
- return new ListBucket(bl, off);
- case CRUSH_BUCKET_TREE:
- return new TreeBucket(bl, off);
- case CRUSH_BUCKET_STRAW:
- return new StrawBucket(bl, off);
- default:
- assert(0);
- }
- return 0;
- }
-
-
-
-}
-
-
-
-
-
-
-
-
-#endif
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef __CRUSH_WRAPPER_H
+#define __CRUSH_WRAPPER_H
+
+#include "crush.h"
+#include "hash.h"
+#include "mapper.h"
+#include "builder.h"
+
+#include "include/encodable.h"
+
+#include <map>
+#include <set>
+
+class CrushWrapper {
+public:
+ struct crush_map *map;
+
+ CrushWrapper() : map(0) {}
+ ~CrushWrapper() {
+ if (map) crush_destroy(map);
+ }
+
+ void create() {
+ if (map) crush_destroy(map);
+ map = crush_create();
+ }
+ void finalize() {
+ assert(map);
+ crush_finalize(map);
+ }
+
+ void update_offload_map(std::set<int32_t>& out_osds,
+ std::map<int32_t,float>& overload_osds) {
+ for (int i=0; i<map->max_devices; i++) {
+ if (out_osds.count(i))
+ map->device_offload[i] = 0x10000;
+ else if (overload_osds.count(i))
+ map->device_offload[i] = (int)(0x10000 * overload_osds[i]); // FIXME: reverse?
+ else
+ map->device_offload[i] = 0; // normal.
+ }
+ }
+
+ void do_rule(int rule, int x, vector<int>& out, int maxout, int forcefeed) {
+ int rawout[maxout];
+
+ int numrep = crush_do_rule(map, rule, x, rawout, maxout, forcefeed);
+
+ out.resize(numrep);
+ for (int i=0; i<numrep; i++)
+ out[i] = rawout[i];
+ }
+
+ void _encode(bufferlist &bl) {
+ ::_encode_simple(map->max_buckets, bl);
+ ::_encode_simple(map->max_rules, bl);
+ ::_encode_simple(map->max_devices, bl);
+
+ // simple arrays
+ bl.append((char*)map->device_offload, sizeof(map->device_offload[0]) * map->max_devices);
+
+ // buckets
+ for (unsigned i=0; i<map->max_buckets; i++) {
+ __u32 type = 0;
+ if (map->buckets[i]) type = map->buckets[i]->bucket_type;
+ ::_encode_simple(type, bl);
+ if (!type) continue;
+
+ ::_encode_simple(map->buckets[i]->id, bl);
+ ::_encode_simple(map->buckets[i]->type, bl);
+ ::_encode_simple(map->buckets[i]->bucket_type, bl);
+ ::_encode_simple(map->buckets[i]->weight, bl);
+ ::_encode_simple(map->buckets[i]->size, bl);
+ for (unsigned j=0; j<map->buckets[i]->size; j++)
+ ::_encode_simple(map->buckets[i]->items[j], bl);
+
+ switch (map->buckets[i]->type) {
+ case CRUSH_BUCKET_UNIFORM:
+ for (unsigned j=0; j<map->buckets[i]->size; j++)
+ ::_encode_simple(((crush_bucket_uniform*)map->buckets[i])->primes[j], bl);
+ ::_encode_simple(((crush_bucket_uniform*)map->buckets[i])->item_weight, bl);
+ break;
+
+ case CRUSH_BUCKET_LIST:
+ for (unsigned j=0; j<map->buckets[i]->size; j++) {
+ ::_encode_simple(((crush_bucket_list*)map->buckets[i])->item_weights[j], bl);
+ ::_encode_simple(((crush_bucket_list*)map->buckets[i])->sum_weights[j], bl);
+ }
+ break;
+
+ case CRUSH_BUCKET_TREE:
+ for (unsigned j=0; j<map->buckets[i]->size; j++)
+ ::_encode_simple(((crush_bucket_tree*)map->buckets[i])->node_weights[j], bl);
+ break;
+
+ case CRUSH_BUCKET_STRAW:
+ for (unsigned j=0; j<map->buckets[i]->size; j++)
+ ::_encode_simple(((crush_bucket_straw*)map->buckets[i])->straws[j], bl);
+ break;
+ }
+ }
+
+ // rules
+ for (unsigned i=0; i<map->max_rules; i++) {
+ __u32 yes = map->rules[i] ? 1:0;
+ ::_encode_simple(yes, bl);
+ if (!yes) continue;
+
+ ::_encode_simple(map->rules[i]->len, bl);
+ for (unsigned j=0; j<map->rules[i]->len; j++)
+ ::_encode_simple(map->rules[i]->steps[j], bl);
+ }
+ }
+
+ void _decode(bufferlist::iterator &blp) {
+ create();
+ ::_decode_simple(map->max_buckets, blp);
+ ::_decode_simple(map->max_rules, blp);
+ ::_decode_simple(map->max_devices, blp);
+
+ map->device_offload = (__u32*)malloc(sizeof(map->device_offload[0])*map->max_devices);
+ blp.copy(sizeof(map->device_offload[0])*map->max_devices, (char*)map->device_offload);
+
+ // buckets
+ map->buckets = (crush_bucket**)malloc(sizeof(crush_bucket*)*map->max_buckets);
+ for (unsigned i=0; i<map->max_buckets; i++) {
+ __u32 type;
+ ::_decode_simple(type, blp);
+ if (!type) {
+ map->buckets[i] = 0;
+ continue;
+ }
+
+ int size = 0;
+ switch (type) {
+ case CRUSH_BUCKET_UNIFORM:
+ size = sizeof(crush_bucket_uniform);
+ break;
+ case CRUSH_BUCKET_LIST:
+ size = sizeof(crush_bucket_list);
+ break;
+ case CRUSH_BUCKET_TREE:
+ size = sizeof(crush_bucket_tree);
+ break;
+ case CRUSH_BUCKET_STRAW:
+ size = sizeof(crush_bucket_straw);
+ break;
+ default:
+ assert(0);
+ }
+ map->buckets[i] = (crush_bucket*)malloc(size);
+ memset(map->buckets[i], 0, size);
+
+ ::_decode_simple(map->buckets[i]->id, blp);
+ ::_decode_simple(map->buckets[i]->type, blp);
+ ::_decode_simple(map->buckets[i]->bucket_type, blp);
+ ::_decode_simple(map->buckets[i]->weight, blp);
+ ::_decode_simple(map->buckets[i]->size, blp);
+
+ map->buckets[i]->items = (__s32*)malloc(sizeof(__s32)*map->buckets[i]->size);
+ for (unsigned j=0; j<map->buckets[i]->size; j++)
+ ::_decode_simple(map->buckets[i]->items[j], blp);
+
+ switch (map->buckets[i]->type) {
+ case CRUSH_BUCKET_UNIFORM:
+ ((crush_bucket_uniform*)map->buckets[i])->primes =
+ (__u32*)malloc(map->buckets[i]->size * sizeof(__u32));
+ for (unsigned j=0; j<map->buckets[i]->size; j++)
+ ::_decode_simple(((crush_bucket_uniform*)map->buckets[i])->primes[j], blp);
+ ::_decode_simple(((crush_bucket_uniform*)map->buckets[i])->item_weight, blp);
+ break;
+
+ case CRUSH_BUCKET_LIST:
+ ((crush_bucket_list*)map->buckets[i])->item_weights =
+ (__u32*)malloc(map->buckets[i]->size * sizeof(__u32));
+ ((crush_bucket_list*)map->buckets[i])->sum_weights =
+ (__u32*)malloc(map->buckets[i]->size * sizeof(__u32));
+
+ for (unsigned j=0; j<map->buckets[i]->size; j++) {
+ ::_decode_simple(((crush_bucket_list*)map->buckets[i])->item_weights[j], blp);
+ ::_decode_simple(((crush_bucket_list*)map->buckets[i])->sum_weights[j], blp);
+ }
+ break;
+
+ case CRUSH_BUCKET_TREE:
+ ((crush_bucket_tree*)map->buckets[i])->node_weights =
+ (__u32*)malloc(map->buckets[i]->size * sizeof(__u32));
+ for (unsigned j=0; j<map->buckets[i]->size; j++)
+ ::_decode_simple(((crush_bucket_tree*)map->buckets[i])->node_weights[j], blp);
+ break;
+
+ case CRUSH_BUCKET_STRAW:
+ ((crush_bucket_straw*)map->buckets[i])->straws =
+ (__u32*)malloc(map->buckets[i]->size * sizeof(__u32));
+ for (unsigned j=0; j<map->buckets[i]->size; j++)
+ ::_decode_simple(((crush_bucket_straw*)map->buckets[i])->straws[j], blp);
+ break;
+ }
+ }
+
+ // rules
+ map->rules = (crush_rule**)malloc(sizeof(crush_rule*)*map->max_rules);
+ for (unsigned i=0; i<map->max_rules; i++) {
+ __u32 yes;
+ ::_decode_simple(yes, blp);
+ if (!yes) {
+ map->rules[i] = 0;
+ continue;
+ }
+
+ map->rules[i] = (crush_rule*)malloc(sizeof(crush_rule));
+ memset(map->rules[i], 0, sizeof(crush_rule));
+
+ ::_decode_simple(map->rules[i]->len, blp);
+ map->rules[i]->steps = (crush_rule_step*)malloc(sizeof(crush_rule_step) * map->rules[i]->len);
+ for (unsigned j=0; j<map->rules[i]->len; j++)
+ ::_decode_simple(map->rules[i]->steps[j], blp);
+ }
+
+ finalize();
+ }
+};
+
+#endif
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation. See file COPYING.
- *
- */
-
-
-// Robert Jenkins' function for mixing 32-bit values
-// http://burtleburtle.net/bob/hash/evahash.html
-// a, b = random bits, c = input and output
-#define hashmix(a,b,c) \
- a=a-b; a=a-c; a=a^(c>>13); \
- b=b-c; b=b-a; b=b^(a<<8); \
- c=c-a; c=c-b; c=c^(b>>13); \
- a=a-b; a=a-c; a=a^(c>>12); \
- b=b-c; b=b-a; b=b^(a<<16); \
- c=c-a; c=c-b; c=c^(b>>5); \
- a=a-b; a=a-c; a=a^(c>>3); \
- b=b-c; b=b-a; b=b^(a<<10); \
- c=c-a; c=c-b; c=c^(b>>15);
-
-namespace crush {
-
- class Hash {
- int seed;
-
- public:
- int get_seed() { return seed; }
- void set_seed(int s) { seed = s; }
-
- Hash(int s) {
- unsigned int hash = 1315423911;
- int x = 231232;
- int y = 1232;
- hashmix(s, x, hash);
- hashmix(y, s, hash);
- seed = s;
- }
-
- inline int operator()(int a) {
- unsigned int hash = seed ^ a;
- int b = a;
- int x = 231232;
- int y = 1232;
- hashmix(b, x, hash);
- hashmix(y, a, hash);
- return (hash & 0x7FFFFFFF);
- }
-
- inline int operator()(int a, int b) {
- unsigned int hash = seed ^ a ^ b;
- int x = 231232;
- int y = 1232;
- hashmix(a, b, hash);
- hashmix(x, a, hash);
- hashmix(b, y, hash);
- return (hash & 0x7FFFFFFF);
- }
-
- inline int operator()(int a, int b, int c) {
- unsigned int hash = seed ^ a ^ b ^ c;
- int x = 231232;
- int y = 1232;
- hashmix(a, b, hash);
- hashmix(c, x, hash);
- hashmix(y, a, hash);
- hashmix(b, x, hash);
- hashmix(y, c, hash);
- return (hash & 0x7FFFFFFF);
- }
-
- inline int operator()(int a, int b, int c, int d) {
- unsigned int hash = seed ^a ^ b ^ c ^ d;
- int x = 231232;
- int y = 1232;
- hashmix(a, b, hash);
- hashmix(c, d, hash);
- hashmix(a, x, hash);
- hashmix(y, b, hash);
- hashmix(c, x, hash);
- hashmix(y, d, hash);
- return (hash & 0x7FFFFFFF);
- }
-
- inline int operator()(int a, int b, int c, int d, int e) {
- unsigned int hash = seed ^ a ^ b ^ c ^ d ^ e;
- int x = 231232;
- int y = 1232;
- hashmix(a, b, hash);
- hashmix(c, d, hash);
- hashmix(e, x, hash);
- hashmix(y, a, hash);
- hashmix(b, x, hash);
- hashmix(y, c, hash);
- hashmix(d, x, hash);
- hashmix(y, e, hash);
- return (hash & 0x7FFFFFFF);
- }
- };
-
-}
-
-
-
-#if 0
-
-
- //return myhash(a) ^ seed;
- return myhash(a, seed);
- }
- int operator()(int a, int b) {
- //return myhash( myhash(a) ^ myhash(b) ^ seed );
- return myhash(a, b, seed);
- }
- int operator()(int a, int b, int c) {
- //return myhash( myhash(a ^ seed) ^ myhash(b ^ seed) ^ myhash(c ^ seed) ^ seed );
- return myhash(a, b, c, seed);
- }
- int operator()(int a, int b, int c, int d) {
- //return myhash( myhash(a ^ seed) ^ myhash(b ^ seed) ^ myhash(c ^ seed) ^ myhash(d ^ seed) ^ seed );
- return myhash(a, b, c, d, seed);
- }
-
- // ethan's rush hash?
- if (0)
- return (n ^ 0xdead1234) * (884811920 * 3 + 1);
-
- if (1) {
-
- // before
- hash ^= ((hash << 5) + (n&255) + (hash >> 2));
- hashmix(a, b, hash);
- n = n >> 8;
- hash ^= ((hash << 5) + (n&255) + (hash >> 2));
- hashmix(a, b, hash);
- n = n >> 8;
- hash ^= ((hash << 5) + (n&255) + (hash >> 2));
- hashmix(a, b, hash);
- n = n >> 8;
- hash ^= ((hash << 5) + (n&255) + (hash >> 2));
- hashmix(a, b, hash);
- n = n >> 8;
-
- //return hash;
- return (hash & 0x7FFFFFFF);
- }
-
- // JS
- // a little better than RS
- // + jenkin's mixing thing (which sucks on its own but helps tons here)
- // best so far
- if (1) {
- unsigned int hash = 1315423911;
- int a = 231232;
- int b = 1232;
-
- for(unsigned int i = 0; i < 4; i++)
- {
- hash ^= ((hash << 5) + (n&255) + (hash >> 2));
- hashmix(a, b, hash);
- n = n >> 8;
- }
-
- return (hash & 0x7FFFFFFF);
- }
-
-
- // Robert jenkins' 96 bit mix
- // sucks
- if (0) {
- int c = n;
- int a = 12378912;
- int b = 2982827;
- a=a-b; a=a-c; a=a^(c>>13);
- b=b-c; b=b-a; b=b^(a<<8);
- c=c-a; c=c-b; c=c^(b>>13);
- a=a-b; a=a-c; a=a^(c>>12);
- b=b-c; b=b-a; b=b^(a<<16);
- c=c-a; c=c-b; c=c^(b>>5);
- a=a-b; a=a-c; a=a^(c>>3);
- b=b-c; b=b-a; b=b^(a<<10);
- c=c-a; c=c-b; c=c^(b>>15);
- return c;
- }
- // robert jenkins 32-bit
- // sucks
- if (0) {
- n += (n << 12);
- n ^= (n >> 22);
- n += (n << 4);
- n ^= (n >> 9);
- n += (n << 10);
- n ^= (n >> 2);
- n += (n << 7);
- n ^= (n >> 12);
- return n;
- }
-
- // djb2
- if (0) {
- unsigned int hash = 5381;
- for (int i=0; i<4; i++) {
- hash = ((hash << 5) + hash) + ((n&255) ^ 123);
- n = n >> 8;
- }
- return hash;
- }
-
-
- // SDBM
- if (1) {
- unsigned int hash = 0;
-
- for(unsigned int i = 0; i < 4; i++)
- {
- hash = (n&255) + (hash << 6) + (hash << 16) - hash;
- n = n >> 8;
- }
-
- return (hash & 0x7FFFFFFF);
- }
-
- // PJW
- // horrid
- if (0) {
- unsigned int BitsInUnsignedInt = (unsigned int)(sizeof(unsigned int) * 8);
- unsigned int ThreeQuarters = (unsigned int)((BitsInUnsignedInt * 3) / 4);
- unsigned int OneEighth = (unsigned int)(BitsInUnsignedInt / 8);
- unsigned int HighBits = (unsigned int)(0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth);
- unsigned int hash = 0;
- unsigned int test = 0;
-
- for(unsigned int i = 0; i < 4; i++)
- {
- hash = (hash << OneEighth) + (n&255);
-
- if((test = hash & HighBits) != 0)
- {
- hash = (( hash ^ (test >> ThreeQuarters)) & (~HighBits));
- }
- n = n >> 8;
- }
-
- return (hash & 0x7FFFFFFF);
- }
-
- // RS Hash function, from Robert Sedgwicks Algorithms in C book, w/ some changes.
- if (0) {
- unsigned int b = 378551;
- unsigned int a = 63689;
- unsigned int hash = 0;
-
- for(unsigned int i=0; i<4; i++)
- {
- hash = hash * a + (n&0xff);
- a = a * b;
- n = n >> 8;
- }
-
- return (hash & 0x7FFFFFFF);
- }
-
- // DJB
- // worse than rs
- if (0) {
- unsigned int hash = 5381;
-
- for(unsigned int i = 0; i < 4; i++)
- {
- hash = ((hash << 5) + hash) + (n&255);
- n = n >> 8;
- }
-
- return (hash & 0x7FFFFFFF);
- }
-
- // AP
- // even worse
- if (1) {
- unsigned int hash = 0;
-
- for(unsigned int i = 0; i < 4; i++)
- {
- hash ^= ((i & 1) == 0) ? ( (hash << 7) ^ (n&255) ^ (hash >> 3)) :
- (~((hash << 11) ^ (n&255) ^ (hash >> 5)));
- n = n >> 8;
- }
-
- return (hash & 0x7FFFFFFF);
- }
-
-
-#endif
--- /dev/null
+
+CC = gcc
+CFLAGS = -Wall
+CFLAGS += -g
+CFLAGS += -O3
+LD = ld
+RM = rm
+
+all: depend libcrush.o test
+
+clean:
+ rm -f *.o libcrush.o
+
+%.o: %.c
+ ${CC} ${CFLAGS} -c $< -o $@
+
+libcrush.o: builder.o crush.o mapper.o
+ $(LD) -i -o $@ $^
+
+test: test.c libcrush.o
+ $(CC) ${CFLAGS} -lm $^ -o $@
+
+.depend:
+ touch .depend
+
+depend:
+ $(RM) .depend
+ makedepend -f- -- $(CFLAGS) -- *.c > .depend 2>/dev/null
+
+include .depend
--- /dev/null
+
+#include "crush.h"
+#include "hash.h"
+
+int
+
--- /dev/null
+
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "builder.h"
+#include "hash.h"
+
+struct crush_map *crush_create()
+{
+ struct crush_map *m;
+ m = malloc(sizeof(*m));
+ memset(m, 0, sizeof(*m));
+ return m;
+}
+
+/*
+ * finalize should be called _after_ all buckets are added to the map.
+ */
+void crush_finalize(struct crush_map *map)
+{
+ int b, i, c;
+
+ /* calc max_devices */
+ for (b=0; b<map->max_buckets; b++) {
+ if (map->buckets[b] == 0) continue;
+ for (i=0; i<map->buckets[b]->size; i++)
+ if (map->buckets[b]->items[i] >= map->max_devices)
+ map->max_devices = map->buckets[b]->items[i] + 1;
+ }
+
+ /* allocate arrays */
+ map->device_parents = malloc(sizeof(map->device_parents[0]) * map->max_devices);
+ memset(map->device_parents, 0, sizeof(map->device_parents[0]) * map->max_devices);
+ map->bucket_parents = malloc(sizeof(map->bucket_parents[0]) * map->max_buckets);
+ memset(map->bucket_parents, 0, sizeof(map->bucket_parents[0]) * map->max_buckets);
+
+ /* build parent maps */
+ for (b=0; b<map->max_buckets; b++) {
+ if (map->buckets[b] == 0) continue;
+ for (i=0; i<map->buckets[b]->size; i++) {
+ c = map->buckets[b]->items[i];
+ BUG_ON(c >= map->max_devices);
+ if (c >= 0)
+ map->device_parents[c] = map->buckets[b]->id;
+ else
+ map->bucket_parents[-1-c] = map->buckets[b]->id;
+ }
+ }
+
+ /* new device offload map? */
+ if (!map->device_offload) {
+ map->device_offload = malloc(sizeof(map->device_offload[0]) * map->max_devices);
+ memset(map->device_offload, 0, sizeof(map->device_offload[0]) * map->max_devices);
+ }
+}
+
+
+
+
+
+/** rules **/
+
+int crush_add_rule(struct crush_map *map,
+ int ruleno,
+ struct crush_rule *rule)
+{
+ int oldsize;
+
+ if (ruleno < 0) {
+ for (ruleno=0; ruleno < map->max_rules; ruleno++)
+ if (map->rules[ruleno] == 0) break;
+ }
+ if (ruleno >= map->max_rules) {
+ /* expand array */
+ oldsize = map->max_rules;
+ map->max_rules = ruleno+1;
+ map->rules = realloc(map->rules, map->max_rules * sizeof(map->rules[0]));
+ memset(map->rules + oldsize, 0, (map->max_rules-oldsize) * sizeof(map->rules[0]));
+ }
+
+ /* add it */
+ map->rules[ruleno] = rule;
+ return ruleno;
+}
+
+struct crush_rule *crush_make_rule()
+{
+ struct crush_rule *rule;
+
+ rule = malloc(sizeof(struct crush_rule));
+ memset(rule, 0, sizeof(*rule));
+ return rule;
+}
+
+void crush_rule_add_step(struct crush_rule *rule, int op, int arg1, int arg2)
+{
+ rule->len++;
+ if (rule->steps)
+ rule->steps = realloc(rule->steps, sizeof(rule->steps[0])*rule->len);
+ else
+ rule->steps = malloc(sizeof(rule->steps[0])*rule->len);
+ rule->steps[rule->len-1].op = op;
+ rule->steps[rule->len-1].arg1 = arg1;
+ rule->steps[rule->len-1].arg2 = arg2;
+}
+
+
+/** buckets **/
+
+int crush_add_bucket(struct crush_map *map,
+ struct crush_bucket *bucket)
+{
+ int id;
+ int oldsize;
+
+ /* find a bucket id */
+ for (id=0; id < map->max_buckets; id++)
+ if (map->buckets[id] == 0) break;
+ if (id == map->max_buckets) {
+ /* expand array */
+ oldsize = map->max_buckets;
+ if (map->max_buckets)
+ map->max_buckets *= 2;
+ else
+ map->max_buckets = 8;
+ map->buckets = realloc(map->buckets, map->max_buckets * sizeof(map->buckets[0]));
+ memset(map->buckets + oldsize, 0, (map->max_buckets-oldsize) * sizeof(map->buckets[0]));
+ }
+
+ /* add it */
+ bucket->id = -1 - id;
+ map->buckets[id] = bucket;
+ return -1 - id;
+}
+
+
+/* uniform bucket */
+
+struct crush_bucket_uniform *
+crush_make_uniform_bucket(int type, int size,
+ int *items,
+ int item_weight)
+{
+ int i, j, x;
+ struct crush_bucket_uniform *bucket;
+
+ bucket = malloc(sizeof(*bucket));
+ memset(bucket, 0, sizeof(*bucket));
+ bucket->h.bucket_type = CRUSH_BUCKET_UNIFORM;
+ bucket->h.type = type;
+ bucket->h.size = size;
+ bucket->h.weight = size * item_weight;
+
+ bucket->item_weight = item_weight;
+
+ bucket->h.items = malloc(sizeof(__u32)*size);
+ for (i=0; i<size; i++)
+ bucket->h.items[i] = items[i];
+
+ /* generate some primes */
+ bucket->primes = malloc(sizeof(__u32)*size);
+
+ x = size + 1;
+ x += crush_hash32(size) % (3*size); /* make it big */
+ x |= 1; /* and odd */
+
+ i=0;
+ while (i < size) {
+ for (j=2; j*j <= x; j++)
+ if (x % j == 0) break;
+ if (j*j > x)
+ bucket->primes[i++] = x;
+ x += 2;
+ }
+
+ return bucket;
+}
+
+
+/* list bucket */
+
+struct crush_bucket_list*
+crush_make_list_bucket(int type, int size,
+ int *items,
+ int *weights)
+{
+ int i;
+ int w;
+ struct crush_bucket_list *bucket;
+
+ bucket = malloc(sizeof(*bucket));
+ memset(bucket, 0, sizeof(*bucket));
+ bucket->h.bucket_type = CRUSH_BUCKET_LIST;
+ bucket->h.type = type;
+ bucket->h.size = size;
+
+ bucket->h.items = malloc(sizeof(__u32)*size);
+ bucket->item_weights = malloc(sizeof(__u32)*size);
+ bucket->sum_weights = malloc(sizeof(__u32)*size);
+ w = 0;
+ for (i=size-1; i>=0; i--) {
+ bucket->h.items[i] = items[i];
+ bucket->item_weights[i] = weights[i];
+ w += weights[i];
+ bucket->sum_weights[i] = w;
+ /*printf("%d item %d weight %d sum %d\n",
+ i, items[i], weights[i], bucket->sum_weights[i]);*/
+ }
+
+ bucket->h.weight = w;
+
+ return bucket;
+}
+
+
+/* tree bucket */
+
+static int height(int n) {
+ int h = 0;
+ while ((n & 1) == 0) {
+ h++;
+ n = n >> 1;
+ }
+ return h;
+}
+static int on_right(int n, int h) {
+ return n & (1 << (h+1));
+}
+static int parent(int n)
+{
+ int h = height(n);
+ if (on_right(n, h))
+ return n - (1<<h);
+ else
+ return n + (1<<h);
+}
+
+struct crush_bucket_tree*
+crush_make_tree_bucket(int type, int size,
+ int *items, /* in leaf order */
+ int *weights)
+{
+ struct crush_bucket_tree *bucket;
+ int depth;
+ int node;
+ int t, i, j;
+
+ bucket = malloc(sizeof(*bucket));
+ memset(bucket, 0, sizeof(*bucket));
+ bucket->h.bucket_type = CRUSH_BUCKET_TREE;
+ bucket->h.type = type;
+ bucket->h.size = size;
+
+ /* calc tree depth */
+ depth = 1;
+ t = size - 1;
+ while (t) {
+ t = t >> 1;
+ depth++;
+ }
+ bucket->h.size = 1 << depth;
+
+ bucket->h.items = malloc(sizeof(__u32)*bucket->h.size);
+ bucket->node_weights = malloc(sizeof(__u32)*bucket->h.size);
+
+ memset(bucket->h.items, 0, sizeof(__u32)*bucket->h.size);
+ memset(bucket->node_weights, 0, sizeof(__u32)*bucket->h.size);
+
+ for (i=0; i<size; i++) {
+ node = ((i+1) << 1)-1;
+ bucket->h.items[node] = items[i];
+ bucket->node_weights[node] = weights[i];
+ bucket->h.weight += weights[i];
+ for (j=1; j<depth; j++) {
+ node = parent(node);
+ bucket->node_weights[node] += weights[i];
+ }
+ }
+ BUG_ON(bucket->node_weights[bucket->h.size/2] != bucket->h.weight);
+
+ return bucket;
+}
+
+
+/* straw bucket */
+
+struct crush_bucket_straw *
+crush_make_straw_bucket(int type,
+ int size,
+ int *items,
+ int *weights)
+{
+ struct crush_bucket_straw *bucket;
+ int *reverse;
+ int i, j, k;
+
+ double straw, wbelow, lastw, wnext, pbelow;
+ int numleft;
+
+ bucket = malloc(sizeof(*bucket));
+ memset(bucket, 0, sizeof(*bucket));
+ bucket->h.bucket_type = CRUSH_BUCKET_STRAW;
+ bucket->h.type = type;
+ bucket->h.size = size;
+
+ bucket->h.items = malloc(sizeof(__u32)*size);
+ bucket->straws = malloc(sizeof(__u32)*size);
+
+ bucket->h.weight = 0;
+ for (i=0; i<size; i++) {
+ bucket->h.items[i] = items[i];
+ bucket->h.weight += weights[i];
+ }
+
+ /* reverse sort by weight (simple insertion sort) */
+ reverse = malloc(sizeof(int) * size);
+ reverse[0] = 0;
+ for (i=1; i<size; i++) {
+ for (j=0; j<i; j++) {
+ if (weights[i] < weights[reverse[j]]) {
+ /* insert here */
+ for (k=i; k>j; k--)
+ reverse[k] = reverse[k-1];
+ reverse[j] = i;
+ break;
+ }
+ }
+ if (j == i)
+ reverse[i] = i;
+ }
+
+ numleft = size;
+ straw = 1.0;
+ wbelow = 0;
+ lastw = 0;
+
+ i=0;
+ while (i < size) {
+ /* set this item's straw */
+ bucket->straws[reverse[i]] = straw * 0x10000;
+ /*printf("item %d at %d weight %d straw %d (%lf)\n",
+ items[reverse[i]],
+ reverse[i], weights[reverse[i]], bucket->straws[reverse[i]], straw);*/
+ i++;
+ if (i == size) break;
+
+ /* same weight as previous? */
+ if (weights[reverse[i]] == weights[reverse[i-1]]) {
+ /*printf("same as previous\n");*/
+ continue;
+ }
+
+ /* adjust straw for next guy */
+ wbelow += ((double)weights[reverse[i-1]] - lastw) * numleft;
+ for (j=i; j<size; j++)
+ if (weights[reverse[j]] == weights[reverse[i]])
+ numleft--;
+ else
+ break;
+ wnext = numleft * (weights[reverse[i]] - weights[reverse[i-1]]);
+ pbelow = wbelow / (wbelow + wnext);
+ /*printf("wbelow %lf wnext %lf pbelow %lf\n", wbelow, wnext, pbelow);*/
+
+ straw *= pow((double)1.0 / pbelow, (double)1.0 / (double)numleft);
+
+ lastw = weights[reverse[i-1]];
+ }
+
+ free(reverse);
+
+ return bucket;
+}
+
--- /dev/null
+#ifndef _CRUSH_BUILDER_H
+#define _CRUSH_BUILDER_H
+
+#include "crush.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct crush_map *crush_create();
+extern void crush_finalize(struct crush_map *map);
+
+/* rules */
+extern struct crush_rule *crush_make_rule();
+extern int crush_add_rule(struct crush_map *map,
+ int ruleno,
+ struct crush_rule *rule);
+extern void crush_rule_add_step(struct crush_rule *rule, int op, int arg1, int arg2);
+
+/* buckets */
+extern int crush_add_bucket(struct crush_map *map,
+ struct crush_bucket *bucket);
+
+struct crush_bucket_uniform *
+crush_make_uniform_bucket(int type, int size,
+ int *items,
+ int item_weight);
+struct crush_bucket_list*
+crush_make_list_bucket(int type, int size,
+ int *items,
+ int *weights);
+struct crush_bucket_tree*
+crush_make_tree_bucket(int type, int size,
+ int *items, /* in leaf order */
+ int *weights);
+struct crush_bucket_straw *
+crush_make_straw_bucket(int type, int size,
+ int *items,
+ int *weights);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+
+#ifdef __KERNEL__
+# define free(x) kfree(x)
+#else
+# include <stdlib.h>
+#endif
+
+#include "crush.h"
+
+void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b)
+{
+ free(b->primes);
+ free(b->h.items);
+ free(b);
+}
+
+void crush_destroy_bucket_list(struct crush_bucket_list *b)
+{
+ free(b->item_weights);
+ free(b->sum_weights);
+ free(b->h.items);
+ free(b);
+}
+
+void crush_destroy_bucket_tree(struct crush_bucket_tree *b)
+{
+ free(b->node_weights);
+ free(b);
+}
+
+void crush_destroy_bucket_straw(struct crush_bucket_straw *b)
+{
+ free(b->straws);
+ free(b->h.items);
+ free(b);
+}
+
+
+/*
+ * deallocate
+ */
+void crush_destroy(struct crush_map *map)
+{
+ int b;
+
+ /* buckets */
+ for (b=0; b<map->max_buckets; b++) {
+ if (map->buckets[b] == 0) continue;
+ switch (map->buckets[b]->type) {
+ case CRUSH_BUCKET_UNIFORM:
+ crush_destroy_bucket_uniform((struct crush_bucket_uniform*)map->buckets[b]);
+ break;
+ case CRUSH_BUCKET_LIST:
+ crush_destroy_bucket_list((struct crush_bucket_list*)map->buckets[b]);
+ break;
+ case CRUSH_BUCKET_TREE:
+ crush_destroy_bucket_tree((struct crush_bucket_tree*)map->buckets[b]);
+ break;
+ case CRUSH_BUCKET_STRAW:
+ crush_destroy_bucket_straw((struct crush_bucket_straw*)map->buckets[b]);
+ break;
+ }
+ }
+ free(map->buckets);
+
+ /* rules */
+ for (b=0; b<map->max_rules; b++) {
+ if (map->rules[b] == 0) continue;
+ if (map->rules[b]->steps)
+ free(map->rules[b]->steps);
+ free(map->rules[b]);
+ }
+ free(map->rules);
+
+ free(map->bucket_parents);
+ free(map->device_parents);
+ free(map->device_offload);
+ free(map);
+}
+
+
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation. See file COPYING.
- *
- */
+#ifndef _CRUSH_CRUSH_H
+#define _CRUSH_CRUSH_H
-#ifndef __crush_CRUSH_H
-#define __crush_CRUSH_H
-
-#include <iostream>
-#include <list>
-#include <vector>
-#include <set>
-#include <map>
-using std::set;
-using std::map;
-using std::vector;
-using std::list;
-#include <ext/hash_map>
-#include <ext/hash_set>
-using namespace __gnu_cxx;
-
-
-#include "Bucket.h"
-
-#include "include/buffer.h"
-
-
-namespace crush {
-
-
- // *** RULES ***
-
- class RuleStep {
- public:
- int cmd;
- vector<int> args;
-
- RuleStep(int c) : cmd(c) {}
- RuleStep(int c, int a) : cmd(c) {
- args.push_back(a);
- }
- RuleStep(int c, int a, int b) : cmd(c) {
- args.push_back(a);
- args.push_back(b);
- }
- RuleStep(int o, int a, int b, int c) : cmd(o) {
- args.push_back(a);
- args.push_back(b);
- args.push_back(c);
- }
-
- void _encode(bufferlist& bl) {
- bl.append((char*)&cmd, sizeof(cmd));
- ::_encode(args, bl);
- }
- void _decode(bufferlist& bl, int& off) {
- bl.copy(off, sizeof(cmd), (char*)&cmd);
- off += sizeof(cmd);
- ::_decode(args, bl, off);
- }
- };
-
-
- // Rule operations
- const int CRUSH_RULE_TAKE = 0;
- const int CRUSH_RULE_CHOOSE = 1; // first n by default
- const int CRUSH_RULE_CHOOSE_FIRSTN = 1;
- const int CRUSH_RULE_CHOOSE_INDEP = 2;
- const int CRUSH_RULE_EMIT = 3;
-
- class Rule {
- public:
- vector< RuleStep > steps;
-
- void _encode(bufferlist& bl) {
- int n = steps.size();
- bl.append((char*)&n, sizeof(n));
- for (int i=0; i<n; i++)
- steps[i]._encode(bl);
- }
- void _decode(bufferlist& bl, int& off) {
- steps.clear();
- int n;
- bl.copy(off, sizeof(n), (char*)&n);
- off += sizeof(n);
- for (int i=0; i<n; i++) {
- steps.push_back(RuleStep(0));
- steps[i]._decode(bl, off);
- }
- }
- };
-
-
-
-
- // *** CRUSH ***
-
- class Crush {
- protected:
- map<int, Bucket*> buckets;
- int bucketno;
- Hash h;
-
- hash_map<int, int> parent_map; // what bucket each leaf/bucket lives in
-
- public:
- map<int, Rule> rules;
-
- //map<int,int> collisions;
- //map<int,int> bumps;
-
- void _encode(bufferlist& bl) {
- // buckets
- int n = buckets.size();
- bl.append((char*)&n, sizeof(n));
- for (map<int, Bucket*>::const_iterator it = buckets.begin();
- it != buckets.end();
- it++) {
- bl.append((char*)&it->first, sizeof(it->first));
- it->second->_encode(bl);
- }
- bl.append((char*)&bucketno, sizeof(bucketno));
-
- // hash
- int s = h.get_seed();
- bl.append((char*)&s, sizeof(s));
-
- //::_encode(out, bl);
- //::_encode(overload, bl);
-
- // rules
- n = rules.size();
- bl.append((char*)&n, sizeof(n));
- for(map<int, Rule>::iterator it = rules.begin();
- it != rules.end();
- it++) {
- bl.append((char*)&it->first, sizeof(it->first));
- it->second._encode(bl);
- }
-
- }
-
- void _decode(bufferlist& bl, int& off) {
- int n;
- bl.copy(off, sizeof(n), (char*)&n);
- off += sizeof(n);
- for (int i=0; i<n; i++) {
- int bid;
- bl.copy(off, sizeof(bid), (char*)&bid);
- off += sizeof(bid);
- Bucket *b = decode_bucket(bl, off);
- buckets[bid] = b;
- }
- bl.copy(off, sizeof(bucketno), (char*)&bucketno);
- off += sizeof(bucketno);
+#ifdef __cplusplus
+extern "C" {
+#endif
- int s;
- bl.copy(off, sizeof(s), (char*)&s);
- off += sizeof(s);
- h.set_seed(s);
+#include <linux/types.h> /* just for int types */
- //::_decode(out, bl, off);
- //::_decode(overload, bl, off);
+#ifndef BUG_ON
+# include <assert.h>
+# define BUG_ON(x) assert(!(x))
+#endif
- // rules
- bl.copy(off, sizeof(n), (char*)&n);
- off += sizeof(n);
- for (int i=0; i<n; i++) {
- int r;
- bl.copy(off, sizeof(r), (char*)&r);
- off += sizeof(r);
- rules[r]._decode(bl,off);
- }
-
- // index
- build_parent_map();
- }
- void build_parent_map() {
- parent_map.clear();
-
- // index every bucket
- for (map<int, Bucket*>::iterator bp = buckets.begin();
- bp != buckets.end();
- ++bp) {
- // index bucket items
- vector<int> items;
- bp->second->get_items(items);
- for (vector<int>::iterator ip = items.begin();
- ip != items.end();
- ++ip)
- parent_map[*ip] = bp->first;
- }
- }
-
+/*** RULES ***/
+enum {
+ CRUSH_RULE_TAKE,
+ CRUSH_RULE_CHOOSE_FIRSTN,
+ CRUSH_RULE_CHOOSE_INDEP,
+ CRUSH_RULE_EMIT
+};
+#define CRUSH_MAX_DEPTH 10
+#define CRUSH_MAX_SET 10
- public:
- Crush(int seed=123) : bucketno(-1), h(seed) {}
- ~Crush() {
- // hose buckets
- for (map<int, Bucket*>::iterator it = buckets.begin();
- it != buckets.end();
- it++) {
- delete it->second;
- }
- }
+struct crush_rule_step {
+ __u32 op;
+ __s32 arg1;
+ __s32 arg2;
+};
- int print(ostream& out, int root, int indent=0) {
- for (int i=0; i<indent; i++) out << " ";
- Bucket *b = buckets[root];
- assert(b);
- out << b->get_weight() << "\t" << b->get_id() << "\t";
- for (int i=0; i<indent; i++) out << " ";
- out << b->get_bucket_type() << ": ";
+struct crush_rule {
+ __u32 len;
+ struct crush_rule_step *steps;
+};
- vector<int> items;
- b->get_items(items);
- if (buckets.count(items[0])) {
- out << std::endl;
- for (unsigned i=0; i<items.size(); i++)
- print(out, items[i], indent+1);
- } else {
- out << "[";
- for (unsigned i=0; i<items.size(); i++) {
- if (i) out << " ";
- out << items[i];
- }
- out << "]";
- }
- return 0;
- }
+/*** BUCKETS ***/
- int add_bucket( Bucket *b ) {
- int n = bucketno;
- bucketno--;
- b->set_id(n);
- buckets[n] = b;
- return n;
- }
+enum {
+ CRUSH_BUCKET_UNIFORM = 1,
+ CRUSH_BUCKET_LIST = 2,
+ CRUSH_BUCKET_TREE = 3,
+ CRUSH_BUCKET_STRAW = 4
+};
- void add_item(int parent, int item, float w, bool back=false) {
- // add item
- assert(!buckets[parent]->is_uniform());
- Bucket *p = buckets[parent];
-
- p->add_item(item, w, back);
+struct crush_bucket {
+ __s32 id; /* this'll be negative */
+ __u16 type;
+ __u16 bucket_type;
+ __u32 weight; /* 16-bit fixed point */
+ __u32 size; /* num items */
+ __s32 *items;
+};
- // set item's parent
- Bucket *n = buckets[item];
- if (n)
- n->set_parent(parent);
+struct crush_bucket_uniform {
+ struct crush_bucket h;
+ __u32 *primes;
+ __u32 item_weight; /* 16-bit fixed point */
+};
- // update weights
- while (buckets.count(p->get_parent())) {
- int child = p->get_id();
- p = buckets[p->get_parent()];
- p->adjust_item_weight(child, w);
- }
- }
+struct crush_bucket_list {
+ struct crush_bucket h;
+ __u32 *item_weights; /* 16-bit fixed point */
+ __u32 *sum_weights; /* 16-bit fixed point. element i is sum of weights 0..i, inclusive */
+};
+struct crush_bucket_tree {
+ struct crush_bucket h; /* note: h.size is tree size, not number of actual items */
+ __u32 *node_weights;
+};
- /*
- this is a hack, fix me! weights should be consistent throughout hierarchy!
-
- */
- void set_bucket_weight(int item, float w) {
- Bucket *b = buckets[item];
- float adj = w - b->get_weight();
+struct crush_bucket_straw {
+ struct crush_bucket h;
+ __u32 *straws; /* 16-bit fixed point */
+};
- while (buckets.count(b->get_parent())) {
- Bucket *p = buckets[b->get_parent()];
- p->adjust_item_weight(b->get_id(), adj);
- b = p;
- }
- }
- /*
- * choose numrep distinct items of type type
- */
- void choose(int x,
- int numrep,
- int type,
- Bucket *inbucket,
- vector<int>& outvec,
- bool firstn,
- set<int>& outset, map<int,float>& overloadmap,
- bool forcefeed=false,
- int forcefeedval=-1) {
- int off = outvec.size();
+/*** CRUSH ***/
- // for each replica
- for (int rep=0; rep<numrep; rep++) {
- int outv = -1; // my result
-
- // forcefeed?
- if (forcefeed) {
- forcefeed = false;
- outvec.push_back(forcefeedval);
- continue;
- }
+struct crush_map {
+ struct crush_bucket **buckets;
+ struct crush_rule **rules;
- // keep trying until we get a non-out, non-colliding item
- int ftotal = 0;
- bool skip_rep = false;
+ /* parent pointers */
+ __u32 *bucket_parents;
+ __u32 *device_parents;
- while (1) {
- // start with the input bucket
- Bucket *in = inbucket;
-
- // choose through intervening buckets
- int flocal = 0;
- bool retry_rep = false;
-
- while (1) {
- // r may be twiddled to (try to) avoid past collisions
- int r = rep;
- if (in->is_uniform()) {
- // uniform bucket; be careful!
- if (firstn || numrep >= in->get_size()) {
- // uniform bucket is too small; just walk thru elements
- r += ftotal; // r' = r + f_total (first n)
- } else {
- // make sure numrep is not a multple of bucket size
- int add = numrep*flocal; // r' = r + n*f_local
- if (in->get_size() % numrep == 0) {
- add += add/in->get_size(); // shift seq once per pass through the bucket
- }
- r += add;
- }
- } else {
- // mixed bucket; just make a distinct-ish r sequence
- if (firstn)
- r += ftotal; // r' = r + f_total
- else
- r += numrep * flocal; // r' = r + n*f_local
- }
-
- // choose
- outv = in->choose_r(x, r, h);
-
- // did we get the type we want?
- int itemtype = 0; // 0 is terminal type
- Bucket *newin = 0; // remember bucket we hit
- if (in->is_uniform()) {
- itemtype = ((UniformBucket*)in)->get_item_type();
- } else {
- if (buckets.count(outv)) { // another bucket
- newin = buckets[outv];
- itemtype = newin->get_type();
- }
- }
- if (itemtype == type) { // this is what we want!
- // collision?
- bool collide = false;
- for (int prep=0; prep<rep; prep++) {
- if (outvec[off+prep] == outv) {
- collide = true;
- break;
- }
- }
-
- // ok choice?
- bool bad = false;
- if (type == 0 && outset.count(outv))
- bad = true;
- if (overloadmap.count(outv)) {
- float f = (float)(h(x, outv) % 1000) / 1000.0;
- if (f > overloadmap[outv])
- bad = true;
- }
-
- if (collide || bad) {
- ftotal++;
- flocal++;
-
- if (collide && flocal < 3)
- continue; // try locally a few times!
-
- if (ftotal >= 10) {
- // ok fine, just ignore dup. FIXME.
- skip_rep = true;
- break;
- }
-
- retry_rep = true;
- }
-
- break; // ok then!
- }
-
- // next
- in = newin;
- }
-
- if (retry_rep) continue; // try again
-
- break;
- }
-
- // skip this rep? (e.g. too many collisions, we give up)
- if (skip_rep) continue;
-
- // output this value
- outvec.push_back(outv);
- } // for rep
-
- // double check!
- if (0) {
- for (unsigned i=1; i<outvec.size(); i++)
- for (unsigned j=0; j<i; j++)
- assert(outvec[i] != outvec[j]);
- }
- }
-
-
- void do_rule(Rule& rule, int x, vector<int>& result,
- set<int>& outset, map<int,float>& overloadmap,
- int forcefeed=-1) {
- //int numresult = 0;
- result.clear();
-
- // determine hierarchical context for forcefeed (if any)
- list<int> force_stack;
- if (forcefeed >= 0 && parent_map.count(forcefeed)) {
- int t = forcefeed;
- while (1) {
- force_stack.push_front(t);
- //cout << "push " << t << " onto force_stack" << std::endl;
- if (parent_map.count(t) == 0) break; // reached root, presumably.
- //cout << " " << t << " parent is " << parent_map[t] << std::endl;
- t = parent_map[t];
- }
- }
-
- // working vector
- vector<int> w; // working variable
-
- // go through each statement
- for (vector<RuleStep>::iterator pc = rule.steps.begin();
- pc != rule.steps.end();
- pc++) {
- // move input?
-
- // do it
- switch (pc->cmd) {
- case CRUSH_RULE_TAKE:
- {
- const int arg = pc->args[0];
- //cout << "take " << arg << std::endl;
-
- if (!force_stack.empty()) {
- assert(force_stack.front() == arg);
- force_stack.pop_front();
- }
-
- w.clear();
- w.push_back(arg);
- }
- break;
-
- case CRUSH_RULE_CHOOSE_FIRSTN:
- case CRUSH_RULE_CHOOSE_INDEP:
- {
- const bool firstn = pc->cmd == CRUSH_RULE_CHOOSE_FIRSTN;
- const int numrep = pc->args[0];
- const int type = pc->args[1];
-
- //cout << "choose " << numrep << " of type " << type << std::endl;
-
- assert(!w.empty());
-
- // reset output
- vector<int> out;
-
- // forcefeeding?
- bool forcing = false;
- int forceval = -1;
- if (!force_stack.empty()) {
- forceval = force_stack.front();
- force_stack.pop_front();
- //cout << "priming out with " << forceval << std::endl;
- forcing = true;
- } else if (forcefeed >= 0 && type == 0) {
- //cout << "forcing context-less " << forcefeed << std::endl;
- forceval = forcefeed;
- forcefeed = -1;
- forcing = true;
- }
-
- // do each row independently
- for (vector<int>::iterator i = w.begin();
- i != w.end();
- i++) {
- assert(buckets.count(*i));
- Bucket *b = buckets[*i];
- choose(x, numrep, type, b, out, firstn,
- outset, overloadmap,
- forcing,
- forceval);
- forcing = false; // only once
- } // for inrow
-
- // put back into w
- w.swap(out);
- out.clear();
- }
- break;
-
- case CRUSH_RULE_EMIT:
- {
- for (unsigned i=0; i<w.size(); i++)
- result.push_back(w[i]);
- //result[numresult++] = w[i];
- w.clear();
- }
- break;
-
- default:
- assert(0);
- }
- }
+ /* offload
+ * size max_devices, values 0...0xffff
+ * 0 == normal
+ * 0x10000 == 100% offload (i.e. failed)
+ */
+ __u32 *device_offload;
+
+ __u32 max_buckets;
+ __u32 max_rules;
+ __s32 max_devices;
+};
- }
+/* common destructors */
+extern void crush_destroy_bucket_uniform(struct crush_bucket_uniform *);
+extern void crush_destroy_bucket_list(struct crush_bucket_list *);
+extern void crush_destroy_bucket_tree(struct crush_bucket_tree *);
+extern void crush_destroy_bucket_straw(struct crush_bucket_straw *);
+extern void crush_destroy(struct crush_map *map);
- };
+#ifdef __cplusplus
}
+#endif
#endif
--- /dev/null
+#ifndef _CRUSH_HASH_H
+#define _CRUSH_HASH_H
+
+// Robert Jenkins' function for mixing 32-bit values
+// http://burtleburtle.net/bob/hash/evahash.html
+// a, b = random bits, c = input and output
+#define hashmix(a,b,c) \
+ a=a-b; a=a-c; a=a^(c>>13); \
+ b=b-c; b=b-a; b=b^(a<<8); \
+ c=c-a; c=c-b; c=c^(b>>13); \
+ a=a-b; a=a-c; a=a^(c>>12); \
+ b=b-c; b=b-a; b=b^(a<<16); \
+ c=c-a; c=c-b; c=c^(b>>5); \
+ a=a-b; a=a-c; a=a^(c>>3); \
+ b=b-c; b=b-a; b=b^(a<<10); \
+ c=c-a; c=c-b; c=c^(b>>15);
+
+#define crush_hash_seed 1315423911
+
+static __inline__ unsigned crush_hash32(unsigned a) {
+ unsigned hash = crush_hash_seed ^ a;
+ unsigned b = a;
+ unsigned x = 231232;
+ unsigned y = 1232;
+ hashmix(b, x, hash);
+ hashmix(y, a, hash);
+ return (hash & 0xFFFFFFFF);
+}
+
+static __inline__ unsigned crush_hash32_2(unsigned a, unsigned b) {
+ unsigned hash = crush_hash_seed ^ a ^ b;
+ unsigned x = 231232;
+ unsigned y = 1232;
+ hashmix(a, b, hash);
+ hashmix(x, a, hash);
+ hashmix(b, y, hash);
+ return (hash & 0xFFFFFFFF);
+}
+
+static __inline__ unsigned crush_hash32_3(unsigned a, unsigned b, unsigned c) {
+ unsigned int hash = crush_hash_seed ^ a ^ b ^ c;
+ unsigned x = 231232;
+ unsigned y = 1232;
+ hashmix(a, b, hash);
+ hashmix(c, x, hash);
+ hashmix(y, a, hash);
+ hashmix(b, x, hash);
+ hashmix(y, c, hash);
+ return (hash & 0xFFFFFFFF);
+}
+
+static __inline__ unsigned crush_hash32_4(unsigned a, unsigned b, unsigned c, unsigned d) {
+ unsigned int hash = crush_hash_seed ^a ^ b ^ c ^ d;
+ unsigned x = 231232;
+ unsigned y = 1232;
+ hashmix(a, b, hash);
+ hashmix(c, d, hash);
+ hashmix(a, x, hash);
+ hashmix(y, b, hash);
+ hashmix(c, x, hash);
+ hashmix(y, d, hash);
+ return (hash & 0xFFFFFFFF);
+}
+
+static __inline__ unsigned crush_hash32_5(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e) {
+ unsigned int hash = crush_hash_seed ^ a ^ b ^ c ^ d ^ e;
+ unsigned x = 231232;
+ unsigned y = 1232;
+ hashmix(a, b, hash);
+ hashmix(c, d, hash);
+ hashmix(e, x, hash);
+ hashmix(y, a, hash);
+ hashmix(b, x, hash);
+ hashmix(y, c, hash);
+ hashmix(d, x, hash);
+ hashmix(y, e, hash);
+ return (hash & 0xFFFFFFFF);
+}
+
+#endif
--- /dev/null
+
+#include "crush.h"
+#include "hash.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/** bucket choose methods **/
+
+/* uniform */
+
+static int
+crush_bucket_uniform_choose(struct crush_bucket_uniform *bucket, int x, int r)
+{
+ unsigned o, p, s;
+ o = crush_hash32_2(x, bucket->h.id) & 0xffff;
+ p = bucket->primes[crush_hash32_2(bucket->h.id, x) % bucket->h.size];
+ s = (x + o + (r+1)*p) % bucket->h.size;
+ /*printf("%d %d %d %d\n", x, o, r, p);*/
+ return bucket->h.items[s];
+}
+
+
+/* list */
+
+static int
+crush_bucket_list_choose(struct crush_bucket_list *bucket, int x, int r)
+{
+ int i;
+ __u64 w;
+
+ for (i=0; i<bucket->h.size; i++) {
+ w = crush_hash32_4(x, bucket->h.items[i], r, bucket->h.id);
+ w &= 0xffff;
+ /*printf("%d item %d weight %d sum_weight %d r %lld",
+ i, bucket->h.items[i], bucket->item_weights[i], bucket->sum_weights[i], w);*/
+ w *= bucket->sum_weights[i];
+ w = w >> 16;
+ /*printf(" scaled %lld\n", w);*/
+ if (w < bucket->item_weights[i])
+ return bucket->h.items[i];
+ }
+
+ BUG_ON(1);
+ return 0;
+}
+
+
+/* tree */
+
+static int height(int n) {
+ int h = 0;
+ while ((n & 1) == 0) {
+ h++;
+ n = n >> 1;
+ }
+ return h;
+}
+static int left(int x) {
+ int h = height(x);
+ return x - (1 << (h-1));
+}
+static int right(int x) {
+ int h = height(x);
+ return x + (1 << (h-1));
+}
+static int terminal(int x) {
+ return x & 1;
+}
+
+static int
+crush_bucket_tree_choose(struct crush_bucket_tree *bucket, int x, int r)
+{
+ int n, l;
+ __u32 w;
+ __u64 t;
+
+ /* start at root */
+ n = bucket->h.size >> 1;
+
+ while (!terminal(n)) {
+ /* pick point in [0, w) */
+ w = bucket->node_weights[n];
+ t = (__u64)crush_hash32_4(x, n, r, bucket->h.id) * (__u64)w;
+ t = t >> 32;
+
+ /* left or right? */
+ l = left(n);
+ if (t < bucket->node_weights[l])
+ n = l;
+ else
+ n = right(n);
+ }
+
+ return bucket->h.items[n];
+}
+
+
+/* straw */
+
+static int
+crush_bucket_straw_choose(struct crush_bucket_straw *bucket, int x, int r)
+{
+ int i;
+ int high = 0;
+ __u64 high_draw = 0;
+ __u64 draw;
+
+ for (i=0; i<bucket->h.size; i++) {
+ draw = crush_hash32_3(x, bucket->h.items[i], r);
+ draw &= 0xffff;
+ draw *= bucket->straws[i];
+ if (i == 0 || draw > high_draw) {
+ high = i;
+ high_draw = draw;
+ }
+ }
+
+ return bucket->h.items[high];
+}
+
+
+
+
+/** crush proper **/
+
+
+/*
+ * choose numrep distinct items of given type
+ */
+static int crush_choose(struct crush_map *map,
+ struct crush_bucket *bucket,
+ int x, int numrep, int type,
+ int *out, int firstn)
+{
+ int rep;
+ int ftotal, flocal;
+ int retry_descent, retry_bucket, skip_rep;
+ struct crush_bucket *in = bucket;
+ int r;
+ int i;
+ int item;
+ int itemtype;
+ int outpos;
+ int collide, bad;
+
+ outpos = 0;
+
+ for (rep = 0; rep < numrep; rep++) {
+ /* keep trying until we get a non-out, non-colliding item */
+ ftotal = 0;
+ skip_rep = 0;
+ do {
+ retry_descent = 0;
+ in = bucket; /* initial bucket */
+
+ /* choose through intervening buckets */
+ flocal = 0;
+ do {
+ retry_bucket = 0;
+ r = rep;
+ if (in->bucket_type == CRUSH_BUCKET_UNIFORM) {
+ /* be careful */
+ if (firstn || numrep >= in->size)
+ r += ftotal; /* r' = r + f_total */
+ else if (in->size % numrep == 0)
+ r += (numrep+1) * flocal; /* r'=r+(n+1)*f_local */
+ else
+ r += numrep * flocal; /* r' = r + n*f_local */
+ } else {
+ if (firstn)
+ r += ftotal; /* r' = r + f_total */
+ else
+ r += numrep * flocal; /* r' = r + n*f_local */
+ }
+
+ /* bucket choose */
+ switch (in->bucket_type) {
+ case CRUSH_BUCKET_UNIFORM:
+ item = crush_bucket_uniform_choose((struct crush_bucket_uniform*)in, x, r);
+ break;
+ case CRUSH_BUCKET_LIST:
+ item = crush_bucket_list_choose((struct crush_bucket_list*)in, x, r);
+ break;
+ case CRUSH_BUCKET_TREE:
+ item = crush_bucket_tree_choose((struct crush_bucket_tree*)in, x, r);
+ break;
+ case CRUSH_BUCKET_STRAW:
+ item = crush_bucket_straw_choose((struct crush_bucket_straw*)in, x, r);
+ break;
+ default:
+ BUG_ON(1);
+ }
+
+ /* desired type? */
+ if (item < 0)
+ itemtype = map->buckets[-1-item]->type;
+ else
+ itemtype = 0;
+
+ /* keep going? */
+ if (itemtype != type) {
+ BUG_ON(item >= 0 || (-1-item) >= map->max_buckets);
+ in = map->buckets[-1-item];
+ continue;
+ }
+
+ /* collision? */
+ collide = 0;
+ for (i=0; i<rep; i++) {
+ if (out[i] == item) {
+ collide = 1;
+ break;
+ }
+ }
+
+ /* bad (out)? */
+ bad = 0;
+ if (itemtype == 0 && map->device_offload[item]) {
+ if (map->device_offload[item] >= 0x10000)
+ bad = 1;
+ else if ((crush_hash32_2(x, item) & 0xffff) < map->device_offload[item])
+ bad = 1;
+ }
+
+ if (bad || collide) {
+ ftotal++;
+ flocal++;
+
+ if (collide && flocal < 3)
+ retry_bucket = 1; /* retry locally a few times */
+ else if (ftotal < 10)
+ retry_descent = 1; /* then retry descent */
+ else
+ skip_rep = 1; /* else give up */
+ }
+ } while (retry_bucket);
+ } while (retry_descent);
+
+ if (skip_rep) continue;
+
+ out[outpos] = item;
+ outpos++;
+ }
+
+ return outpos;
+}
+
+
+int crush_do_rule(struct crush_map *map,
+ int ruleno,
+ int x, int *result, int result_max,
+ int forcefeed) /* -1 for none */
+{
+ int result_len;
+ int force_stack[CRUSH_MAX_DEPTH];
+ int force_pos = -1;
+ int a[CRUSH_MAX_SET];
+ int b[CRUSH_MAX_SET];
+ int *w;
+ int wsize = 0;
+ int *o;
+ int osize;
+ int *tmp;
+ struct crush_rule *rule;
+ int step;
+ int i;
+ int numrep;
+
+ rule = map->rules[ruleno];
+ result_len = 0;
+ w = a;
+ o = b;
+
+ /* determine hierarchical context of forcefeed, if any */
+ if (forcefeed >= 0) {
+ if (map->device_parents[forcefeed] == 0) {
+ /*printf("CRUSH: forcefed device dne\n");*/
+ return -1; /* force fed device dne */
+ }
+ while (1) {
+ force_stack[++force_pos] = forcefeed;
+ /*printf("force_stack[%d] = %d\n", force_pos, forcefeed);*/
+ if (forcefeed >= 0)
+ forcefeed = map->device_parents[forcefeed];
+ else
+ forcefeed = map->bucket_parents[-1-forcefeed];
+ if (forcefeed == 0) break;
+ }
+ }
+
+ for (step = 0; step < rule->len; step++) {
+ switch (rule->steps[step].op) {
+ case CRUSH_RULE_TAKE:
+ if (force_pos >= 0) {
+ w[0] = force_stack[force_pos];
+ force_pos--;
+ BUG_ON(w[0] != rule->steps[step].arg1);
+ } else {
+ w[0] = rule->steps[step].arg1;
+ }
+ wsize = 1;
+ break;
+
+ case CRUSH_RULE_CHOOSE_FIRSTN:
+ case CRUSH_RULE_CHOOSE_INDEP:
+ BUG_ON(wsize == 0);
+
+ /* reset output */
+ osize = 0;
+
+ for (i = 0; i < wsize; i++) {
+ numrep = rule->steps[step].arg1;
+ if (force_pos >= 0) {
+ o[osize++] = force_stack[force_pos];
+ force_pos--;
+ numrep--;
+ }
+ if (!numrep) continue;
+ osize += crush_choose(map,
+ map->buckets[-1-w[i]],
+ x, numrep, rule->steps[step].arg2,
+ o+osize, rule->steps[step].op == CRUSH_RULE_CHOOSE_FIRSTN);
+ }
+
+ /* swap t and w arrays */
+ tmp = o;
+ o = w;
+ w = tmp;
+ wsize = osize;
+ break;
+
+
+ case CRUSH_RULE_EMIT:
+ for (i=0; i<wsize && result_max; i++) {
+ result[result_len] = w[i];
+ result_len++;
+ result_max--;
+ }
+ wsize = 0;
+ break;
+
+ default:
+ BUG_ON(1);
+ }
+ }
+
+ return result_len;
+}
+
+
--- /dev/null
+#ifndef _CRUSH_MAPPER_H
+#define _CRUSH_MAPPER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "crush.h"
+
+extern int crush_do_rule(struct crush_map *map,
+ int ruleno,
+ int x, int *result, int result_max,
+ int forcefeed); /* -1 for none */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "crush.h"
+#include "mapper.h"
+#include "builder.h"
+
+
+int main()
+{
+ int sub[10];
+ int subw[10];
+ int i, j;
+ int d;
+ int o[100];
+ int root;
+ int ruleno;
+ int r[10];
+
+ int uw[10] = { 1000, 1000, 500, 1000, 2000, 1000, 1000, 3000, 1000, 500 };
+
+ struct crush_bucket *b;
+ struct crush_rule *rule;
+
+ struct crush_map *map = crush_create();
+
+ d = 0;
+ for (i=0; i<10; i++) {
+ for (j=0; j<10; j++)
+ o[j] = d++;
+ b = (struct crush_bucket*)crush_make_uniform_bucket(1, 10, o, uw[i]);
+ sub[i] = crush_add_bucket(map, b);
+ subw[i] = b->weight;
+ printf("make bucket %d weight %d\n", sub[i], subw[i]);
+ }
+
+ root = crush_add_bucket(map, (struct crush_bucket*)crush_make_tree_bucket(2, 10, sub, subw));
+
+ rule = crush_make_rule();
+ crush_rule_add_step(rule, CRUSH_RULE_TAKE, root, 0);
+ crush_rule_add_step(rule, CRUSH_RULE_CHOOSE_FIRSTN, 3, 1);
+ crush_rule_add_step(rule, CRUSH_RULE_CHOOSE_FIRSTN, 1, 0);
+ crush_rule_add_step(rule, CRUSH_RULE_EMIT, 0, 0);
+ ruleno = crush_add_rule(map, -1, rule);
+
+ crush_finalize(map);
+ printf("built\n");
+
+ /* test */
+ memset(o, 0, 100*sizeof(o[0]));
+ for (i=0; i<1000000; i++) {
+ crush_do_rule(map, ruleno, i, r, 3, -1);
+ /*printf("%d %d %d\n", r[0], r[1], r[2]);*/
+ for (j=0; j<3; j++)
+ o[r[j]]++;
+ }
+
+ for (i=0; i<100; i += 10)
+ printf("%2d : %d\n", i, o[i]);
+
+ return 0;
+}
+++ /dev/null
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
-{
- vector<int> v(numrep);
- map<int,int> ocount;
-
- for (int x=1; x<=numpg; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- bool bad = false;
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- for (int j=i+1; j<numrep; j++) {
- if (v[i] == v[j])
- bad = true;
- }
- }
- //if (bad)
- // cout << "bad set " << x << ": " << v << endl;
-
- placement[x] = v;
-
- //cout << v << "\t" << ocount << endl;
- }
-
- if (0)
- for (map<int,int>::iterator it = ocount.begin();
- it != ocount.end();
- it++)
- cout << it->first << "\t" << it->second << endl;
-
-}
-
-
-float testmovement(int n, float f, int buckettype)
-{
- Hash h(73232313);
-
- // crush
- Crush c;
-
- int ndisks = 0;
-
- // bucket
- Bucket *b;
- if (buckettype == 0)
- b = new TreeBucket(1);
- else if (buckettype == 1 || buckettype == 2)
- b = new ListBucket(1);
- else if (buckettype == 3)
- b = new StrawBucket(1);
- else if (buckettype == 4)
- b = new UniformBucket(0,0);
-
- for (int i=0; i<n; i++)
- b->add_item(ndisks++,1);
-
- c.add_bucket(b);
- int root = b->get_id();
-
- //c.print(cout,root);
-
- // rule
- int numrep = 2;
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
- //c.overload[10] = .1;
-
-
- int pg_per = 1000;
- int numpg = pg_per*ndisks/numrep;
-
- vector<int> ocount(ndisks);
-
- /*
- cout << ndisks << " disks, " << endl;
- cout << pg_per << " pgs per disk" << endl;
- cout << numpg << " logical pgs" << endl;
- cout << "numrep is " << numrep << endl;
- */
- map<int, vector<int> > placement1, placement2;
-
- //c.print(cout, root);
-
-
- // ORIGINAL
- place(c, rule, numpg, numrep, placement1);
-
- int olddisks = ndisks;
-
- // add item
- if (buckettype == 2) {
- // start over!
- ndisks = 0;
- b = new ListBucket(1);
- for (int i=0; i<=n; i++)
- b->add_item(ndisks++,1);
- c.add_bucket(b);
- root = b->get_id();
-
- rule.steps.clear();
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
- }
- else
- b->add_item(ndisks++, 1);
-
-
- // ADDED
- //c.print(cout, root);
- place(c, rule, numpg, numrep, placement2);
-
- int moved = 0;
- for (int x=1; x<=numpg; x++)
- if (placement1[x] != placement2[x])
- for (int j=0; j<numrep; j++)
- if (placement1[x][j] != placement2[x][j])
- moved++;
-
- int total = numpg*numrep;
- float actual = (float)moved / (float)(total);
- float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
- float fac = actual/ideal;
- //cout << add << "\t" << olddisks << "\t" << ndisks << "\t" << moved << "\t" << total << "\t" << actual << "\t" << ideal << "\t" << fac << endl;
- cout << "\t" << fac;
- return fac;
-}
-
-
-int main()
-{
- //cout << "// " << depth << ", modifydepth " << modifydepth << ", branching " << branching << ", disks " << n << endl;
- cout << "n\ttree\tlhead\tltail\tstraw\tuniform" << endl;
-
- //for (int s=2; s<=64; s+= (s<4?1:(s<16?2:4))) {
- for (int s=2; s<=64; s+= (s<4?1:4)) {
- float f = 1.0 / (float)s;
- //cout << f << "\t" << s;
- cout << s;
- for (int buckettype=0; buckettype<5; buckettype++)
- testmovement(s, f, buckettype);
- cout << endl;
- }
-}
-
+++ /dev/null
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
- if (h == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
- for (int i=0; i<wid[h]; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 10, disks);
- b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
- return b;
- } else {
- // mixed
- //Bucket *b = new MixedBucket(h+1);
- Bucket *b = new StrawBucket(h+1);
- for (int i=0; i<wid[h]; i++) {
- Bucket *n = make_bucket(c, wid, h-1, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- }
- c.add_bucket(b);
- //cout << h << " mixedbucket with " << wid[h] << endl;
- return b;
- }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
- Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
- return b->get_id();
-}
-
-
-float go(int dep)
-{
- Hash h(73232313);
-
- // crush
- Crush c;
-
-
- // buckets
- int root = -1;
- int ndisks = 0;
-
- vector<int> wid;
- if (0) {
- for (int d=0; d<dep; d++)
- wid.push_back(10);
- }
- if (1) {
- if (dep == 0)
- wid.push_back(1000);
- if (dep == 1) {
- wid.push_back(1);
- wid.push_back(1000);
- }
- if (dep == 2) {
- wid.push_back(5);
- wid.push_back(5);
- wid.push_back(8);
- wid.push_back(5);
- }
- }
-
- if (1) {
- root = make_hierarchy(c, wid, ndisks);
- }
- if (0) {
- MixedBucket *b = new MixedBucket(1);
- for (int i=0; i<10000; i++)
- b->add_item(ndisks++, 10);
- root = c.add_bucket(b);
- }
- if (0) {
- vector<int> disks;
- for (int i=0; i<10000; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 10000, disks);
- Hash h(123);
- b->make_primes(h);
- root = c.add_bucket(b);
- }
-
-
-
- // rule
- int numrep = 1;
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
- //c.overload[10] = .1;
-
-
- int pg_per = 100;
- int numpg = pg_per*ndisks/numrep;
-
- vector<int> ocount(ndisks);
- //cout << ndisks << " disks, " << endl;
- //cout << pg_per << " pgs per disk" << endl;
- // cout << numpg << " logical pgs" << endl;
- //cout << "numrep is " << numrep << endl;
-
-
- int place = 100000;
- int times = place / numpg;
- if (!times) times = 1;
-
- cout << "#looping " << times << " times" << endl;
-
- float tvar = 0;
- int tvarnum = 0;
-
- int x = 0;
- for (int t=0; t<times; t++) {
- vector<int> v(numrep);
-
- for (int z=0; z<ndisks; z++) ocount[z] = 0;
-
- for (int xx=1; xx<numpg; xx++) {
- x++;
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- bool bad = false;
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- for (int j=i+1; j<numrep; j++) {
- if (v[i] == v[j])
- bad = true;
- }
- }
- if (bad)
- cout << "bad set " << x << ": " << v << endl;
-
- //cout << v << "\t" << ocount << endl;
- }
-
- /*
- for (int i=0; i<ocount.size(); i++) {
- cout << "disk " << i << " has " << ocount[i] << endl;
- }
- */
-
- //cout << "collisions: " << c.collisions << endl;
- //cout << "r bumps: " << c.bumps << endl;
-
-
- float avg = 0.0;
- for (int i=0; i<ocount.size(); i++)
- avg += ocount[i];
- avg /= ocount.size();
- float var = 0.0;
- for (int i=0; i<ocount.size(); i++)
- var += (ocount[i] - avg) * (ocount[i] - avg);
- var /= ocount.size();
-
- //cout << "avg " << avg << " var " << var << " sd " << sqrt(var) << endl;
- //cout << avg << "\t";
-
- tvar += var;
- tvarnum++;
- }
-
- tvar /= tvarnum;
-
- //cout << "total variance " << tvar << endl;
-
- return tvar;
-}
-
-
-int main()
-{
- for (int d=0; d<=2; d++) {
- float var = go(d);
- //cout << "## depth = " << d << endl;
- cout << d << "\t" << var << "\t" << sqrt(var) << endl;
- }
-}
+++ /dev/null
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-int buckettype = 0;
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
- if (h == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
- for (int i=0; i<wid[h]; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 1, disks);
- //b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
- buckets[h].push_back(b);
- return b;
- } else {
- // mixed
- //Bucket *b = new TreeBucket(h+1);
- //Bucket *b = new ListBucket(h+1);
- //Bucket *b = new StrawBucket(h+1);
- Bucket *b;
- if (buckettype == 0)
- b = new TreeBucket(h+1);
- else if (buckettype == 1 || buckettype == 2)
- b = new ListBucket(h+1);
- else if (buckettype == 3)
- b = new StrawBucket(h+1);
-
- c.add_bucket(b);
- for (int i=0; i<wid[h]; i++) {
- Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- n->set_parent(b->get_id());
- }
- buckets[h].push_back(b);
- //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
- return b;
- }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
- Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
- return b->get_id();
-}
-
-
-void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
-{
- vector<int> v(numrep);
- map<int,int> ocount;
-
- for (int x=1; x<=numpg; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- bool bad = false;
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- for (int j=i+1; j<numrep; j++) {
- if (v[i] == v[j])
- bad = true;
- }
- }
-
- placement[x] = v;
-
- //cout << v << "\t" << ocount << endl;
- }
-
- if (0)
- for (map<int,int>::iterator it = ocount.begin();
- it != ocount.end();
- it++)
- cout << it->first << "\t" << it->second << endl;
-
-}
-
-
-float testmovement(int depth, int branching, int udisks, int add, int modifydepth)
-{
- Hash h(73232313);
-
- // crush
- Crush c;
-
-
- // buckets
- int root = -1;
- int ndisks = 0;
-
- vector<int> wid;
- wid.push_back(udisks);
- for (int d=1; d<depth; d++)
- wid.push_back(branching);
-
- map< int, list<Bucket*> > buckets;
-
- root = make_hierarchy(c, wid, buckets, ndisks);
-
- //c.print(cout,root);
-
- // rule
- int numrep = 2;
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
- //c.overload[10] = .1;
-
-
- int pg_per = 100;
- int numpg = pg_per*ndisks/numrep;
-
- vector<int> ocount(ndisks);
-
- /*
- cout << ndisks << " disks, " << endl;
- cout << pg_per << " pgs per disk" << endl;
- cout << numpg << " logical pgs" << endl;
- cout << "numrep is " << numrep << endl;
- */
- map<int, vector<int> > placement1, placement2;
-
- //c.print(cout, root);
-
-
- // ORIGINAL
- place(c, rule, numpg, numrep, placement1);
-
- int olddisks = ndisks;
-
- // add disks
- //cout << " adding " << add << " disks" << endl;
- vector<int> disks;
- for (int i=0; i<add; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 1, disks);
- //b->make_primes(h);
-
- //Bucket *o = buckets[2].back();
- Bucket *o;
- if (buckettype == 2)
- o = buckets[modifydepth].front();
- else
- o = buckets[modifydepth].back();
-
- c.add_bucket(b);
- //cout << " adding under " << o->get_id() << endl;
- c.add_item(o->get_id(), b->get_id(), b->get_weight());
- //((MixedBucket*)o)->add_item(b->get_id(), b->get_weight());
- //newbucket = b;
-
-
- // ADDED
- //c.print(cout, root);
- place(c, rule, numpg, numrep, placement2);
-
- int moved = 0;
- for (int x=1; x<=numpg; x++)
- if (placement1[x] != placement2[x])
- for (int j=0; j<numrep; j++)
- if (placement1[x][j] != placement2[x][j])
- moved++;
-
- int total = numpg*numrep;
- float actual = (float)moved / (float)(total);
- float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
- float fac = actual/ideal;
- //cout << add << "\t" << olddisks << "\t" << ndisks << "\t" << moved << "\t" << total << "\t" << actual << "\t" << ideal << "\t" << fac << endl;
- cout << "\t" << fac;
- return fac;
-}
-
-
-int main()
-{
-
- int udisks = 10;
- int add = udisks;
-
- //int depth = 3;
- //int branching = 25;
- int depth = 4;
- int branching = 9;
-
- int modifydepth = 1;
- int bfac = (int)(sqrt((double)branching));
- int n = (int)(udisks * pow((float)branching, (float)depth-1));
-
- cout << "// depth " << depth << ", modifydepth " << modifydepth << ", branching " << branching << ", disks " << n << endl;
- cout << "n\ttree\tlhead\tltail\tstraw" << endl;
- for (int add = udisks; add <= n; add *= bfac) {
- cout << add;
- for (buckettype=0; buckettype<4; buckettype++)
- testmovement(depth, branching, udisks, add, modifydepth);
- cout << endl;
- }
-}
-
+++ /dev/null
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-int buckettype = 2; // 0 = mixed, 1 = linear, 2 = straw
-
-int big_one_skip = 255;
-int big_one_size;
-Bucket *big_one = 0;
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
- if (h == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
-
- int s = wid[h];
- if (big_one_skip > 0)
- big_one_skip--;
- if (!big_one_skip && !big_one)
- s = big_one_size;
-
-
- for (int i=0; i<s; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 1, disks);
- if (!big_one_skip && !big_one) big_one = b;
- b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks " << disks.size()<< endl;
- buckets[h].push_back(b);
- return b;
- } else {
- // mixed
- Bucket *b;
- if (buckettype == 0)
- b = new TreeBucket(h+1);
- else if (buckettype == 1)
- b = new ListBucket(h+1);
- else if (buckettype == 2)
- b = new StrawBucket(h+1);
- c.add_bucket(b);
- for (int i=0; i<wid[h]; i++) {
- Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- n->set_parent(b->get_id());
- }
- buckets[h].push_back(b);
- //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
- return b;
- }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
- Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
- return b->get_id();
-}
-
-
-void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
-{
- vector<int> v(numrep);
- map<int,int> ocount;
-
- for (int x=1; x<=numpg; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- bool bad = false;
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- for (int j=i+1; j<numrep; j++) {
- if (v[i] == v[j])
- bad = true;
- }
- }
- if (bad)
- cout << "bad set " << x << ": " << v << endl;
-
- placement[x] = v;
-
- //cout << v << "\t" << ocount << endl;
- }
-
- if (0)
- for (map<int,int>::iterator it = ocount.begin();
- it != ocount.end();
- it++)
- cout << it->first << "\t" << it->second << endl;
-
-}
-
-
-float testmovement(int depth, int branching, int udisks, int add)
-{
- Hash h(73232313);
-
- // crush
- Crush c;
-
-
- // buckets
- int root = -1;
- int ndisks = 0;
-
- vector<int> wid;
- wid.push_back(udisks);
- for (int d=1; d<depth; d++)
- wid.push_back(branching + ((d==2)?1:0));
-
- map< int, list<Bucket*> > buckets;
-
- big_one_size = add;
- big_one = 0;
-
- //cout << "making tree" << endl;
- root = make_hierarchy(c, wid, buckets, ndisks);
-
- //c.print(cout, root);
-
-
- // rule
- int numrep = 2;
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
- //c.overload[10] = .1;
-
-
- int pg_per = 100;
- int numpg = pg_per*ndisks/numrep;
-
- vector<int> ocount(ndisks);
-
- /*
- cout << ndisks << " disks, " << endl;
- cout << pg_per << " pgs per disk" << endl;
- cout << numpg << " logical pgs" << endl;
- cout << "numrep is " << numrep << endl;
- */
- map<int, vector<int> > placement1, placement2;
-
- //c.print(cout, root);
-
- int olddisks = ndisks;
-
-
- place(c, rule, numpg, numrep, placement1);
-
- if (1) {
- // remove disks
- assert(big_one);
- c.adjust_item(big_one->get_id(), 0);
- }
-
- int newdisks = ndisks - add;
-
- //c.print(cout, root);
- place(c, rule, numpg, numrep, placement2);
-
- int moved = 0;
- for (int x=1; x<=numpg; x++)
- if (placement1[x] != placement2[x])
- for (int j=0; j<numrep; j++)
- if (placement1[x][j] != placement2[x][j])
- moved++;
-
- int total = numpg*numrep;
- float actual = (float)moved / (float)(total);
- //float ideal = (float)(newdisks-olddisks) / (float)(ndisks);
- float ideal = (float)(olddisks-newdisks) / (float)(olddisks);
- float fac = actual/ideal;
- cout << add << "\t" << olddisks << "\t" << ndisks << "\t" << moved << "\t" << total << "\t" << actual << "\t" << ideal << "\t" << fac << endl;
- return fac;
-}
-
-
-int main()
-{
-
- int udisks = 10;
- int ndisks = 10;
- int depth = 4;
- int branching = 9;
- int add = udisks;
-
- //cout << "\t" << n;
- // cout << endl;
-
- buckettype = 2; // 0 = tree, 1 = linear, 2 = straw
-
- int n = udisks * pow((float)branching, (float)depth-1);
- for (int add = udisks; add <= n; add *= 3) {
- big_one_skip = 0;
- big_one_skip = 9;
- testmovement(depth, branching, udisks, add);
- }
-
- /*
- cout << "##" << endl;
- for (map<int, map<float,float> >::iterator i = r.begin();
- i != r.end();
- i++) {
- cout << i->first;
- for (map<float,float>::iterator j = i->second.begin();
- j != i->second.end();
- j++)
- cout << "\t" << j->first << "\t" << j->second;
- cout << endl;
- }
- */
-}
-
+++ /dev/null
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-int buckettype = 0;
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
- if (h == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
- for (int i=0; i<wid[h]; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 1, disks);
- //b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
- buckets[h].push_back(b);
- return b;
- } else {
- // mixed
- //Bucket *b = new TreeBucket(h+1);
- //Bucket *b = new ListBucket(h+1);
- //Bucket *b = new StrawBucket(h+1);
- Bucket *b;
- if (buckettype == 0)
- b = new TreeBucket(h+1);
- else if (buckettype == 1 || buckettype == 2)
- b = new ListBucket(h+1);
- else if (buckettype == 3)
- b = new StrawBucket(h+1);
-
- c.add_bucket(b);
- for (int i=0; i<wid[h]; i++) {
- Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- n->set_parent(b->get_id());
- }
- buckets[h].push_back(b);
- //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
- return b;
- }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
- Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
- return b->get_id();
-}
-
-
-void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
-{
- vector<int> v(numrep);
- map<int,int> ocount;
-
- for (int x=1; x<=numpg; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- bool bad = false;
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- for (int j=i+1; j<numrep; j++) {
- if (v[i] == v[j])
- bad = true;
- }
- }
-
- placement[x] = v;
-
- //cout << v << "\t" << ocount << endl;
- }
-
- if (0)
- for (map<int,int>::iterator it = ocount.begin();
- it != ocount.end();
- it++)
- cout << it->first << "\t" << it->second << endl;
-
-}
-
-
-float testmovement(int depth, int branching, int udisks, int add, int modifydepth)
-{
- Hash h(73232313);
-
- // crush
- Crush c;
-
-
- // buckets
- int root = -1;
- int ndisks = 0;
-
- vector<int> wid;
- wid.push_back(udisks);
- for (int d=1; d<depth; d++)
- wid.push_back(branching);
-
- map< int, list<Bucket*> > buckets;
-
- root = make_hierarchy(c, wid, buckets, ndisks);
-
- //c.print(cout,root);
-
- // rule
- int numrep = 2;
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
- //c.overload[10] = .1;
-
-
- int pg_per = 100;
- int numpg = pg_per*ndisks/numrep;
-
- vector<int> ocount(ndisks);
-
- /*
- cout << ndisks << " disks, " << endl;
- cout << pg_per << " pgs per disk" << endl;
- cout << numpg << " logical pgs" << endl;
- cout << "numrep is " << numrep << endl;
- */
- map<int, vector<int> > placement1, placement2;
-
- //c.print(cout, root);
-
-
- // ORIGINAL
- place(c, rule, numpg, numrep, placement1);
-
- int olddisks = ndisks;
-
- // add disks
- //cout << " adding " << add << " disks" << endl;
- vector<int> disks;
- for (int i=0; i<add; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 1, disks);
- //b->make_primes(h);
-
- //Bucket *o = buckets[2].back();
- Bucket *o;
- if (buckettype == 2)
- o = buckets[modifydepth].front();
- else
- o = buckets[modifydepth].back();
-
- c.add_bucket(b);
- //cout << " adding under " << o->get_id() << endl;
- c.add_item(o->get_id(), b->get_id(), b->get_weight(), buckettype == 2);
- //((MixedBucket*)o)->add_item(b->get_id(), b->get_weight());
- //newbucket = b;
-
-
- // ADDED
- //c.print(cout, root);
- place(c, rule, numpg, numrep, placement2);
-
- int moved = 0;
- for (int x=1; x<=numpg; x++)
- if (placement1[x] != placement2[x])
- for (int j=0; j<numrep; j++)
- if (placement1[x][j] != placement2[x][j])
- moved++;
-
- int total = numpg*numrep;
- float actual = (float)moved / (float)(total);
- float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
- float fac = actual/ideal;
- //cout << add << "\t" << olddisks << "\t" << ndisks << "\t" << moved << "\t" << total << "\t" << actual << "\t" << ideal << "\t" << fac << endl;
- cout << "\t" << fac;
- return fac;
-}
-
-
-int main()
-{
-
- int udisks = 10;
- int add = udisks;
-
- //int depth = 3;
- //int branching = 25;
- int depth = 2;
- int branching = 9*9*9;
-
- int modifydepth = 1;
- int bfac = (int)(sqrt((double)branching));
- bfac = 3;
- int n = (int)(udisks * pow((float)branching, (float)depth-1));
-
- cout << "// depth " << depth << ", modifydepth " << modifydepth << ", branching " << branching << ", disks " << n << endl;
- cout << "n\ttree\tlhead\tltail\tstraw" << endl;
- for (int add = udisks; add <= n; add *= bfac) {
- cout << add;
- for (buckettype=0; buckettype<3; buckettype++)
- testmovement(depth, branching, udisks, add, modifydepth);
- cout << endl;
- }
-}
-
+++ /dev/null
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include "../../common/Clock.h"
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Clock g_clock;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
- if (h == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
- for (int i=0; i<wid[h]; i++)
- disks.push_back(ndisks++);
- float w = 10;//((ndisks-1)/100+1)*10;
- UniformBucket *b = new UniformBucket(1, 0, w, disks);
- //b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks weight " << w << endl;
- return b;
- } else {
- // mixed
- Bucket *b = new TreeBucket(h+1);
- for (int i=0; i<wid[h]; i++) {
- Bucket *n = make_bucket(c, wid, h-1, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- }
- c.add_bucket(b);
- //cout << h << " mixedbucket with " << wid[h] << endl;
- return b;
- }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
- Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
- return b->get_id();
-}
-
-
-
-float go(int dep, int failpc)
-{
- Hash h(73232313);
-
- //int overloadcutoff = (int)((float)10000.0 / (float)utilization);
-
- //cout << "util " << utilization << " cutoff " << overloadcutoff << endl;
- // crush
- Crush c;
-
-
- // buckets
- int root = -1;
- int ndisks = 0;
-
- vector<int> wid;
- for (int d=0; d<dep; d++)
- wid.push_back(10);
-
- if (1) {
- root = make_hierarchy(c, wid, ndisks);
- }
-
- //cout << ndisks << " disks" << endl;
-
-
- int numf = ndisks * failpc / 100;
-
-
-
-
- // rule
- int numrep = 1;
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
- //c.overload[10] = .1;
-
- int pg_per_base = 100;//20;
- int pg_med = 10*pg_per_base;
- int pg_per = pg_per_base*5.5;//100;
- int numpg = pg_per*ndisks/numrep;
-
- vector<int> ocount(ndisks);
- //cout << ndisks << " disks, " << endl;
- //cout << pg_per << " pgs per disk" << endl;
- // cout << numpg << " logical pgs" << endl;
- //cout << "numrep is " << numrep << endl;
-
-
- int place = 1000000;
- int times = place / numpg;
- if (!times) times = 1;
-
-
- //cout << "looping " << times << " times" << endl;
-
- float tavg[10];
- float tvar[10];
- for (int j=0;j<10;j++) {
- tvar[j] = 0;
- tavg[j] = 0;
- }
- int tvarnum = 0;
- float trvar = 0.0;
-
- float overloadsum = 0.0;
- float adjustsum = 0.0;
- float afteroverloadsum = 0.0;
- float aslowdown = 0.0;
- int chooses = 0;
- int xs = 1;
- for (int t=0; t<times; t++) {
- vector<int> v(numrep);
-
- c.out.clear();
-
- for (int z=0; z<ndisks; z++) ocount[z] = 0;
-
- utime_t t1a = g_clock.now();
- for (int x=xs; x<numpg+xs; x++) {
- c.do_rule(rule, x, v);
- //chooses += numrep;
- for (int i=0; i<v.size(); i++) {
- //if (v[i] >= ndisks) cout << "v[i] " << i << " is " << v[i] << " .. x = " << x << endl;
- //assert(v[i] < ndisks);
- ocount[v[i]]++;
- }
- }
- utime_t t1b = g_clock.now();
-
- // add in numf failed disks
- for (int f = 0; f < numf; f++) {
- int d = rand() % ndisks;
- while (c.out.count(d)) d = rand() % ndisks;
- c.out.insert(d);
- }
-
- utime_t t3a = g_clock.now();
- for (int x=xs; x<numpg+xs; x++) {
- c.do_rule(rule, x, v);
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- for (int i=0; i<v.size(); i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- }
-
- //cout << v << "\t" << ocount << endl;
- }
- xs += numpg;
-
- utime_t t3b = g_clock.now();
-
- t1b -= t1a;
- double t1 = (double)t1b;
- t3b -= t3a;
- double t3 = (double)t3b;
- double slowdown = t3/t1;
- //cout << "slowdown " << slowdown << endl;
- aslowdown += slowdown;
-
- //cout << "collisions: " << c.collisions << endl;
- //cout << "r bumps: " << c.bumps << endl;
-
- // stair var calc
- int n = ndisks/10;
- float avg[10];
- float var[10];
- for (int i=0;i<10;i++) {
- int s = n*i;
- avg[i] = 0.0;
- int nf = 0;
- for (int j=0; j<n; j++) {
- if (c.out.count(j+s)) { nf++; continue; }
- avg[i] += ocount[j+s];
- }
- avg[i] /= (n-nf);//ocount.size();
- var[i] = 0.0;
- for (int j=0; j<n; j++) {
- if (c.out.count(j+s)) continue;
- var[i] += (ocount[j+s] - avg[i]) * (ocount[j+s] - avg[i]);
- }
- var[i] /= (n-nf);//ocount.size();
-
- tvar[i] += var[i];
- tavg[i] += avg[i];
- }
- //cout << "avg " << avg << " var " << var << " sd " << sqrt(var) << endl;
-
- tvarnum++;
-
- // flat var calc
- int na = ndisks - numf; // num active
- float ravg = 0.0;
- for (int i=0;i<ndisks;i++) {
- if (c.out.count(i)) continue;
- ravg += ocount[i];
- }
- ravg /= (float)na;
- float rvar = 0.0;
- for (int i=0; i<ndisks; i++) {
- if (c.out.count(i)) continue;
- rvar += (ravg-(float)ocount[i])*(ravg-(float)ocount[i]);
- }
- rvar /= (float)na;
-
- trvar += rvar;
- }
-
-
- trvar /= (float)tvarnum;
-
- //overloadsum /= tvarnum;
- //adjustsum /= tvarnum;
- float avar = 0.0;
- for (int j=0;j<10;j++) {
- tvar[j] /= tvarnum;
- tavg[j] /= tvarnum;
- avar += tvar[j];
- }
- avar /= 10;
- avar = sqrt(avar);
- avar /= /*5.5 **/ (float)pg_per_base;
- //afteroverloadsum /= tvarnum;
- aslowdown /= tvarnum;
-
- //int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
- //float crate = (float) collisions / (float)chooses;
- //cout << "collisions: " << c.collisions << endl;
-
-
- //cout << "total variance " << tvar << endl;
- //cout << " overlaod " << overloadsum << endl;
-
- cout << failpc
- << "\t" << numf
- //<< "\t" << adjustsum
- //<< "\t" << afteroverloadsum
- << "\t" << aslowdown
- << "\t" << trvar
- << "\t" << sqrt(trvar) / (float)pg_per_base
- << "\t..\t" << avar
- << "\t-";
-
- for (int i=0;i<10;i++)
- cout << "\t" << tavg[i] << "\t" << sqrt(tvar[i]);// << "\t" << tvar[i]/tavg[i];
-
- cout << endl;
- return tvar[0];
-}
-
-
-int main()
-{
- for (int pc = 0; pc < 90; pc += 5) {
- float var = go(3, pc);
- }
-
-
-}
+++ /dev/null
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
- if (h == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
- for (int i=0; i<wid[h]; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 10, disks);
- //b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
- return b;
- } else {
- // mixed
- MixedBucket *b = new MixedBucket(h+1);
- for (int i=0; i<wid[h]; i++) {
- Bucket *n = make_bucket(c, wid, h-1, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- }
- c.add_bucket(b);
- //cout << h << " mixedbucket with " << wid[h] << endl;
- return b;
- }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
- Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
- return b->get_id();
-}
-
-
-Bucket *make_random(Crush& c, int wid, int height, int& ndisks)
-{
- int w = rand() % (wid-1) + 2;
-
- if (height == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
- for (int i=0; i<w; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 10, disks);
- b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
- return b;
- } else {
- // mixed
- int h = rand() % height + 1;
- MixedBucket *b = new MixedBucket(h+1);
- for (int i=0; i<w; i++) {
- Bucket *n = make_random(c, wid, h-1, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- }
- c.add_bucket(b);
- //cout << h << " mixedbucket with " << wid[h] << endl;
- return b;
- }
-
-}
-
-
-float go(int dep, int overloadcutoff)
-{
- Hash h(73232313);
-
- // crush
- Crush c;
-
-
- // buckets
- int root = -1;
- int ndisks = 0;
-
- vector<int> wid;
- for (int d=0; d<dep; d++)
- wid.push_back(10);
-
- if (1) {
- root = make_hierarchy(c, wid, ndisks);
- }
- if (0) {
- Bucket *r = make_random(c, 20, 4, ndisks);
- root = r->get_id();
- //c.print(cout, root);
- }
- if (0) {
- MixedBucket *b = new MixedBucket(1);
- for (int i=0; i<10000; i++)
- b->add_item(ndisks++, 10);
- root = c.add_bucket(b);
- }
- if (0) {
- vector<int> disks;
- for (int i=0; i<10000; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 10000, disks);
- Hash h(123);
- b->make_primes(h);
- root = c.add_bucket(b);
- }
- //cout << ndisks << " disks" << endl;
-
-
-
- // rule
- int numrep = 1;
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
- //c.overload[10] = .1;
-
-
- int pg_per = 100;
- int numpg = pg_per*ndisks/numrep;
-
- vector<int> ocount(ndisks);
- //cout << ndisks << " disks, " << endl;
- //cout << pg_per << " pgs per disk" << endl;
- // cout << numpg << " logical pgs" << endl;
- //cout << "numrep is " << numrep << endl;
-
-
- int place = 1000000;
- int times = place / numpg;
- if (!times) times = 1;
-
-
- //cout << "looping " << times << " times" << endl;
-
- float tvar = 0;
- int tvarnum = 0;
-
- float overloadsum = 0.0;
- float adjustsum = 0.0;
- float afteroverloadsum = 0.0;
- int chooses = 0;
- int xs = 1;
- for (int t=0; t<times; t++) {
- vector<int> v(numrep);
-
- c.overload.clear();
-
- for (int z=0; z<ndisks; z++) ocount[z] = 0;
-
- for (int x=xs; x<numpg+xs; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- chooses += numrep;
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- bool bad = false;
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- for (int j=i+1; j<numrep; j++) {
- if (v[i] == v[j])
- bad = true;
- }
- }
- if (bad)
- cout << "bad set " << x << ": " << v << endl;
-
- //cout << v << "\t" << ocount << endl;
- }
-
- // overloaded?
- int overloaded = 0;
- int adjusted = 0;
- for (int i=0; i<ocount.size(); i++) {
- if (ocount[i] > overloadcutoff)
- overloaded++;
-
- if (ocount[i] > 100+(overloadcutoff-100)/2) {
- adjusted++;
- c.overload[i] = 100.0 / (float)ocount[i];
- //cout << "disk " << i << " has " << ocount[i] << endl;
- }
- ocount[i] = 0;
- }
- //cout << overloaded << " overloaded" << endl;
- overloadsum += (float)overloaded / (float)ndisks;
- adjustsum += (float)adjusted / (float)ndisks;
-
-
- for (int x=xs; x<numpg+xs; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- bool bad = false;
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- for (int j=i+1; j<numrep; j++) {
- if (v[i] == v[j])
- bad = true;
- }
- }
- if (bad)
- cout << "bad set " << x << ": " << v << endl;
-
- //cout << v << "\t" << ocount << endl;
- }
- xs += numpg;
-
- int still = 0;
- for (int i=0; i<ocount.size(); i++) {
- if (ocount[i] > overloadcutoff) {
- still++;
- //c.overload[ocount[i]] = 100.0 / (float)ocount[i];
- //cout << "disk " << i << " has " << ocount[i] << endl;
- }
- }
- //if (still) cout << "overload was " << overloaded << " now " << still << endl;
- afteroverloadsum += (float)still / (float)ndisks;
-
- //cout << "collisions: " << c.collisions << endl;
- //cout << "r bumps: " << c.bumps << endl;
-
- float avg = 0.0;
- for (int i=0; i<ocount.size(); i++)
- avg += ocount[i];
- avg /= ocount.size();
- float var = 0.0;
- for (int i=0; i<ocount.size(); i++)
- var += (ocount[i] - avg) * (ocount[i] - avg);
- var /= ocount.size();
-
- //cout << "avg " << avg << " var " << var << " sd " << sqrt(var) << endl;
-
- tvar += var;
- tvarnum++;
- }
-
- overloadsum /= tvarnum;
- adjustsum /= tvarnum;
- tvar /= tvarnum;
- afteroverloadsum /= tvarnum;
-
- int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
- float crate = (float) collisions / (float)chooses;
- //cout << "collisions: " << c.collisions << endl;
-
-
- //cout << "total variance " << tvar << endl;
- //cout << " overlaod " << overloadsum << endl;
-
- cout << overloadcutoff << "\t" << (10000.0 / (float)overloadcutoff) << "\t" << tvar << "\t" << overloadsum << "\t" << adjustsum << "\t" << afteroverloadsum << "\t" << crate << endl;
- return tvar;
-}
-
-
-int main()
-{
- for (int d=140; d>100; d -= 5) {
- float var = go(3,d);
- //cout << "## depth = " << d << endl;
- //cout << d << "\t" << var << endl;
- }
-}
+++ /dev/null
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
- if (h == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
- for (int i=0; i<wid[h]; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 10, disks);
- //b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
- return b;
- } else {
- // mixed
- Bucket *b = new TreeBucket(h+1);
- for (int i=0; i<wid[h]; i++) {
- Bucket *n = make_bucket(c, wid, h-1, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- }
- c.add_bucket(b);
- //cout << h << " mixedbucket with " << wid[h] << endl;
- return b;
- }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
- Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
- return b->get_id();
-}
-
-
-float go(int dep)
-{
- Hash h(73232313);
-
- // crush
- Crush c;
-
-
- // buckets
- int root = -1;
- int ndisks = 0;
-
- vector<int> wid;
- if (1) {
- for (int d=0; d<dep; d++)
- wid.push_back(10);
- }
- if (0) {
- if (dep == 0)
- wid.push_back(1000);
- if (dep == 1) {
- wid.push_back(1);
- wid.push_back(1000);
- }
- if (dep == 2) {
- wid.push_back(5);
- wid.push_back(5);
- wid.push_back(8);
- wid.push_back(5);
- }
- }
-
- if (1) {
- root = make_hierarchy(c, wid, ndisks);
- }
-
-
-
- // rule
- int numrep = 1;
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
- //c.overload[10] = .1;
-
-
- int pg_per = 100;
- int numpg = pg_per*ndisks/numrep;
-
- vector<int> ocount(ndisks);
- //cout << ndisks << " disks, " << endl;
- //cout << pg_per << " pgs per disk" << endl;
- // cout << numpg << " logical pgs" << endl;
- //cout << "numrep is " << numrep << endl;
-
-
- int place = 100000;
- int times = place / numpg;
- if (!times) times = 1;
-
- cout << "#looping " << times << " times" << endl;
-
- float tvar = 0;
- int tvarnum = 0;
- float tavg = 0;
-
- int x = 0;
- for (int t=0; t<times; t++) {
- vector<int> v(numrep);
-
- for (int z=0; z<ndisks; z++) ocount[z] = 0;
-
- for (int xx=1; xx<numpg; xx++) {
- x++;
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- bool bad = false;
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- for (int j=i+1; j<numrep; j++) {
- if (v[i] == v[j])
- bad = true;
- }
- }
-
- //cout << v << "\t" << ocount << endl;
- }
-
- /*
- for (int i=0; i<ocount.size(); i++) {
- cout << "disk " << i << " has " << ocount[i] << endl;
- }
- */
-
- //cout << "collisions: " << c.collisions << endl;
- //cout << "r bumps: " << c.bumps << endl;
-
-
- float avg = 0.0;
- for (int i=0; i<ocount.size(); i++)
- avg += ocount[i];
- avg /= ocount.size();
- float var = 0.0;
- for (int i=0; i<ocount.size(); i++)
- var += (ocount[i] - avg) * (ocount[i] - avg);
- var /= ocount.size();
-
- if (times < 10)
- cout << "avg " << avg << " evar " << sqrt(avg) << " sd " << sqrt(var) << endl;
- //cout << avg << "\t";
-
- tvar += var;
- tavg += avg;
- tvarnum++;
- }
-
- tavg /= tvarnum;
- tvar /= tvarnum;
-
- cout << "total variance " << sqrt(tvar) << " expected " << sqrt(tavg) << endl;
-
- return tvar;
-}
-
-
-int main()
-{
- for (int d=2; d<=5; d++) {
- float var = go(d);
- //cout << "## depth = " << d << endl;
- //cout << d << "\t" << var << "\t" << sqrt(var) << endl;
- }
-}
+++ /dev/null
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
- if (h == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
- for (int i=0; i<wid[h]; i++)
- disks.push_back(ndisks++);
- float w = ((ndisks-1)/100+1)*10;
- UniformBucket *b = new UniformBucket(1, 0, w, disks);
- //b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks weight " << w << endl;
- return b;
- } else {
- // mixed
- Bucket *b = new TreeBucket(h+1);
- //Bucket *b = new StrawBucket(h+1);
- for (int i=0; i<wid[h]; i++) {
- Bucket *n = make_bucket(c, wid, h-1, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- }
- c.add_bucket(b);
- //cout << h << " mixedbucket with " << wid[h] << endl;
- return b;
- }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
- Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
- return b->get_id();
-}
-
-
-
-float go(int dep, int overloadcutoff)
-{
- Hash h(73232313);
-
- // crush
- Crush c;
-
-
- // buckets
- int root = -1;
- int ndisks = 0;
-
- vector<int> wid;
- for (int d=0; d<dep; d++)
- wid.push_back(10);
-
- if (1) {
- root = make_hierarchy(c, wid, ndisks);
- }
-
-
- // rule
- int numrep = 1;
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
- //c.overload[10] = .1;
-
-
- int pg_per_base = 10;
- int pg_per = pg_per_base*5.5;//100;
- int numpg = pg_per*ndisks/numrep;
-
- vector<int> ocount(ndisks);
- //cout << ndisks << " disks, " << endl;
- //cout << pg_per << " pgs per disk" << endl;
- // cout << numpg << " logical pgs" << endl;
- //cout << "numrep is " << numrep << endl;
-
-
- int place = 100000;
- int times = place / numpg;
- if (!times) times = 1;
-
-
- //cout << "looping " << times << " times" << endl;
-
- float tavg[10];
- float tvar[10];
- for (int j=0;j<10;j++) {
- tvar[j] = 0;
- tavg[j] = 0;
- }
- int tvarnum = 0;
-
- float overloadsum = 0.0;
- float adjustsum = 0.0;
- float afteroverloadsum = 0.0;
- int chooses = 0;
- int xs = 1;
- for (int t=0; t<times; t++) {
- vector<int> v(numrep);
-
- c.overload.clear();
-
- for (int z=0; z<ndisks; z++) ocount[z] = 0;
-
- for (int x=xs; x<numpg+xs; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- chooses += numrep;
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- bool bad = false;
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- for (int j=i+1; j<numrep; j++) {
- if (v[i] == v[j])
- bad = true;
- }
- }
- //if (bad)
- //cout << "bad set " << x << ": " << v << endl;
-
- //cout << v << "\t" << ocount << endl;
- }
-
- // overloaded?
- int overloaded = 0;
- int adjusted = 0;
- for (int i=0; i<ocount.size(); i++) {
- int target = (i/100+1)*10;
- int cutoff = target * overloadcutoff / 100;
- int adjoff = target + (cutoff - target)*3/4;
- if (ocount[i] > cutoff)
- overloaded++;
-
- if (ocount[i] > adjoff) {
- adjusted++;
- c.overload[i] = (float)target / (float)ocount[i];
- //cout << "setting overload " << i << " to " << c.overload[i] << endl;
- //cout << "disk " << i << " has " << ocount[i] << endl;
- }
- ocount[i] = 0;
- }
- //cout << overloaded << " overloaded" << endl;
- overloadsum += (float)overloaded / (float)ndisks;
- adjustsum += (float)adjusted / (float)ndisks;
-
-
-
- if (1) {
- // second pass
- for (int x=xs; x<numpg+xs; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- bool bad = false;
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- for (int j=i+1; j<numrep; j++) {
- if (v[i] == v[j])
- bad = true;
- }
- }
-
- //cout << v << "\t" << ocount << endl;
- }
-
- for (int i=0; i<ocount.size(); i++) {
- int target = (i/100+1)*10;
- int cutoff = target * overloadcutoff / 100;
- int adjoff = cutoff;//target + (cutoff - target)*3/4;
-
- if (ocount[i] >= adjoff) {
- adjusted++;
- if (c.overload.count(i) == 0) {
- c.overload[i] = 1.0;
- adjusted++;
- }
- //else cout << "(re)adjusting " << i << endl;
- c.overload[i] *= (float)target / (float)ocount[i];
- //cout << "setting overload " << i << " to " << c.overload[i] << endl;
- //cout << "disk " << i << " has " << ocount[i] << endl;
- }
- ocount[i] = 0;
- }
- }
-
- for (int x=xs; x<numpg+xs; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- bool bad = false;
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- for (int j=i+1; j<numrep; j++) {
- if (v[i] == v[j])
- bad = true;
- }
- }
- //cout << v << "\t" << ocount << endl;
- }
- xs += numpg;
-
- int still = 0;
- for (int i=0; i<ocount.size(); i++) {
- int target = (i/100+1)*10;
- int cutoff = target * overloadcutoff / 100;
- int adjoff = target + (cutoff - target)/3;
-
- if (ocount[i] > cutoff) {
- still++;
- //c.overload[ocount[i]] = 100.0 / (float)ocount[i];
- if (c.overload.count(i)) cout << "[adjusted] ";
- cout << "disk " << i << " has " << ocount[i] << endl;
- }
- }
- //if (still) cout << "overload was " << overloaded << " now " << still << endl;
- afteroverloadsum += (float)still / (float)ndisks;
-
- //cout << "collisions: " << c.collisions << endl;
- //cout << "r bumps: " << c.bumps << endl;
-
- int n = ndisks/10;
- float avg[10];
- float var[10];
- for (int i=0;i<10;i++) {
- int s = n*i;
- avg[i] = 0.0;
- for (int j=0; j<n; j++)
- avg[i] += ocount[j+s];
- avg[i] /= n;//ocount.size();
- var[i] = 0.0;
- for (int j=0; j<n; j++)
- var[i] += (ocount[j+s] - avg[i]) * (ocount[j+s] - avg[i]);
- var[i] /= n;//ocount.size();
-
- tvar[i] += var[i];
- tavg[i] += avg[i];
- }
- //cout << "avg " << avg << " var " << var << " sd " << sqrt(var) << endl;
-
- tvarnum++;
- }
-
- overloadsum /= tvarnum;
- adjustsum /= tvarnum;
- for (int j=0;j<10;j++) {
- tvar[j] /= tvarnum;
- tavg[j] /= tvarnum;
- }
- afteroverloadsum /= tvarnum;
-
- //int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
- //float crate = (float) collisions / (float)chooses;
- //cout << "collisions: " << c.collisions << endl;
-
-
- //cout << "total variance " << tvar << endl;
- //cout << " overlaod " << overloadsum << endl;
-
- cout << overloadcutoff << "\t" << (10000.0 / (float)overloadcutoff) << "\t" << overloadsum << "\t" << adjustsum << "\t" << afteroverloadsum;
- for (int i=0;i<10;i++)
- cout << "\t" << tavg[i] << "\t" << tvar[i];// << "\t" << tvar[i]/tavg[i];
- cout << endl;
- return tvar[0];
-}
-
-
-int main()
-{
- float var = go(3,200);
- for (int d=140; d>100; d -= 5) {
- float var = go(3,d);
- //cout << "## depth = " << d << endl;
- //cout << d << "\t" << var << endl;
- }
-}
+++ /dev/null
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
- if (h == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
- for (int i=0; i<wid[h]; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 1, disks);
- b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
- buckets[h].push_back(b);
- return b;
- } else {
- // mixed
- MixedBucket *b = new MixedBucket(h+1);
- c.add_bucket(b);
- for (int i=0; i<wid[h]; i++) {
- Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- n->set_parent(b->get_id());
- }
- buckets[h].push_back(b);
- //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
- return b;
- }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
- Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
- return b->get_id();
-}
-
-
-void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
-{
- vector<int> v(numrep);
- map<int,int> ocount;
-
- for (int x=1; x<=numpg; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- bool bad = false;
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- for (int j=i+1; j<numrep; j++) {
- if (v[i] == v[j])
- bad = true;
- }
- }
- if (bad)
- cout << "bad set " << x << ": " << v << endl;
-
- placement[x] = v;
-
- //cout << v << "\t" << ocount << endl;
- }
-
- if (0)
- for (map<int,int>::iterator it = ocount.begin();
- it != ocount.end();
- it++)
- cout << it->first << "\t" << it->second << endl;
-
-}
-
-
-float testmovement(int depth, int branching, int udisks)
-{
- Hash h(73232313);
-
- // crush
- Crush c;
-
-
- // buckets
- int root = -1;
- int ndisks = 0;
-
- vector<int> wid;
- wid.push_back(udisks);
- for (int d=1; d<depth; d++)
- wid.push_back(branching);
-
- map< int, list<Bucket*> > buckets;
-
- if (1) {
- root = make_hierarchy(c, wid, buckets, ndisks);
- }
- if (0) {
- MixedBucket *b = new MixedBucket(1);
- for (int i=0; i<10000; i++)
- b->add_item(ndisks++, 10);
- root = c.add_bucket(b);
- }
- if (0) {
- vector<int> disks;
- for (int i=0; i<10000; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 1, disks);
- Hash h(123);
- b->make_primes(h);
- root = c.add_bucket(b);
- }
-
-
-
- // rule
- int numrep = 2;
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
- //c.overload[10] = .1;
-
-
- int pg_per = 100;
- int numpg = pg_per*ndisks/numrep;
-
- vector<int> ocount(ndisks);
-
- /*
- cout << ndisks << " disks, " << endl;
- cout << pg_per << " pgs per disk" << endl;
- cout << numpg << " logical pgs" << endl;
- cout << "numrep is " << numrep << endl;
- */
- map<int, vector<int> > placement1, placement2;
-
- //c.print(cout, root);
-
- place(c, rule, numpg, numrep, placement1);
-
- if (1) {
- // failed
-
- //for (int i=500; i<1000; i++)
- //c.failed.insert(i);
- c.failed.insert(0);
- }
-
- int olddisks = ndisks;
-
- if (1) {
- int n = udisks;
- //cout << " adding " << n << " disks" << endl;
- vector<int> disks;
- for (int i=0; i<n; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 1, disks);
- Hash h(123);
- b->make_primes(h);
- Bucket *o = buckets[1].back();
- c.add_bucket(b);
- //cout << " adding under " << o->get_id() << endl;
- c.add_item(o->get_id(), b->get_id(), b->get_weight());
- //((MixedBucket*)o)->add_item(b->get_id(), b->get_weight());
- }
-
- //c.print(cout, root);
- place(c, rule, numpg, numrep, placement2);
-
- int moved = 0;
- for (int x=1; x<=numpg; x++) {
- if (placement1[x] != placement2[x]) {
- for (int j=0; j<numrep; j++)
- if (placement1[x][j] != placement2[x][j])
- moved++;
-
- }
- }
-
- float f = (float)moved / (float)(numpg*numrep);
- float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
- float fac = f/ideal;
- //cout << moved << " moved or " << f << ", ideal " << ideal << ", factor of " << fac << endl;
- return fac;
-}
-
-
-int main()
-{
-
- int udisks = 10;
- int ndisks = 10;
- for (int depth = 2; depth <= 4; depth++) {
- vector<float> v;
- cout << depth;
- for (int branching = 3; branching < 16; branching += 1) {
- float fac = testmovement(depth, branching, udisks);
- v.push_back(fac);
- int n = udisks * pow((float)branching, (float)depth-1);
- cout << "\t" << n;
- cout << "\t" << fac;
- }
- //for (int i=0; i<v.size(); i++)
- //cout << "\t" << v[i];
- cout << endl;
-
- }
-
-}
-
+++ /dev/null
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
- if (h == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
- for (int i=0; i<wid[h]; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 1, disks);
- b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
- buckets[h].push_back(b);
- return b;
- } else {
- // mixed
- MixedBucket *b = new MixedBucket(h+1);
- c.add_bucket(b);
- for (int i=0; i<wid[h]; i++) {
- Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- n->set_parent(b->get_id());
- }
- buckets[h].push_back(b);
- //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
- return b;
- }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
- Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
- return b->get_id();
-}
-
-
-void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, set<int> >& placement)
-{
- vector<int> v(numrep);
- map<int,int> ocount;
-
- for (int x=1; x<=numpg; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- bool bad = false;
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- for (int j=i+1; j<numrep; j++) {
- if (v[i] == v[j])
- bad = true;
- }
- placement[v[i]].insert(x);
- }
- if (bad)
- cout << "bad set " << x << ": " << v << endl;
-
-
- //cout << v << "\t" << ocount << endl;
- }
-
- if (0)
- for (map<int,int>::iterator it = ocount.begin();
- it != ocount.end();
- it++)
- cout << it->first << "\t" << it->second << endl;
-
-}
-
-
-float testmovement(int depth, int branching, int udisks)
-{
- Hash h(73232313);
-
- // crush
- Crush c;
-
-
- // buckets
- int root = -1;
- int ndisks = 0;
-
- vector<int> wid;
- wid.push_back(udisks);
- for (int d=1; d<depth; d++)
- wid.push_back(branching);
-
- map< int, list<Bucket*> > buckets;
-
- if (1) {
- root = make_hierarchy(c, wid, buckets, ndisks);
- }
- if (0) {
- MixedBucket *b = new MixedBucket(1);
- for (int i=0; i<10000; i++)
- b->add_item(ndisks++, 10);
- root = c.add_bucket(b);
- }
- if (0) {
- vector<int> disks;
- for (int i=0; i<10000; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 1, disks);
- Hash h(123);
- b->make_primes(h);
- root = c.add_bucket(b);
- }
-
-
-
- // rule
- int numrep = 2;
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
- //c.overload[10] = .1;
-
-
- int pg_per = 100;
- int numpg = pg_per*ndisks/numrep;
-
- vector<int> ocount(ndisks);
-
- /*
- cout << ndisks << " disks, " << endl;
- cout << pg_per << " pgs per disk" << endl;
- cout << numpg << " logical pgs" << endl;
- cout << "numrep is " << numrep << endl;
- */
- map<int, set<int> > placement1, placement2;
-
- //c.print(cout, root);
-
- place(c, rule, numpg, numrep, placement1);
-
- float over = .5;
-
- if (1) {
- // failed
-
- //for (int i=500; i<1000; i++)
- //c.failed.insert(i);
- //c.failed.insert(0);
- c.overload[0] = over;
- }
-
- int olddisks = ndisks;
-
-
-
- if (0) {
- int n = udisks;
- //cout << " adding " << n << " disks" << endl;
- vector<int> disks;
- for (int i=0; i<n; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 1, disks);
- Hash h(123);
- b->make_primes(h);
- Bucket *o = buckets[1].back();
- c.add_bucket(b);
- //cout << " adding under " << o->get_id() << endl;
- c.add_item(o->get_id(), b->get_id(), b->get_weight());
- //((MixedBucket*)o)->add_item(b->get_id(), b->get_weight());
- }
-
- //c.print(cout, root);
- place(c, rule, numpg, numrep, placement2);
-
- vector<int> moved(ndisks);
-
- //int moved = 0;
- for (int d=0; d<ndisks; d++) {
- for (set<int>::iterator it = placement1[d].begin();
- it != placement1[d].end();
- it++) {
- placement2[d].erase(*it);
- }
- }
-
- float avg = 0;
- for (int d=0; d<ndisks; d++) {
- moved[d] = placement2[d].size();
- avg += moved[d];
- }
- avg /= (float)ndisks;
- float var = 0;
- for (int d=0; d<ndisks; d++) {
- var += (moved[d]-avg)*(moved[d]-avg);
- }
- var /= (float)ndisks;
-
- float expected = over * 100.0 / (float)(ndisks-1);
-
- cout << ndisks << "\t" << expected << "\t" << avg << "\t" << var << endl;
- /*
- float f = (float)moved / (float)(numpg*numrep);
- float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
- float fac = f/ideal;
- //cout << moved << " moved or " << f << ", ideal " << ideal << ", factor of " << fac << endl;
- return fac;
- */
-}
-
-
-int main()
-{
-
- int udisks = 10;
- int ndisks = 10;
- for (int depth = 2; depth <= 4; depth++) {
- vector<float> v;
- cout << depth;
- for (int branching = 3; branching < 16; branching += 1) {
- float fac = testmovement(depth, branching, udisks);
- v.push_back(fac);
- int n = udisks * pow((float)branching, (float)depth-1);
- //cout << "\t" << n;
- //cout << "\t" << fac;
- }
- //for (int i=0; i<v.size(); i++)
- //cout << "\t" << v[i];
- //cout << endl;
-
- }
-
-}
-
+++ /dev/null
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include "../../common/Clock.h"
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Clock g_clock;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
- if (h == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
- for (int i=0; i<wid[h]; i++)
- disks.push_back(ndisks++);
- float w = ((ndisks-1)/100+1)*10;
- UniformBucket *b = new UniformBucket(1, 0, w, disks);
- //b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks weight " << w << endl;
- return b;
- } else {
- // mixed
- Bucket *b = new TreeBucket(h+1);
- for (int i=0; i<wid[h]; i++) {
- Bucket *n = make_bucket(c, wid, h-1, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- }
- c.add_bucket(b);
- //cout << h << " mixedbucket with " << wid[h] << endl;
- return b;
- }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
- Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
- return b->get_id();
-}
-
-
-
-float go(int dep, int utilization )
-{
- Hash h(73232313);
-
- int overloadcutoff = (int)((float)10000.0 / (float)utilization);
-
- //cout << "util " << utilization << " cutoff " << overloadcutoff << endl;
- // crush
- Crush c;
-
-
- // buckets
- int root = -1;
- int ndisks = 0;
-
- vector<int> wid;
- for (int d=0; d<dep; d++)
- wid.push_back(10);
-
- if (1) {
- root = make_hierarchy(c, wid, ndisks);
- }
-
- //cout << ndisks << " disks" << endl;
-
-
-
- // rule
- int numrep = 1;
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
- //c.overload[10] = .1;
-
- int pg_per_base = 20;
- int pg_med = 10*pg_per_base;
- int pg_per = pg_per_base*5.5;//100;
- int numpg = pg_per*ndisks/numrep;
-
- vector<int> ocount(ndisks);
- //cout << ndisks << " disks, " << endl;
- //cout << pg_per << " pgs per disk" << endl;
- // cout << numpg << " logical pgs" << endl;
- //cout << "numrep is " << numrep << endl;
-
-
- int place = 100000;
- int times = place / numpg;
- if (!times) times = 1;
-
-
- //cout << "looping " << times << " times" << endl;
-
- float tavg[10];
- float tvar[10];
- for (int j=0;j<10;j++) {
- tvar[j] = 0;
- tavg[j] = 0;
- }
- int tvarnum = 0;
-
- float overloadsum = 0.0;
- float adjustsum = 0.0;
- float afteroverloadsum = 0.0;
- float aslowdown = 0.0;
- int chooses = 0;
- int xs = 1;
- for (int t=0; t<times; t++) {
- vector<int> v(numrep);
-
- c.overload.clear();
-
- for (int z=0; z<ndisks; z++) ocount[z] = 0;
-
-
- utime_t t1a = g_clock.now();
-
- for (int x=xs; x<numpg+xs; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- chooses += numrep;
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- }
-
- //cout << v << "\t" << ocount << endl;
- }
-
- utime_t t1b = g_clock.now();
-
- // overloaded?
- int overloaded = 0;
- int adjusted = 0;
- for (int i=0; i<ocount.size(); i++) {
- int target = (i/100+1)*pg_per_base;
- int cutoff = target * overloadcutoff / 100;
- int adjoff = target + (cutoff - target)*3/4;
- if (ocount[i] > cutoff)
- overloaded++;
-
- if (ocount[i] > adjoff) {
- adjusted++;
- c.overload[i] = (float)target / (float)ocount[i];
- //cout << "setting overload " << i << " to " << c.overload[i] << endl;
- //cout << "disk " << i << " has " << ocount[i] << endl;
- }
- ocount[i] = 0;
- }
- //cout << overloaded << " overloaded" << endl;
- overloadsum += (float)overloaded / (float)ndisks;
- adjustsum += (float)adjusted / (float)ndisks;
-
-
-
- // keep adjusting!
- for (int bla=0; bla<5; bla++) {
- utime_t t2a = g_clock.now();
-
- // second pass
- for (int x=xs; x<numpg+xs; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- }
-
- //cout << v << "\t" << ocount << endl;
- }
-
- utime_t t2b = g_clock.now();
-
- int numover = 0;
- for (int i=0; i<ocount.size(); i++) {
- int target = (i/100+1)*pg_per_base;
- int cutoff = target * overloadcutoff / 100;
- int adjoff = cutoff;//target + (cutoff - target)*3/4;
-
- if (ocount[i] >= adjoff) {
- numover++;
- if (c.overload.count(i) == 0) {
- c.overload[i] = 1.0;
- adjusted++;
- }
- //else cout << "(re)adjusting " << i << endl;
- c.overload[i] *= (float)target / (float)ocount[i];
- //cout << "setting overload " << i << " to " << c.overload[i] << endl;
- //cout << "disk " << i << " has " << ocount[i] << endl;
- }
- ocount[i] = 0;
- }
- if (!numover) break;
- cout << "readjusting" << endl;
- }
-
- utime_t t3a = g_clock.now();
-
- for (int x=xs; x<numpg+xs; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- }
-
- //cout << v << "\t" << ocount << endl;
- }
- xs += numpg;
-
- utime_t t3b = g_clock.now();
-
- t1b -= t1a;
- double t1 = (double)t1b;
- t3b -= t3a;
- double t3 = (double)t3b;
- double slowdown = t3/t1;
- //cout << "slowdown " << slowdown << endl;
- aslowdown += slowdown;
-
- int still = 0;
- for (int i=0; i<ocount.size(); i++) {
- int target = (i/100+1)*pg_per_base;
- int cutoff = target * overloadcutoff / 100;
- //int adjoff = target + (cutoff - target)/3;
-
- if (ocount[i] > cutoff) {
- still++;
- //c.overload[ocount[i]] = 100.0 / (float)ocount[i];
- if (c.overload.count(i)) cout << "[adjusted] ";
- cout << "disk " << i << " has " << ocount[i] << endl;
- }
- }
- //if (still) cout << "overload was " << overloaded << " now " << still << endl;
- afteroverloadsum += (float)still / (float)ndisks;
-
- //cout << "collisions: " << c.collisions << endl;
- //cout << "r bumps: " << c.bumps << endl;
-
- int n = ndisks/10;
- float avg[10];
- float var[10];
- for (int i=0;i<10;i++) {
- int s = n*i;
- avg[i] = 0.0;
- for (int j=0; j<n; j++)
- avg[i] += ocount[j+s];
- avg[i] /= n;//ocount.size();
- var[i] = 0.0;
- for (int j=0; j<n; j++)
- var[i] += (ocount[j+s] - avg[i]) * (ocount[j+s] - avg[i]);
- var[i] /= n;//ocount.size();
-
- tvar[i] += var[i];
- tavg[i] += avg[i];
- }
- //cout << "avg " << avg << " var " << var << " sd " << sqrt(var) << endl;
-
- tvarnum++;
- }
-
- overloadsum /= tvarnum;
- adjustsum /= tvarnum;
- float avar = 0.0;
- for (int j=0;j<10;j++) {
- tvar[j] /= tvarnum;
- tavg[j] /= tvarnum;
- avar += tvar[j];
- }
- avar /= 10;
- avar = sqrt(avar);
- avar /= 5.5 * (float)pg_per_base;
- afteroverloadsum /= tvarnum;
- aslowdown /= tvarnum;
-
- //int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
- //float crate = (float) collisions / (float)chooses;
- //cout << "collisions: " << c.collisions << endl;
-
-
- //cout << "total variance " << tvar << endl;
- //cout << " overlaod " << overloadsum << endl;
-
- cout << overloadcutoff << "\t" << utilization
- << "\t" << overloadsum << "\t" << adjustsum << "\t" << afteroverloadsum
- << "\t" << aslowdown << "\t" << avar << "\t-";
-
- for (int i=0;i<10;i++)
- cout << "\t" << tavg[i] << "\t" << tvar[i];// << "\t" << tvar[i]/tavg[i];
- cout << endl;
- return tvar[0];
-}
-
-
-int main()
-{
- float var = go(3,50);
- /* for (int d=70; d<100; d += 5) {
- float var = go(3,d);
- //cout << "## depth = " << d << endl;
- //cout << d << "\t" << var << endl;
- }*/
- go(3,96);
- go(3,97);
- go(3,98);
- go(3,99);
-
-
-}
+++ /dev/null
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
- if (h == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
- for (int i=0; i<wid[h]; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 10, disks);
- b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
- return b;
- } else {
- // mixed
- MixedBucket *b = new MixedBucket(h+1);
- for (int i=0; i<wid[h]; i++) {
- Bucket *n = make_bucket(c, wid, h-1, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- }
- c.add_bucket(b);
- //cout << h << " mixedbucket with " << wid[h] << endl;
- return b;
- }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
- Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
- return b->get_id();
-}
-
-
-Bucket *make_random(Crush& c, int wid, int height, int& ndisks)
-{
- int w = rand() % (wid-1) + 2;
-
- if (height == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
- for (int i=0; i<w; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 10, disks);
- b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
- return b;
- } else {
- // mixed
- int h = rand() % height + 1;
- MixedBucket *b = new MixedBucket(h+1);
- for (int i=0; i<w; i++) {
- Bucket *n = make_random(c, wid, h-1, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- }
- c.add_bucket(b);
- //cout << h << " mixedbucket with " << wid[h] << endl;
- return b;
- }
-
-}
-
-
-float go(int dep, int overloadcutoff)
-{
- Hash h(73232313);
-
- // crush
- Crush c;
-
-
- // buckets
- int root = -1;
- int ndisks = 0;
-
- vector<int> wid;
- for (int d=0; d<dep; d++)
- wid.push_back(10);
-
- if (1) {
- root = make_hierarchy(c, wid, ndisks);
- }
- if (0) {
- Bucket *r = make_random(c, 20, 4, ndisks);
- root = r->get_id();
- //c.print(cout, root);
- }
- if (0) {
- MixedBucket *b = new MixedBucket(1);
- for (int i=0; i<10000; i++)
- b->add_item(ndisks++, 10);
- root = c.add_bucket(b);
- }
- if (0) {
- vector<int> disks;
- for (int i=0; i<10000; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 10000, disks);
- Hash h(123);
- b->make_primes(h);
- root = c.add_bucket(b);
- }
- //cout << ndisks << " disks" << endl;
-
-
-
- // rule
- int numrep = 1;
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
- //c.overload[10] = .1;
-
-
- int pg_per = 100;
- int numpg = pg_per*ndisks/numrep;
-
- vector<int> ocount(ndisks);
- //cout << ndisks << " disks, " << endl;
- //cout << pg_per << " pgs per disk" << endl;
- // cout << numpg << " logical pgs" << endl;
- //cout << "numrep is " << numrep << endl;
-
-
- int place = 1000000;
- int times = place / numpg;
- if (!times) times = 1;
-
-
- //cout << "looping " << times << " times" << endl;
-
- float tvar = 0;
- int tvarnum = 0;
-
- float overloadsum = 0.0;
- float adjustsum = 0.0;
- float afteroverloadsum = 0.0;
- int chooses = 0;
- int xs = 1;
- for (int t=0; t<times; t++) {
- vector<int> v(numrep);
-
- c.overload.clear();
-
- for (int z=0; z<ndisks; z++) ocount[z] = 0;
-
- for (int x=xs; x<numpg+xs; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- chooses += numrep;
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- bool bad = false;
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- for (int j=i+1; j<numrep; j++) {
- if (v[i] == v[j])
- bad = true;
- }
- }
- if (bad)
- cout << "bad set " << x << ": " << v << endl;
-
- //cout << v << "\t" << ocount << endl;
- }
-
- // overloaded?
- int overloaded = 0;
- int adjusted = 0;
- for (int i=0; i<ocount.size(); i++) {
- if (ocount[i] > overloadcutoff)
- overloaded++;
-
- if (ocount[i] > 100+(overloadcutoff-100)/2) {
- adjusted++;
- c.overload[i] = 100.0 / (float)ocount[i];
- //cout << "disk " << i << " has " << ocount[i] << endl;
- }
- ocount[i] = 0;
- }
- //cout << overloaded << " overloaded" << endl;
- overloadsum += (float)overloaded / (float)ndisks;
- adjustsum += (float)adjusted / (float)ndisks;
-
-
- for (int x=xs; x<numpg+xs; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- bool bad = false;
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- for (int j=i+1; j<numrep; j++) {
- if (v[i] == v[j])
- bad = true;
- }
- }
- if (bad)
- cout << "bad set " << x << ": " << v << endl;
-
- //cout << v << "\t" << ocount << endl;
- }
- xs += numpg;
-
- int still = 0;
- for (int i=0; i<ocount.size(); i++) {
- if (ocount[i] > overloadcutoff) {
- still++;
- //c.overload[ocount[i]] = 100.0 / (float)ocount[i];
- //cout << "disk " << i << " has " << ocount[i] << endl;
- }
- }
- //if (still) cout << "overload was " << overloaded << " now " << still << endl;
- afteroverloadsum += (float)still / (float)ndisks;
-
- //cout << "collisions: " << c.collisions << endl;
- //cout << "r bumps: " << c.bumps << endl;
-
- float avg = 0.0;
- for (int i=0; i<ocount.size(); i++)
- avg += ocount[i];
- avg /= ocount.size();
- float var = 0.0;
- for (int i=0; i<ocount.size(); i++)
- var += (ocount[i] - avg) * (ocount[i] - avg);
- var /= ocount.size();
-
- //cout << "avg " << avg << " var " << var << " sd " << sqrt(var) << endl;
-
- tvar += var;
- tvarnum++;
- }
-
- overloadsum /= tvarnum;
- adjustsum /= tvarnum;
- tvar /= tvarnum;
- afteroverloadsum /= tvarnum;
-
- int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
- float crate = (float) collisions / (float)chooses;
- //cout << "collisions: " << c.collisions << endl;
-
-
- //cout << "total variance " << tvar << endl;
- //cout << " overlaod " << overloadsum << endl;
-
- cout << overloadcutoff << "\t" << (10000.0 / (float)overloadcutoff) << "\t" << tvar << "\t" << overloadsum << "\t" << adjustsum << "\t" << afteroverloadsum << "\t" << crate << endl;
- return tvar;
-}
-
-
-int main()
-{
- for (int d=140; d>100; d -= 5) {
- float var = go(3,d);
- //cout << "## depth = " << d << endl;
- //cout << d << "\t" << var << endl;
- }
-}
+++ /dev/null
-
-#include "include/types.h"
-#include "include/Distribution.h"
-#include "osd/OSDMap.h"
-
-
-Distribution file_size_distn; //kb
-
-
-list<int> object_queue;
-int max_object_size = 1024*1024*100; //kb
-
-off_t no;
-
-int get_object() //kb
-{
- if (object_queue.empty()) {
- int max = file_size_distn.sample();
- no++;
- int filesize = max/2 + (rand() % 100) * max/200 + 1;
- //cout << "file " << filesize << endl;
- while (filesize > max_object_size) {
- object_queue.push_back(max_object_size);
- filesize -= max_object_size;
- }
- object_queue.push_back(filesize);
- }
- int s = object_queue.front();
- object_queue.pop_front();
- //cout << "object " << s << endl;
- return s;
-}
-
-void getdist(vector<off_t>& v, float& avg, float& var)
-{
- avg = 0.0;
- for (int i=0; i<v.size(); i++)
- avg += v[i];
- avg /= v.size();
-
- var = 0.0;
- for (int i=0; i<v.size(); i++)
- var += (v[i] - avg) * (v[i] - avg);
- var /= v.size();
-}
-
-
-void testpgs(int n, // numpg
- off_t pggb,
- float& avg,
- float& var,
- off_t& numo
- )
-{
- off_t dist = (off_t)n * 1024LL*1024LL * (off_t)pggb; //kb
- vector<off_t> pgs(n);
- off_t did = 0;
-
- no = 0;
- while (did < dist) {
- off_t s = get_object();
- pgs[rand()%n] += s;
- did += s;
- }
- while (!object_queue.empty())
- pgs[rand()%n] += get_object();
-
- numo = no;
- //cout << did/n << endl;
-
- //for (int i=0; i<n; i++) cout << pgs[i] << endl;
-
- getdist(pgs, avg, var);
- //cout << "avg " << avg << " var " << var << " dev " << sqrt(var) << endl;
-
-}
-
-
-
-int main()
-{
- /*
-
-// File Size
-//cate count_mean size_mean
-1b -0.5 0.65434375 0
-1k 0.5 19.0758125 0.00875
-512K 1.5 35.6566 2.85875
-1M 2.5 27.7271875 25.0084375
-2M 3.5 16.63503125 20.8046875
-4M 4.5 106.82384375 296.053125
-8M 5.5 81.493375 335.77625
-16M 6.5 14.13553125 185.9775
-32M 7.5 2.176 52.921875
-256M 8.5 0.655938 47.8066
-512M 9.5 0.1480625 57.83375
-2G 10.5 0.020125 19.2888
- */
- file_size_distn.add(1, 19.0758125+0.65434375);
- file_size_distn.add(512, 35.6566);
- file_size_distn.add(1024, 27.7271875);
- file_size_distn.add(2*1024, 16.63503125);
- file_size_distn.add(4*1024, 106.82384375);
- file_size_distn.add(8*1024, 81.493375);
- file_size_distn.add(16*1024, 14.13553125);
- file_size_distn.add(32*1024, 2.176);
- file_size_distn.add(256*1024, 0.655938);
- file_size_distn.add(512*1024, 0.1480625);
- file_size_distn.add(1*1024*1024, 0.020125); // actually 2, but 32bit
- file_size_distn.normalize();
-
-
- for (int pggb = 1; pggb < 16; pggb++) {
- cout << pggb;
- for (int max = 1; max <= 1024; max *= 2) {
- float avg, var, var2, var3;
- off_t no;
- max_object_size = max*1024;
- testpgs(100, pggb, avg, var, no);
- testpgs(100, pggb, avg, var2, no);
- testpgs(100, pggb, avg, var3, no);
- float dev = sqrt((var+var2+var3)/3.0);
- cout << "\t" << no << "\t" << max << "\t" << dev;
- }
- cout << endl;
- }
-
-
-
-
-}
+++ /dev/null
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
- if (h == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
- for (int i=0; i<wid[h]; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 1, disks);
- b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
- buckets[h].push_back(b);
- return b;
- } else {
- // mixed
- Bucket *b = new TreeBucket(h+1);
- c.add_bucket(b);
- for (int i=0; i<wid[h]; i++) {
- Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- n->set_parent(b->get_id());
- }
- buckets[h].push_back(b);
- //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
- return b;
- }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
- Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
- return b->get_id();
-}
-
-
-void place(Crush& c, Rule& rule, int numpg, int numrep, vector<int>& ocount)
-{
- vector<int> v(numrep);
- //map<int,int> ocount;
-
- for (int x=1; x<=numpg; x++) {
-
- //cout << H(x) << "\t" << h(x) << endl;
- c.do_rule(rule, x, v);
- //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << " " << v[2] << endl;
-
- bool bad = false;
- for (int i=0; i<numrep; i++) {
- //int d = b.choose_r(x, i, h);
- //v[i] = d;
- ocount[v[i]]++;
- for (int j=i+1; j<numrep; j++) {
- if (v[i] == v[j])
- bad = true;
- }
- }
- if (bad)
- cout << "bad set " << x << ": " << v << endl;
-
- //placement[x] = v;
-
- //cout << v << "\t" << ocount << endl;
- }
-
-
-}
-
-
-int main()//float testmovement(int depth, int branching, int udisks)
-{
- Hash h(73232313);
-
- // crush
- Crush c;
-
-
- // buckets
- int root = -1;
- int ndisks = 0;
-
- vector<int> wid;
- wid.push_back(10);
- wid.push_back(2);
-
- map< int, list<Bucket*> > buckets;
- root = make_hierarchy(c, wid, buckets, ndisks);
-
- // add small bucket
- vector<int> disks;
- for (int i=0; i<3; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 1, disks);
- b->make_primes(h);
- Bucket *o = buckets[1].back();
- c.add_bucket(b);
- //cout << " adding under " << o->get_id() << endl;
- c.add_item(o->get_id(), b->get_id(), b->get_weight());
-
-
- // rule
- int numrep = 6;
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
- //c.overload[10] = .1;
-
- int pg_per = 10000;
- int numpg = pg_per*ndisks/numrep;
-
- vector<int> ocount(ndisks);
-
- c.print(cout, root);
-
- place(c, rule, numpg, numrep, ocount);
-
- for (int i=0; i<ocount.size(); i++) {
- cout << "disk " << i << " = " << ocount[i] << endl;
- }
-
- return 0;
-}
-
-
+++ /dev/null
-
-#include "../../common/Clock.h"
-#include "../crush.h"
-using namespace crush;
-
-
-Clock g_clock;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-int numrep = 1;
-
-
-double go(int n, int bucket)
-{
- Hash h(73232313);
-
- // crush
- Crush c;
-
-
- // buckets
- int root = -1;
- int ndisks = 0;
-
- Bucket *b;
- vector<int> items;
- if (bucket == 0) b = new UniformBucket(1,0,10,items);
- if (bucket == 1) b = new TreeBucket(1);
- if (bucket == 2) b = new ListBucket(1);
- if (bucket == 3) b = new StrawBucket(1);
-
- for (int d=0; d<n; d++)
- b->add_item(ndisks++, 1);
-
- //if (!bucket) ((UniformBucket*)b)->make_primes(h);
-
- root = c.add_bucket(b);
-
- // rule
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-
- int place = 1000000;
-
-
- vector<int> v(numrep);
- set<int> out;
- map<int,float> overload;
-
- utime_t start = g_clock.now();
-
- for (int x=1; x <= place; x++)
- c.do_rule(rule, x, v, out, overload);
-
- utime_t end = g_clock.now();
-
- end -= start;
- double el = (double)end;
-
- //cout << "\t" << ndisks;
-
- return el;
-}
-
-
-int main()
-{
-
- for (int n=4; n<=50; n += 4) {
- cout << n;
- for (int b=0; b<4; b++) {
- double el = go(n,b);
- cout << "\t" << el;
- }
- cout << endl;
- }
-}
+++ /dev/null
-
-#include "../../common/Clock.h"
-#include "../crush.h"
-using namespace crush;
-
-
-Clock g_clock;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-int uniform = 10;
-int branching = 10;
-int buckettype = 0;
-int numrep = 1;
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
- if (h == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
- for (int i=0; i<wid[h]; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 10, disks);
- //b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
- return b;
- } else {
- // mixed
- Bucket *b;
- if (buckettype == 0)
- b = new TreeBucket(h+1);
- else if (buckettype == 1 || buckettype == 2)
- b = new ListBucket(h+1);
- else if (buckettype == 3)
- b = new StrawBucket(h+1);
- for (int i=0; i<wid[h]; i++) {
- Bucket *n = make_bucket(c, wid, h-1, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- }
- c.add_bucket(b);
- //cout << h << " mixedbucket with " << wid[h] << endl;
- return b;
- }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
- Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
- return b->get_id();
-}
-
-
-double go(int dep, int per)
-{
- Hash h(73232313);
-
- // crush
- Crush c;
-
-
- // buckets
- int root = -1;
- int ndisks = 0;
-
- vector<int> wid;
- if (1) {
- wid.push_back(uniform);
- for (int d=1; d<dep; d++)
- wid.push_back(per);
- }
- if (0) {
- if (dep == 0)
- wid.push_back(1000);
- if (dep == 1) {
- wid.push_back(1);
- wid.push_back(1000);
- }
- if (dep == 2) {
- wid.push_back(5);
- wid.push_back(5);
- wid.push_back(8);
- wid.push_back(5);
- }
- }
-
- if (1) {
- root = make_hierarchy(c, wid, ndisks);
- }
-
-
-
- // rule
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-
- int place = 1000000;
-
-
- vector<int> v(numrep);
-
- utime_t start = g_clock.now();
-
- set<int> out;
- map<int,float> overload;
-
- for (int x=1; x <= place; x++)
- c.do_rule(rule, x, v, out, overload);
-
- utime_t end = g_clock.now();
-
- end -= start;
- double el = (double)end;
-
- //cout << "\t" << ndisks;
-
- return el;
-}
-
-
-int main()
-{
- uniform = branching = 8;
-
- cout << "// dep\tuniform\tbranch\tndisks" << endl;
-
- for (int d=2; d<=5; d++) {
- cout << d;// << "\t" << branching;
- cout << "\t" << uniform;
- cout << "\t" << branching;
-
- int n = 1;
- for (int i=0; i<d; i++)
- n *= branching;
- cout << "\t" << n;
-
- numrep = 2;
-
- // crush
- for (buckettype = 0; buckettype <= 3; buckettype++) {
- switch (buckettype) {
- case 0: cout << "\ttree"; break;
- case 1: cout << "\tlist"; break;
- case 2: continue;
- case 3: cout << "\tstraw"; break;
- }
-
- //for (numrep = 1; numrep <= 3; numrep++) {
- //cout << "\t" << numrep;
-
- double el = go(d, branching);
- cout << "\t" << el;
- }
-
- // rush
-
- buckettype = 0;
- cout << "\trush_T\t" << go(2, n/uniform);
-
- buckettype = 1;
- cout << "\trush_P\t" << go(2, n/uniform);
-
- cout << endl;
- }
-}
+++ /dev/null
-
-#include "../../common/Clock.h"
-#include "../crush.h"
-using namespace crush;
-
-
-Clock g_clock;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-int branching = 10;
-bool linear = false;
-int numrep = 1;
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
- if (h == 0) {
- // uniform
- Hash hash(123);
- vector<int> disks;
- for (int i=0; i<wid[h]; i++)
- disks.push_back(ndisks++);
- UniformBucket *b = new UniformBucket(1, 0, 10, disks);
- //b->make_primes(hash);
- c.add_bucket(b);
- //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
- return b;
- } else {
- // mixed
- Bucket *b;
- if (linear)
- b = new ListBucket(h+1);
- else
- b = new TreeBucket(h+1);
- for (int i=0; i<wid[h]; i++) {
- Bucket *n = make_bucket(c, wid, h-1, ndisks);
- b->add_item(n->get_id(), n->get_weight());
- }
- c.add_bucket(b);
- //cout << h << " mixedbucket with " << wid[h] << endl;
- return b;
- }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
- Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
- return b->get_id();
-}
-
-
-double go(int s)
-{
- int dep = 2;
- Hash h(73232313);
-
- // crush
- Crush c;
-
-
- // buckets
- int root = -1;
- int ndisks = 0;
-
- vector<int> wid;
- if (1) {
- //for (int d=0; d<dep; d++)
- wid.push_back(8);
- wid.push_back(s/8);
- }
- if (0) {
- if (dep == 0)
- wid.push_back(1000);
- if (dep == 1) {
- wid.push_back(1);
- wid.push_back(1000);
- }
- if (dep == 2) {
- wid.push_back(5);
- wid.push_back(5);
- wid.push_back(8);
- wid.push_back(5);
- }
- }
-
- if (1) {
- root = make_hierarchy(c, wid, ndisks);
- }
-
-
-
- // rule
- Rule rule;
- rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
- rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-
- int place = 1000000;
-
-
- vector<int> v(numrep);
-
- utime_t start = g_clock.now();
-
- for (int x=1; x <= place; x++)
- c.do_rule(rule, x, v);
-
- utime_t end = g_clock.now();
-
- end -= start;
- double el = (double)end;
-
- cout << "\t" << ndisks;
-
- return el;
-}
-
-
-int main()
-{
- branching = 8;
-
- int d = 2;
- numrep = 2;
-
- for (int s = 64; s <= 32768; s *= 8) {
- cout << "t";
- linear = false;
- double el = go(s, d);
- cout << "\t" << el;
-
- cout << "\tp";
- linear = true;
- el = go(s, d);
- cout << "\t" << el;
-
- cout << endl;
- }
-}
+++ /dev/null
-
-#include "../../common/Clock.h"
-#include "../crush.h"
-using namespace crush;
-
-
-Clock g_clock;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-int branching = 10;
-bool linear = false;
-int numrep = 1;
-
-int main() {
-
- Bucket *b = new UniformBucket(1, 0);
- //b = new TreeBucket(1);
-}
-
+++ /dev/null
-
-
-#include "../Bucket.h"
-using namespace crush;
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-ostream& operator<<(ostream& out, vector<int>& v)
-{
- out << "[";
- for (int i=0; i<v.size(); i++) {
- if (i) out << " ";
- out << v[i];
- }
- out << "]";
- return out;
-}
-
-
-int main()
-{
- Hash h(73);
-
- int ndisks = 0;
- int numrep = 3;
-
- StrawBucket mb(1);
- /*for (int i=0;i<10;i++)
- mb.add_item(ndisks++, 10);
- */
- mb.add_item(ndisks++, 1);
- mb.add_item(ndisks++, 1);
- mb.add_item(ndisks++, 10);
- mb.add_item(ndisks++, 10);
- mb.add_item(ndisks++, 100);
- mb.add_item(ndisks++, 1000);
-
- vector<int> ocount(ndisks);
-
- vector<int> v(numrep);
- int nplace = 0;
- for (int x=1; x<1000000; x++) {
- //cout << H(x) << "\t" << h(x) << endl;
- for (int i=0; i<numrep; i++) {
- int d = mb.choose_r(x, i, h);
- v[i] = d;
- ocount[d]++;
- nplace++;
- }
- //cout << v << "\t" << endl;//ocount << endl;
- }
-
- for (int i=0; i<ocount.size(); i++) {
- float f = ocount[i] / (float)nplace;
- cout << "disk " << i << " has " << ocount[i] << " " << f << endl;
- }
-
-}
+++ /dev/null
-
-#include <vector>
-#include <iostream>
-using namespace std;
-
-
-void getdist(vector<int>& v, float& avg, float& var)
-{
- avg = 0.0;
- for (int i=0; i<v.size(); i++)
- avg += v[i];
- avg /= v.size();
-
- var = 0.0;
- for (int i=0; i<v.size(); i++)
- var += (v[i] - avg) * (v[i] - avg);
- var /= v.size();
-}
-
-int main()
-{
- int n = 50;
- vector<int> a(n);
- vector<int> b(n);
-
- for (int i=0; i<n*n; i++)
- a[rand()%n]++;
-
- float aavg, avar;
- getdist(a, aavg, avar);
-
- for (int i=0; i<7*n*n; i++)
- b[rand()%n]++;
-
- float bavg, bvar;
- getdist(b, bavg, bvar);
-
- cout << "a avg " << aavg << " var " << avar << endl;
- cout << "b avg " << bavg << " var " << bvar << endl;
-
-
- vector<int> c(n);
- for (int i=0; i<n; i++)
- c[i] = a[i] * b[i];
-
- float cavg, cvar;
- getdist(c, cavg, cvar);
-
- cout << "c avg " << cavg << " var " << cvar << endl;
-
-}
--- /dev/null
+#ifndef _CRUSH_TYPES_H
+#define _CRUSH_TYPES_H
+
+#ifdef KERNEL
+# define free(x) kfree(x)
+#else
+# include <stdlib.h>
+#endif
+
+
+#include <linux/types.h> /* just for int types */
+
+#ifndef BUG_ON
+# include <assert.h>
+# define BUG_ON(x) assert(!(x))
+#endif
+
+#endif
+++ /dev/null
-
-CC = gcc
-CFLAGS = -Wall
-CFLAGS += -O3 -g
-LD = ld
-RM = rm
-
-all: depend builder.o libcrush.o
-
-clean:
- rm -f *.o libcrush.o
-
-%.o: %.c
- ${CC} ${CFLAGS} -c $< -o $@
-
-libcrush.o: crush.o buckets.o
- $(LD) -i -o $@ $^
-
-.depend:
- touch .depend
-
-depend:
- $(RM) .depend
- makedepend -f- -- $(CFLAGS) -- *.c > .depend 2>/dev/null
-
-include .depend
+++ /dev/null
-
-#include "hash.h"
-#include "buckets.h"
-
-int
-crush_bucket_uniform_choose(struct crush_bucket_uniform *bucket, int x, int r)
-{
- unsigned o, p, s;
- o = crush_hash32_2(x, bucket->h.id);
- p = bucket->primes[crush_hash32_2(bucket->h.id, x) % bucket->h.size];
- s = (x + o + (r+1)*p) % bucket->h.size;
- return bucket->h.items[s];
-}
-
-int
-crush_bucket_list_choose(struct crush_bucket_list *bucket, int x, int r)
-{
- int i;
- __u64 w;
-
- for (i=0; i<bucket->h.size; i++) {
- w = crush_hash32_4(x, bucket->h.items[i], r, bucket->h.id) & 0xffff;
- w = (w * bucket->sum_weights[i]) >> 32;
- if (w < bucket->item_weights[i])
- return bucket->h.items[i];
- }
-
- BUG_ON(1);
- return 0;
-}
-
-int
-crush_bucket_tree_choose(struct crush_bucket_tree *bucket, int x, int r)
-{
- return 0;
-}
-
-int
-crush_bucket_straw_choose(struct crush_bucket_straw *bucket, int x, int r)
-{
- int i;
- int high = 0;
- unsigned high_draw = 0;
- __u64 draw;
-
- for (i=0; i<bucket->h.size; i++) {
- draw = (crush_hash32_3(x, bucket->h.items[i], r) & 0xffff) * bucket->straws[i];
- draw = draw >> 32;
- if (i == 0 || draw > high_draw) {
- high = i;
- high_draw = draw;
- }
- }
-
- return high;
-}
-
-
-
-void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b)
-{
- free(b->primes);
- free(b->h.items);
-}
-
-void crush_destroy_bucket_list(struct crush_bucket_list *b)
-{
- free(b->item_weights);
- free(b->sum_weights);
- free(b->h.items);
-}
-
-void crush_destroy_bucket_tree(struct crush_bucket_tree *b)
-{
- free(b->h.items);
-}
-
-void crush_destroy_bucket_straw(struct crush_bucket_straw *b)
-{
- free(b->straws);
- free(b->h.items);
-}
+++ /dev/null
-#ifndef _CRUSH_BUCKETS_H
-#define _CRUSH_BUCKETS_H
-
-#include "types.h"
-
-enum {
- CRUSH_BUCKET_UNIFORM = 1,
- CRUSH_BUCKET_LIST = 2,
- CRUSH_BUCKET_TREE = 3,
- CRUSH_BUCKET_STRAW = 4
-};
-
-struct crush_bucket {
- __u32 id;
- __u32 type;
- __u32 weight; /* 16-bit fixed point */
- __u32 size; /* num items */
- __s32 *items;
-};
-
-struct crush_bucket_uniform {
- struct crush_bucket h;
- __u32 item_weight; /* 16-bit fixed point */
- __u32 *primes;
-};
-
-struct crush_bucket_list {
- struct crush_bucket h;
- __u32 *item_weights; /* 16-bit fixed point */
- __u32 *sum_weights; /* 16-bit fixed point. element i is sum of weights 0..i, inclusive */
-};
-
-struct crush_bucket_tree {
- struct crush_bucket h;
-
-};
-
-struct crush_bucket_straw {
- struct crush_bucket h;
- __u32 *straws; /* 16-bit fixed point */
-};
-
-extern int crush_bucket_uniform_choose(struct crush_bucket_uniform *bucket, int x, int r);
-extern int crush_bucket_list_choose(struct crush_bucket_list *bucket, int x, int r);
-extern int crush_bucket_tree_choose(struct crush_bucket_tree *bucket, int x, int r);
-extern int crush_bucket_straw_choose(struct crush_bucket_straw *bucket, int x, int r);
-
-extern void crush_destroy_bucket_uniform(struct crush_bucket_uniform *);
-extern void crush_destroy_bucket_list(struct crush_bucket_list *);
-extern void crush_destroy_bucket_tree(struct crush_bucket_tree *);
-extern void crush_destroy_bucket_straw(struct crush_bucket_straw *);
-
-#endif
+++ /dev/null
-
-#include <string.h>
-#include <math.h>
-#include <stdlib.h>
-
-#include "builder.h"
-#include "hash.h"
-
-
-struct crush_map *crush_new()
-{
- struct crush_map *m;
- m = malloc(sizeof(*m));
- memset(&m, 0, sizeof(m));
- return m;
-}
-
-/*
- * finalize should be called _after_ all buckets are added to the map.
- */
-void crush_finalize(struct crush_map *map)
-{
- int b, i, c;
-
- /* calc max_devices */
- for (b=0; b<map->max_buckets; b++) {
- if (map->buckets[b] == 0) continue;
- for (i=0; i<map->buckets[b]->size; i++)
- if (map->buckets[b]->items[i] > map->max_devices)
- map->max_devices = map->buckets[b]->items[i];
- }
-
- /* allocate arrays */
- map->device_parents = malloc(sizeof(map->device_parents[0]) * map->max_devices);
- map->device_offload = malloc(sizeof(map->device_offload[0]) * map->max_devices);
- memset(map->device_parents, 0, sizeof(map->device_parents[0]) * map->max_devices);
- memset(map->device_offload, 0, sizeof(map->device_offload[0]) * map->max_devices);
- map->bucket_parents = malloc(sizeof(map->bucket_parents[0]) * map->max_buckets);
- memset(map->bucket_parents, 0, sizeof(map->bucket_parents[0]) * map->max_buckets);
-
- /* build reverse map */
- for (b=0; b<map->max_buckets; b++) {
- if (map->buckets[b] == 0) continue;
- for (i=0; i<map->buckets[b]->size; i++) {
- c = map->buckets[b]->items[i];
- if (c >= 0)
- map->device_parents[c] = map->buckets[b]->id;
- else
- map->bucket_parents[-c] = map->buckets[b]->id;
- }
- }
-}
-
-/*
- * deallocate
- */
-void crush_destroy(struct crush_map *map)
-{
- int b;
-
- /* buckets */
- for (b=0; b<map->max_buckets; b++) {
- if (map->buckets[b] == 0) continue;
- switch (map->buckets[b]->type) {
- case CRUSH_BUCKET_UNIFORM:
- crush_destroy_bucket_uniform((struct crush_bucket_uniform*)map->buckets[b]);
- break;
- case CRUSH_BUCKET_LIST:
- crush_destroy_bucket_list((struct crush_bucket_list*)map->buckets[b]);
- break;
- case CRUSH_BUCKET_TREE:
- crush_destroy_bucket_tree((struct crush_bucket_tree*)map->buckets[b]);
- break;
- case CRUSH_BUCKET_STRAW:
- crush_destroy_bucket_straw((struct crush_bucket_straw*)map->buckets[b]);
- break;
- }
- }
- free(map->buckets);
-
- /* rules */
- for (b=0; b<map->max_rules; b++) {
- if (map->rules[b] == 0) continue;
- if (map->rules[b]->steps)
- free(map->rules[b]->steps);
- free(map->rules[b]);
- }
- free(map->rules);
-
- free(map->bucket_parents);
- free(map->device_parents);
- free(map->device_offload);
-
- memset(map, 0, sizeof(*map));
-}
-
-
-
-
-/** rules **/
-
-int crush_add_rule(struct crush_map *map,
- struct crush_rule *rule)
-{
- int id;
-
- /* find a rule id */
- for (id=0; id < map->max_rules; id++)
- if (map->rules[id] == 0) break;
- if (id == map->max_rules) {
- /* expand array */
- if (map->max_rules)
- map->max_rules *= 2;
- else
- map->max_rules = 8;
- map->rules = realloc(map->rules, map->max_rules * sizeof(map->rules[0]));
- }
-
- /* add it */
- map->rules[id] = rule;
- return id;
-}
-
-struct crush_rule *crush_make_rule()
-{
- struct crush_rule *rule;
-
- rule = malloc(sizeof(struct crush_rule));
- memset(&rule, 0, sizeof(rule));
- return rule;
-}
-
-void crush_rule_add_step(struct crush_rule *rule, int op, int arg1, int arg2)
-{
- rule->len++;
- if (rule->steps)
- rule->steps = malloc(sizeof(rule->steps[0])*rule->len);
- else
- rule->steps = realloc(rule->steps, sizeof(rule->steps[0])*rule->len);
- rule->steps[rule->len-1].op = op;
- rule->steps[rule->len-1].arg1 = arg1;
- rule->steps[rule->len-1].arg2 = arg2;
-}
-
-
-/** buckets **/
-
-int crush_add_bucket(struct crush_map *map,
- struct crush_bucket *bucket)
-{
- int id;
-
- /* find a bucket id */
- for (id=0; id < map->max_buckets; id++)
- if (map->buckets[id] == 0) break;
- if (id == map->max_buckets) {
- /* expand array */
- if (map->max_buckets)
- map->max_buckets *= 2;
- else
- map->max_buckets = 8;
- map->buckets = realloc(map->buckets, map->max_buckets * sizeof(map->buckets[0]));
- }
-
- /* add it */
- bucket->id = id;
- map->buckets[id] = bucket;
- return id;
-}
-
-
-void crush_make_uniform_bucket(struct crush_map *map,
- struct crush_bucket_uniform *bucket,
- int size,
- int *items,
- int item_weight)
-{
- int i, j, x;
-
- memset(bucket, 0, sizeof(*bucket));
- bucket->h.size = size;
- bucket->h.weight = size * item_weight;
-
- bucket->item_weight = item_weight;
-
- bucket->h.items = malloc(sizeof(__u32)*size);
- for (i=0; i<size; i++)
- bucket->h.items[i] = items[i];
-
- /* generate some primes */
- bucket->primes = malloc(sizeof(__u32)*size);
-
- x = size + 1;
- x += crush_hash32(size) % (3*size); /* make it big */
- x |= 1; /* and odd */
-
- i=0;
- while (i < size) {
- for (j=2; j*j <= x; j++)
- if (x % j == 0) break;
- if (j*j > x)
- bucket->primes[i++] = x;
- x += 2;
- }
-}
-
-void crush_make_list_bucket(struct crush_map *map,
- struct crush_bucket_list *bucket,
- int size,
- int *items,
- int *weights)
-{
- int i;
- int w;
-
- memset(bucket, 0, sizeof(*bucket));
- bucket->h.size = size;
-
- bucket->h.items = malloc(sizeof(__u32)*size);
- bucket->item_weights = malloc(sizeof(__u32)*size);
- bucket->sum_weights = malloc(sizeof(__u32)*size);
- w = 0;
- for (i=0; i<size; i++) {
- bucket->h.items[i] = items[i];
- bucket->item_weights[i] = weights[i];
- w += weights[i];
- bucket->sum_weights[i] = w;
- }
-
- bucket->h.weight = w;
-}
-
-
-void crush_make_straw_bucket(struct crush_map *map,
- struct crush_bucket_straw *bucket,
- int size,
- int *items,
- int *weights)
-{
- int *reverse;
- int i, j, k;
-
- double straw, wbelow, lastw, wnext, pbelow;
- int numleft;
-
- memset(bucket, 0, sizeof(*bucket));
- bucket->h.size = size;
-
- bucket->h.items = malloc(sizeof(__u32)*size);
- bucket->straws = malloc(sizeof(__u32)*size);
-
- bucket->h.weight = 0;
- for (i=0; i<size; i++) {
- bucket->h.items[i] = items[i];
- bucket->h.weight += weights[i];
- }
-
- /* reverse sort by weight */
- reverse = malloc(sizeof(int) * size);
- reverse[0] = items[0];
- for (i=1; i<size; i++) {
- for (j=0; j<i; j++) {
- if (weights[i] < weights[reverse[j]]) {
- /* insert here */
- for (k=i; k>j; k--)
- reverse[k] = reverse[k-1];
- reverse[j] = items[i];
- }
- }
- if (j == i)
- reverse[i] = items[i];
- }
-
- numleft = size;
- straw = 1.0;
- wbelow = 0;
- lastw = 0;
-
- i=0;
- while (i < size) {
- /* set this item's straw */
- bucket->straws[reverse[i]] = straw * 0x10000;
- i++;
- if (i == size) break;
-
- /* same weight as previous? */
- if (weights[reverse[i]] == weights[reverse[i-1]])
- continue;
-
- /* adjust straw for next guy */
- wbelow += (((double)weights[reverse[i-1]] / (double)0x10000) - lastw) * numleft;
- numleft--;
- wnext = numleft * ((double)(weights[reverse[i]] - weights[reverse[i-1]]) / (double)0x10000);
- pbelow = wbelow / (wbelow + wnext);
-
- straw *= pow((double)1.0 / pbelow, (double)1.0 / numleft);
-
- lastw = weights[reverse[i-1]];
- }
-
- free(reverse);
-
-}
-
+++ /dev/null
-
-#include "crush.h"
-#include "hash.h"
-
-/*
- * choose numrep distinct items of given type
- */
-static int crush_choose(struct crush_map *map,
- struct crush_bucket *bucket,
- int x, int numrep, int type,
- int *out, int firstn)
-{
- int rep;
- int ftotal, flocal;
- int retry_rep, skip_rep;
- struct crush_bucket *in = bucket;
- int r;
- int i;
- int item;
- int itemtype;
- int outpos;
- int collide, bad;
-
- outpos = 0;
-
- for (rep = 0; rep < numrep; rep++) {
- /* keep trying until we get a non-out, non-colliding item */
- ftotal = 0;
- skip_rep = 0;
-
- while (1) {
- in = bucket; /* initial bucket */
-
- /* choose through intervening buckets */
- flocal = 0;
- retry_rep = 0;
-
- while (1) {
- r = rep;
- if (in->type == CRUSH_BUCKET_UNIFORM) {
- /* be careful */
- if (firstn || numrep >= in->size) {
- r += ftotal; /* r' = r + f_total */
- } else {
- r += numrep * flocal; /* r' = r + n*f_local */
- /* make sure numrep is not a multiple of bucket size */
- if (in->size % numrep == 0)
- /* shift seq once per pass through the bucket */
- r += numrep * flocal / in->size;
- }
- } else {
- if (firstn)
- r += ftotal; /* r' = r + f_total */
- else
- r += numrep * flocal; /* r' = r + n*f_local */
- }
-
- /* bucket choose */
- switch (in->type) {
- case CRUSH_BUCKET_UNIFORM:
- item = crush_bucket_uniform_choose((struct crush_bucket_uniform*)in, x, r);
- break;
- case CRUSH_BUCKET_LIST:
- item = crush_bucket_list_choose((struct crush_bucket_list*)in, x, r);
- break;
- case CRUSH_BUCKET_TREE:
- item = crush_bucket_tree_choose((struct crush_bucket_tree*)in, x, r);
- break;
- case CRUSH_BUCKET_STRAW:
- item = crush_bucket_straw_choose((struct crush_bucket_straw*)in, x, r);
- break;
- default:
- BUG_ON(1);
- }
-
- /* desired type? */
- if (item < 0)
- itemtype = map->buckets[-item]->type;
- else
- itemtype = 0;
-
- /* keep going? */
- if (itemtype != type) {
- in = map->buckets[-item];
- continue;
- }
-
- /* collision? */
- collide = 0;
- for (i=0; i<rep; i++) {
- if (out[i] == item) {
- collide = 1;
- break;
- }
- }
-
- /* bad (out)? */
- bad = 0;
- if (itemtype == 0 && map->device_offload[item]) {
- if (map->device_offload[item] >= 0x10000)
- bad = 1;
- else if ((crush_hash32_2(x, item) & 0xffff) < map->device_offload[item])
- bad = 1;
- }
-
- if (bad || collide) {
- ftotal++;
- flocal++;
-
- if (collide && flocal < 3)
- continue; /* locally a few times */
- if (ftotal >= 10) {
- /* give up, ignore dup, fixme */
- skip_rep = 1;
- break;
- }
- retry_rep = 1;
- }
- break;
- }
-
- if (retry_rep) continue;
- }
-
- if (skip_rep) continue;
-
- out[outpos] = item;
- outpos++;
- }
-
- return outpos;
-}
-
-
-int crush_do_rule(struct crush_map *map,
- int ruleno,
- int x, int *result, int result_max,
- int forcefeed) /* -1 for none */
-{
- int result_len;
- int force_stack[CRUSH_MAX_DEPTH];
- int force_pos = -1;
- int a[CRUSH_MAX_SET];
- int b[CRUSH_MAX_SET];
- int *w;
- int wsize = 0;
- int *o;
- int osize;
- int *tmp;
- struct crush_rule *rule;
- int step;
- int i;
- int numrep;
-
- rule = map->rules[ruleno];
- result_len = 0;
- w = a;
- o = b;
-
- /* determine hierarchical context of forcefeed, if any */
- if (forcefeed >= 0) {
- while (1) {
- force_stack[++force_pos] = forcefeed;
- if (forcefeed >= 0)
- forcefeed = map->device_parents[forcefeed];
- else
- forcefeed = map->bucket_parents[-forcefeed];
- if (forcefeed == 0) break;
- }
- }
-
- for (step = 0; step < rule->len; step++) {
- switch (rule->steps[step].op) {
- case CRUSH_RULE_TAKE:
- if (force_pos >= 0) {
- w[0] = force_stack[force_pos];
- force_pos--;
- BUG_ON(w[0] != rule->steps[step].arg1);
- } else {
- w[0] = rule->steps[step].arg1;
- }
- wsize = 1;
- break;
-
- case CRUSH_RULE_CHOOSE_FIRSTN:
- case CRUSH_RULE_CHOOSE_INDEP:
- BUG_ON(wsize == 0);
-
- /* reset output */
- osize = 0;
-
- for (i = 0; i < wsize; i++) {
- numrep = rule->steps[step].arg1;
-
- if (force_pos >= 0) {
- o[osize++] = force_stack[force_pos];
- force_pos--;
- numrep--;
- }
- if (numrep)
- crush_choose(map,
- map->buckets[-w[i]],
- x, numrep, rule->steps[step].arg2,
- o+osize, rule->steps[step].op == CRUSH_RULE_CHOOSE_FIRSTN);
- }
-
- /* swap t and w arrays */
- tmp = o;
- o = w;
- w = o;
- wsize = osize;
- break;
-
-
- case CRUSH_RULE_EMIT:
- for (i=0; i<wsize && result_max; i++) {
- result[result_len] = w[i];
- result_len++;
- result_max--;
- }
- wsize = 0;
- break;
-
- default:
- BUG_ON(1);
- }
- }
-
- return result_len;
-}
-
+++ /dev/null
-#ifndef _CRUSH_CRUSH_H
-#define _CRUSH_CRUSH_H
-
-#include "types.h"
-#include "buckets.h"
-
-enum {
- CRUSH_RULE_TAKE,
- CRUSH_RULE_CHOOSE_FIRSTN,
- CRUSH_RULE_CHOOSE_INDEP,
- CRUSH_RULE_EMIT
-};
-
-#define CRUSH_MAX_DEPTH 10
-#define CRUSH_MAX_SET 10
-
-struct crush_rule_step {
- __u32 op;
- __s32 arg1;
- __s32 arg2;
-};
-
-struct crush_rule {
- __u32 len;
- struct crush_rule_step *steps;
-};
-
-struct crush_map {
- struct crush_bucket **buckets;
- struct crush_rule **rules;
-
- /* parent pointers */
- __u32 *bucket_parents;
- __u32 *device_parents;
-
- /* offload
- * size max_devices, values 0...0xffff
- * 0 == normal
- * 0x10000 == 100% offload (i.e. failed)
- */
- __u32 *device_offload;
-
- __u32 max_buckets;
- __u32 max_rules;
- __u32 max_devices;
-};
-
-extern int crush_do_rule(struct crush_map *map,
- int ruleno,
- int x, int *result, int result_max,
- int forcefeed); /* -1 for none */
-
-/*extern int crush_decode(struct crush_map *map, struct ceph_bufferlist *bl);*/
-
-#endif
+++ /dev/null
-#ifndef _CRUSH_HASH_H
-#define _CRUSH_HASH_H
-
-// Robert Jenkins' function for mixing 32-bit values
-// http://burtleburtle.net/bob/hash/evahash.html
-// a, b = random bits, c = input and output
-#define hashmix(a,b,c) \
- a=a-b; a=a-c; a=a^(c>>13); \
- b=b-c; b=b-a; b=b^(a<<8); \
- c=c-a; c=c-b; c=c^(b>>13); \
- a=a-b; a=a-c; a=a^(c>>12); \
- b=b-c; b=b-a; b=b^(a<<16); \
- c=c-a; c=c-b; c=c^(b>>5); \
- a=a-b; a=a-c; a=a^(c>>3); \
- b=b-c; b=b-a; b=b^(a<<10); \
- c=c-a; c=c-b; c=c^(b>>15);
-
-#define crush_hash_seed 1315423911
-
-static __inline__ unsigned crush_hash32(unsigned a) {
- unsigned hash = crush_hash_seed ^ a;
- unsigned b = a;
- unsigned x = 231232;
- unsigned y = 1232;
- hashmix(b, x, hash);
- hashmix(y, a, hash);
- return (hash & 0xFFFFFFFF);
-}
-
-static __inline__ unsigned crush_hash32_2(unsigned a, unsigned b) {
- unsigned hash = crush_hash_seed ^ a ^ b;
- unsigned x = 231232;
- unsigned y = 1232;
- hashmix(a, b, hash);
- hashmix(x, a, hash);
- hashmix(b, y, hash);
- return (hash & 0xFFFFFFFF);
-}
-
-static __inline__ unsigned crush_hash32_3(unsigned a, unsigned b, unsigned c) {
- unsigned int hash = crush_hash_seed ^ a ^ b ^ c;
- unsigned x = 231232;
- unsigned y = 1232;
- hashmix(a, b, hash);
- hashmix(c, x, hash);
- hashmix(y, a, hash);
- hashmix(b, x, hash);
- hashmix(y, c, hash);
- return (hash & 0xFFFFFFFF);
-}
-
-static __inline__ unsigned crush_hash32_4(unsigned a, unsigned b, unsigned c, unsigned d) {
- unsigned int hash = crush_hash_seed ^a ^ b ^ c ^ d;
- unsigned x = 231232;
- unsigned y = 1232;
- hashmix(a, b, hash);
- hashmix(c, d, hash);
- hashmix(a, x, hash);
- hashmix(y, b, hash);
- hashmix(c, x, hash);
- hashmix(y, d, hash);
- return (hash & 0xFFFFFFFF);
-}
-
-static __inline__ unsigned crush_hash32_5(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e) {
- unsigned int hash = crush_hash_seed ^ a ^ b ^ c ^ d ^ e;
- unsigned x = 231232;
- unsigned y = 1232;
- hashmix(a, b, hash);
- hashmix(c, d, hash);
- hashmix(e, x, hash);
- hashmix(y, a, hash);
- hashmix(b, x, hash);
- hashmix(y, c, hash);
- hashmix(d, x, hash);
- hashmix(y, e, hash);
- return (hash & 0xFFFFFFFF);
-}
-
-#endif
+++ /dev/null
-#ifndef _CRUSH_TYPES_H
-#define _CRUSH_TYPES_H
-
-#ifdef KERNEL
-# define free(x) kfree(x)
-#else
-# include <stdlib.h>
-#endif
-
-
-#include <linux/types.h> /* just for int types */
-
-#ifndef BUG_ON
-# include <assert.h>
-# define BUG_ON(x) assert(!(x))
-#endif
-
-#endif
#include "MonitorStore.h"
+#include "crush/CrushWrapper.h"
+
#include "messages/MOSDFailure.h"
#include "messages/MOSDMap.h"
#include "messages/MOSDGetMap.h"
}
-void OSDMonitor::build_crush_map(Crush& crush,
+void OSDMonitor::build_crush_map(CrushWrapper& crush,
map<int,double>& weights)
{
+ // new
+ crush.create();
if (g_conf.num_osd >= 12) {
int ndom = g_conf.osd_max_rep;
- UniformBucket *domain[ndom];
- int domid[ndom];
- for (int i=0; i<ndom; i++) {
- domain[i] = new UniformBucket(1, 0);
- domid[i] = crush.add_bucket(domain[i]);
- }
-
- // add osds
+ int ritems[ndom];
+ int rweights[ndom];
+
int nper = ((g_conf.num_osd - 1) / ndom) + 1;
derr(0) << ndom << " failure domains, " << nper << " osds each" << dendl;
- int i = 0;
- for (int dom=0; dom<ndom; dom++) {
- for (int j=0; j<nper; j++) {
- domain[dom]->add_item(i, weights[i] ? weights[i]:1.0);
- //derr(0) << "osd" << i << " in domain " << dom << dendl;
- i++;
- if (i == g_conf.num_osd) break;
+
+ int o = 0;
+ for (int i=0; i<ndom; i++) {
+ int items[nper];
+ //int w[nper];
+ int j;
+ rweights[i] = 0;
+ for (j=0; j<nper; j++, o++) {
+ if (o == g_conf.num_osd) break;
+ dout(20) << "added osd" << o << dendl;
+ items[j] = o;
+ //w[j] = weights[o] ? (0x10000 - (int)(weights[o] * 0x10000)):0x10000;
+ //rweights[i] += w[j];
+ rweights[i] += 0x10000;
}
+
+ crush_bucket_uniform *domain = crush_make_uniform_bucket(1, j, items, 0x10000);
+ ritems[i] = crush_add_bucket(crush.map, (crush_bucket*)domain);
+ dout(20) << "added domain bucket i " << ritems[i] << " of size " << j << dendl;
}
// root
- Bucket *root = new ListBucket(2);
- for (int i=0; i<ndom; i++) {
- //derr(0) << "dom " << i << " w " << domain[i]->get_weight() << dendl;
- root->add_item(domid[i], domain[i]->get_weight());
- }
- int nroot = crush.add_bucket(root);
+ crush_bucket_list *root = crush_make_list_bucket(2, ndom, ritems, rweights);
+ int rootid = crush_add_bucket(crush.map, (crush_bucket*)root);
// rules
// replication
for (int i=1; i<=ndom; i++) {
- int r = CRUSH_REP_RULE(i);
- crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_TAKE, nroot));
- crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, i, 1));
- crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, 1, 0));
- crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+ crush_rule *rule = crush_make_rule();
+ crush_rule_add_step(rule, CRUSH_RULE_TAKE, rootid, 0);
+ crush_rule_add_step(rule, CRUSH_RULE_CHOOSE_FIRSTN, i, 1);
+ crush_rule_add_step(rule, CRUSH_RULE_CHOOSE_FIRSTN, 1, 0);
+ crush_rule_add_step(rule, CRUSH_RULE_EMIT, 0, 0);
+ crush_add_rule(crush.map, CRUSH_REP_RULE(i), rule);
}
+ /*
// raid
for (int i=g_conf.osd_min_raid_width; i <= g_conf.osd_max_raid_width; i++) {
int r = CRUSH_RAID_RULE(i);
crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_EMIT));
}
}
+ */
// test
//vector<int> out;
} else {
// one bucket
- Bucket *b = new UniformBucket(1, 0);
- int root = crush.add_bucket(b);
- for (int i=0; i<g_conf.num_osd; i++) {
- b->add_item(i, weights[i] ? weights[i]:1.0);
- }
+
+ int items[g_conf.num_osd];
+ for (int i=0; i<g_conf.num_osd; i++)
+ items[i] = i;
+
+ crush_bucket_uniform *b = crush_make_uniform_bucket(1, g_conf.num_osd, items, 0x10000);
+ int root = crush_add_bucket(crush.map, (crush_bucket*)b);
// rules
// replication
for (int i=1; i<=g_conf.osd_max_rep; i++) {
- int r = CRUSH_REP_RULE(i);
- crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
- crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, i, 0));
- crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+ crush_rule *rule = crush_make_rule();
+ crush_rule_add_step(rule, CRUSH_RULE_TAKE, root, 0);
+ crush_rule_add_step(rule, CRUSH_RULE_CHOOSE_FIRSTN, i, 0);
+ crush_rule_add_step(rule, CRUSH_RULE_EMIT, 0, 0);
+ crush_add_rule(crush.map, CRUSH_REP_RULE(i), rule);
}
+ /*
// raid
for (int i=g_conf.osd_min_raid_width; i <= g_conf.osd_max_raid_width; i++) {
int r = CRUSH_RAID_RULE(i);
crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_CHOOSE_INDEP, i, 0));
crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_EMIT));
}
+ */
}
+ crush.finalize();
+ dout(20) << "crush max_devices " << crush.map->max_devices << dendl;
+ //vector<int> t;
+ //crush.do_rule(2, 132, t, 4, -1);
}
if (pending_inc.new_up.size() == osdmap.get_osds().size()) {
delay = 0.0;
if (g_conf.osd_auto_weight) {
- Crush crush;
+ CrushWrapper crush;
build_crush_map(crush, osd_weight);
crush._encode(pending_inc.crush);
}
map<int,double> osd_weight;
- void build_crush_map(Crush& crush,
+ void build_crush_map(CrushWrapper& crush,
map<int,double>& weights);
// svc
#include "common/Mutex.h"
#include "common/Clock.h"
-#include "crush/crush.h"
-using namespace crush;
+#include "crush/CrushWrapper.h"
#include <vector>
#include <list>
map<int32_t,entity_inst_t> osd_inst;
public:
- Crush crush; // hierarchical map
+ CrushWrapper crush; // hierarchical map
friend class OSDMonitor;
friend class MDS;
void mark_down(int o, bool clean) { down_osds[o] = clean; }
void mark_up(int o) { down_osds.erase(o); }
- void mark_out(int o) { out_osds.insert(o); }
- void mark_in(int o) { out_osds.erase(o); }
-
+ void mark_out(int o) {
+ out_osds.insert(o);
+ crush.update_offload_map(out_osds, overload_osds);
+ }
+ void mark_in(int o) {
+ out_osds.erase(o);
+ crush.update_offload_map(out_osds, overload_osds);
+ }
void apply_incremental(Incremental &inc) {
assert(inc.epoch == epoch+1);
return;
}
if (inc.crush.length()) {
- int off = 0;
- crush._decode(inc.crush, off);
+ bufferlist::iterator blp = inc.crush.begin();
+ crush._decode(blp);
}
// nope, incremental.
i++) {
overload_osds[i->first] = i->second;
}
+
+ crush.update_offload_map(out_osds, overload_osds);
}
// serialize, unserialize
::_encode(overload_osds, blist);
::_encode(osd_inst, blist);
- crush._encode(blist);
+ bufferlist cbl;
+ crush._encode(cbl);
+ ::_encode(cbl, blist);
}
void decode(bufferlist& blist) {
::_decode(overload_osds, blist, off);
::_decode(osd_inst, blist, off);
- crush._decode(blist, off);
+ bufferlist cbl;
+ ::_decode(cbl, blist, off);
+ bufferlist::iterator cblp = cbl.begin();
+ crush._decode(cblp);
+
+ crush.update_offload_map(out_osds, overload_osds);
}
}
ObjectLayout make_object_layout(object_t oid, int pg_type, int pg_size, int preferred=-1, int object_stripe_unit = 0) {
- static crush::Hash H(777);
-
int num = preferred >= 0 ? localized_pg_num:pg_num;
int num_mask = preferred >= 0 ? localized_pg_num_mask:pg_num_mask;
case CEPH_OBJECT_LAYOUT_HASHINO:
//ps = stable_mod(oid.bno + H(oid.bno+oid.ino)^H(oid.ino>>32), num, num_mask);
- ps = stable_mod(oid.bno + H(oid.ino)^H(oid.ino>>32), num, num_mask);
+ ps = stable_mod(oid.bno + crush_hash32_2(oid.ino, oid.ino>>32), num, num_mask);
break;
case CEPH_OBJECT_LAYOUT_HASH:
//ps = stable_mod(H( (oid.bno & oid.ino) ^ ((oid.bno^oid.ino) >> 32) ), num, num_mask);
//ps = stable_mod(H(oid.bno) + H(oid.ino)^H(oid.ino>>32), num, num_mask);
//ps = stable_mod(oid.bno + H(oid.bno+oid.ino)^H(oid.bno+oid.ino>>32), num, num_mask);
- ps = stable_mod(oid.bno + H(oid.ino)^H(oid.ino>>32), num, num_mask);
+ ps = stable_mod(oid.bno + crush_hash32_2(oid.ino, oid.ino>>32), num, num_mask);
break;
default:
if (pg.preferred() >= 0 &&
out_osds.count(pg.preferred()) == 0)
forcefeed = pg.preferred();
- crush.do_rule(crush.rules[rule],
+ crush.do_rule(rule,
pg.ps(),
- osds,
- out_osds, overload_osds,
+ osds, pg.size(),
forcefeed);
}
break;
case CEPH_PG_LAYOUT_HYBRID:
{
- static crush::Hash H(777);
- int h = H(pg.ps());
+ int h = crush_hash32(pg.ps());
for (int i=0; i<pg.size(); i++)
osds.push_back( (h+i) % g_conf.num_osd );
}
case CEPH_PG_LAYOUT_HASH:
{
- static crush::Hash H(777);
for (int i=0; i<pg.size(); i++) {
int t = 1;
int osd = 0;
while (t++) {
- osd = H(i, pg.ps(), t) % g_conf.num_osd;
+ osd = crush_hash32_3(i, pg.ps(), t) % g_conf.num_osd;
int j = 0;
for (; j<i; j++)
if (osds[j] == osd) break;
using namespace std;
#include <ext/hash_map>
+#include <ext/hash_set>
using namespace __gnu_cxx;
// crush rule ids
-#define CRUSH_REP_RULE(nrep) (100+nrep) // replication
-#define CRUSH_RAID_RULE(num) (200+num) // raid
+#define CRUSH_REP_RULE(nrep) (nrep) // replication
+#define CRUSH_RAID_RULE(num) (10+num) // raid