diff options
author | Sage Weil <sage@newdream.net> | 2017-06-15 23:34:10 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-15 23:34:10 +0200 |
commit | 078e910eff67b5b89fb98e70f8c470584afc5214 (patch) | |
tree | a0d9993a13556e02d0f0151031a00dcc3d2f3de0 /src/osd | |
parent | Merge pull request #15687 from xiexingguo/wip-fix-decode-oi (diff) | |
parent | qa: test 'osd df' in cephtool/test.sh (diff) | |
download | ceph-078e910eff67b5b89fb98e70f8c470584afc5214.tar.xz ceph-078e910eff67b5b89fb98e70f8c470584afc5214.zip |
Merge pull request #15675 from gregsfortytwo/wip-bad-command
mon,mgr: fix "ceph osd df", add some tools to find untested commands
Reviewed-by: Sage Weil <sage@redhat.com>
Reviewed-by: Kefu Chai <kchai@redhat.com>
Diffstat (limited to 'src/osd')
-rw-r--r-- | src/osd/OSDMap.cc | 321 | ||||
-rw-r--r-- | src/osd/OSDMap.h | 7 |
2 files changed, 328 insertions, 0 deletions
diff --git a/src/osd/OSDMap.cc b/src/osd/OSDMap.cc index 8097b8636a3..dead2fd616e 100644 --- a/src/osd/OSDMap.cc +++ b/src/osd/OSDMap.cc @@ -27,6 +27,7 @@ #include "crush/CrushTreeDumper.h" #include "common/Clock.h" +#include "mon/PGStatService.h" #define dout_subsys ceph_subsys_osd @@ -3905,3 +3906,323 @@ int OSDMap::get_osds_by_bucket_name(const string &name, set<int> *osds) const { return crush->get_leaves(name, osds); } + +template <typename F> +class OSDUtilizationDumper : public CrushTreeDumper::Dumper<F> { +public: + typedef CrushTreeDumper::Dumper<F> Parent; + + OSDUtilizationDumper(const CrushWrapper *crush, const OSDMap *osdmap_, + const PGStatService *pgs_, bool tree_) : + Parent(crush), + osdmap(osdmap_), + pgs(pgs_), + tree(tree_), + average_util(average_utilization()), + min_var(-1), + max_var(-1), + stddev(0), + sum(0) { + } + +protected: + void dump_stray(F *f) { + for (int i = 0; i < osdmap->get_max_osd(); i++) { + if (osdmap->exists(i) && !this->is_touched(i)) + dump_item(CrushTreeDumper::Item(i, 0, 0), f); + } + } + + void dump_item(const CrushTreeDumper::Item &qi, F *f) override { + if (!tree && qi.is_bucket()) + return; + + float reweight = qi.is_bucket() ? -1 : osdmap->get_weightf(qi.id); + int64_t kb = 0, kb_used = 0, kb_avail = 0; + double util = 0; + if (get_bucket_utilization(qi.id, &kb, &kb_used, &kb_avail)) + if (kb_used && kb) + util = 100.0 * (double)kb_used / (double)kb; + + double var = 1.0; + if (average_util) + var = util / average_util; + + size_t num_pgs = qi.is_bucket() ? 0 : pgs->get_num_pg_by_osd(qi.id); + + dump_item(qi, reweight, kb, kb_used, kb_avail, util, var, num_pgs, f); + + if (!qi.is_bucket() && reweight > 0) { + if (min_var < 0 || var < min_var) + min_var = var; + if (max_var < 0 || var > max_var) + max_var = var; + + double dev = util - average_util; + dev *= dev; + stddev += reweight * dev; + sum += reweight; + } + } + + virtual void dump_item(const CrushTreeDumper::Item &qi, + float &reweight, + int64_t kb, + int64_t kb_used, + int64_t kb_avail, + double& util, + double& var, + const size_t num_pgs, + F *f) = 0; + + double dev() { + return sum > 0 ? sqrt(stddev / sum) : 0; + } + + double average_utilization() { + int64_t kb = 0, kb_used = 0; + for (int i = 0; i < osdmap->get_max_osd(); i++) { + if (!osdmap->exists(i) || osdmap->get_weight(i) == 0) + continue; + int64_t kb_i, kb_used_i, kb_avail_i; + if (get_osd_utilization(i, &kb_i, &kb_used_i, &kb_avail_i)) { + kb += kb_i; + kb_used += kb_used_i; + } + } + return kb > 0 ? 100.0 * (double)kb_used / (double)kb : 0; + } + + bool get_osd_utilization(int id, int64_t* kb, int64_t* kb_used, + int64_t* kb_avail) const { + const osd_stat_t *p = pgs->get_osd_stat(id); + if (!p) return false; + *kb = p->kb; + *kb_used = p->kb_used; + *kb_avail = p->kb_avail; + return *kb > 0; + } + + bool get_bucket_utilization(int id, int64_t* kb, int64_t* kb_used, + int64_t* kb_avail) const { + if (id >= 0) { + if (osdmap->is_out(id)) { + *kb = 0; + *kb_used = 0; + *kb_avail = 0; + return true; + } + return get_osd_utilization(id, kb, kb_used, kb_avail); + } + + *kb = 0; + *kb_used = 0; + *kb_avail = 0; + + for (int k = osdmap->crush->get_bucket_size(id) - 1; k >= 0; k--) { + int item = osdmap->crush->get_bucket_item(id, k); + int64_t kb_i = 0, kb_used_i = 0, kb_avail_i = 0; + if (!get_bucket_utilization(item, &kb_i, &kb_used_i, &kb_avail_i)) + return false; + *kb += kb_i; + *kb_used += kb_used_i; + *kb_avail += kb_avail_i; + } + return *kb > 0; + } + +protected: + const OSDMap *osdmap; + const PGStatService *pgs; + bool tree; + double average_util; + double min_var; + double max_var; + double stddev; + double sum; +}; + + +class OSDUtilizationPlainDumper : public OSDUtilizationDumper<TextTable> { +public: + typedef OSDUtilizationDumper<TextTable> Parent; + + OSDUtilizationPlainDumper(const CrushWrapper *crush, const OSDMap *osdmap, + const PGStatService *pgs, bool tree) : + Parent(crush, osdmap, pgs, tree) {} + + void dump(TextTable *tbl) { + tbl->define_column("ID", TextTable::LEFT, TextTable::RIGHT); + tbl->define_column("WEIGHT", TextTable::LEFT, TextTable::RIGHT); + tbl->define_column("REWEIGHT", TextTable::LEFT, TextTable::RIGHT); + tbl->define_column("SIZE", TextTable::LEFT, TextTable::RIGHT); + tbl->define_column("USE", TextTable::LEFT, TextTable::RIGHT); + tbl->define_column("AVAIL", TextTable::LEFT, TextTable::RIGHT); + tbl->define_column("%USE", TextTable::LEFT, TextTable::RIGHT); + tbl->define_column("VAR", TextTable::LEFT, TextTable::RIGHT); + tbl->define_column("PGS", TextTable::LEFT, TextTable::RIGHT); + if (tree) + tbl->define_column("TYPE NAME", TextTable::LEFT, TextTable::LEFT); + + Parent::dump(tbl); + + dump_stray(tbl); + + *tbl << "" << "" << "TOTAL" + << si_t(pgs->get_osd_sum().kb << 10) + << si_t(pgs->get_osd_sum().kb_used << 10) + << si_t(pgs->get_osd_sum().kb_avail << 10) + << lowprecision_t(average_util) + << "" + << TextTable::endrow; + } + +protected: + struct lowprecision_t { + float v; + explicit lowprecision_t(float _v) : v(_v) {} + }; + friend std::ostream &operator<<(ostream& out, const lowprecision_t& v); + + using OSDUtilizationDumper<TextTable>::dump_item; + void dump_item(const CrushTreeDumper::Item &qi, + float &reweight, + int64_t kb, + int64_t kb_used, + int64_t kb_avail, + double& util, + double& var, + const size_t num_pgs, + TextTable *tbl) override { + *tbl << qi.id + << weightf_t(qi.weight) + << weightf_t(reweight) + << si_t(kb << 10) + << si_t(kb_used << 10) + << si_t(kb_avail << 10) + << lowprecision_t(util) + << lowprecision_t(var); + + if (qi.is_bucket()) { + *tbl << "-"; + } else { + *tbl << num_pgs; + } + + if (tree) { + ostringstream name; + for (int k = 0; k < qi.depth; k++) + name << " "; + if (qi.is_bucket()) { + int type = crush->get_bucket_type(qi.id); + name << crush->get_type_name(type) << " " + << crush->get_item_name(qi.id); + } else { + name << "osd." << qi.id; + } + *tbl << name.str(); + } + + *tbl << TextTable::endrow; + } + +public: + string summary() { + ostringstream out; + out << "MIN/MAX VAR: " << lowprecision_t(min_var) + << "/" << lowprecision_t(max_var) << " " + << "STDDEV: " << lowprecision_t(dev()); + return out.str(); + } +}; + +ostream& operator<<(ostream& out, + const OSDUtilizationPlainDumper::lowprecision_t& v) +{ + if (v.v < -0.01) { + return out << "-"; + } else if (v.v < 0.001) { + return out << "0"; + } else { + std::streamsize p = out.precision(); + return out << std::fixed << std::setprecision(2) << v.v << std::setprecision(p); + } +} + +class OSDUtilizationFormatDumper : public OSDUtilizationDumper<Formatter> { +public: + typedef OSDUtilizationDumper<Formatter> Parent; + + OSDUtilizationFormatDumper(const CrushWrapper *crush, const OSDMap *osdmap, + const PGStatService *pgs, bool tree) : + Parent(crush, osdmap, pgs, tree) {} + + void dump(Formatter *f) { + f->open_array_section("nodes"); + Parent::dump(f); + f->close_section(); + + f->open_array_section("stray"); + dump_stray(f); + f->close_section(); + } + +protected: + using OSDUtilizationDumper<Formatter>::dump_item; + void dump_item(const CrushTreeDumper::Item &qi, + float &reweight, + int64_t kb, + int64_t kb_used, + int64_t kb_avail, + double& util, + double& var, + const size_t num_pgs, + Formatter *f) override { + f->open_object_section("item"); + CrushTreeDumper::dump_item_fields(crush, qi, f); + f->dump_float("reweight", reweight); + f->dump_int("kb", kb); + f->dump_int("kb_used", kb_used); + f->dump_int("kb_avail", kb_avail); + f->dump_float("utilization", util); + f->dump_float("var", var); + f->dump_unsigned("pgs", num_pgs); + CrushTreeDumper::dump_bucket_children(crush, qi, f); + f->close_section(); + } + +public: + void summary(Formatter *f) { + f->open_object_section("summary"); + f->dump_int("total_kb", pgs->get_osd_sum().kb); + f->dump_int("total_kb_used", pgs->get_osd_sum().kb_used); + f->dump_int("total_kb_avail", pgs->get_osd_sum().kb_avail); + f->dump_float("average_utilization", average_util); + f->dump_float("min_var", min_var); + f->dump_float("max_var", max_var); + f->dump_float("dev", dev()); + f->close_section(); + } +}; + +void print_osd_utilization(const OSDMap& osdmap, + const PGStatService *pgstat, + ostream& out, + Formatter *f, + bool tree) +{ + const CrushWrapper *crush = osdmap.crush.get(); + if (f) { + f->open_object_section("df"); + OSDUtilizationFormatDumper d(crush, &osdmap, pgstat, tree); + d.dump(f); + d.summary(f); + f->close_section(); + f->flush(out); + } else { + OSDUtilizationPlainDumper d(crush, &osdmap, pgstat, tree); + TextTable tbl; + d.dump(&tbl); + out << tbl << d.summary() << "\n"; + } +} diff --git a/src/osd/OSDMap.h b/src/osd/OSDMap.h index 264fc5f7fcf..a4b124d938d 100644 --- a/src/osd/OSDMap.h +++ b/src/osd/OSDMap.h @@ -1298,5 +1298,12 @@ inline ostream& operator<<(ostream& out, const OSDMap& m) { return out; } +class PGStatService; + +void print_osd_utilization(const OSDMap& osdmap, + const PGStatService *pgstat, + ostream& out, + Formatter *f, + bool tree); #endif |