mirror of
https://github.com/ceph/ceph
synced 2025-02-24 11:37:37 +00:00
move the OSDUtilizationDumper code into OSDMap
Signed-off-by: Greg Farnum <gfarnum@redhat.com>
This commit is contained in:
parent
7383a3a4b5
commit
234783c12b
@ -571,323 +571,6 @@ void OSDMonitor::update_logger()
|
||||
mon->cluster_logger->set(l_cluster_osd_epoch, osdmap.get_epoch());
|
||||
}
|
||||
|
||||
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 OSDMonitor::print_utilization(ostream &out, Formatter *f, bool tree) const
|
||||
{
|
||||
const CrushWrapper *crush = osdmap.crush.get();
|
||||
|
||||
if (f) {
|
||||
f->open_object_section("df");
|
||||
OSDUtilizationFormatDumper d(crush, &osdmap, mon->pgservice, tree);
|
||||
d.dump(f);
|
||||
d.summary(f);
|
||||
f->close_section();
|
||||
f->flush(out);
|
||||
} else {
|
||||
OSDUtilizationPlainDumper d(crush, &osdmap, mon->pgservice, tree);
|
||||
TextTable tbl;
|
||||
d.dump(&tbl);
|
||||
out << tbl
|
||||
<< d.summary() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void OSDMonitor::create_pending()
|
||||
{
|
||||
pending_inc = OSDMap::Incremental(osdmap.epoch+1);
|
||||
@ -4243,7 +3926,8 @@ bool OSDMonitor::preprocess_command(MonOpRequestRef op)
|
||||
} else if (prefix == "osd df") {
|
||||
string method;
|
||||
cmd_getval(g_ceph_context, cmdmap, "output_method", method);
|
||||
print_utilization(ds, f ? f.get() : NULL, method == "tree");
|
||||
print_osd_utilization(osdmap, mon->pgservice, ds,
|
||||
f ? f.get() : NULL, method == "tree");
|
||||
rdata.append(ds);
|
||||
} else if (prefix == "osd getmaxosd") {
|
||||
if (f) {
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include "crush/CrushTreeDumper.h"
|
||||
#include "common/Clock.h"
|
||||
#include "mon/PGStatService.h"
|
||||
|
||||
#define dout_subsys ceph_subsys_osd
|
||||
|
||||
@ -3908,3 +3909,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";
|
||||
}
|
||||
}
|
||||
|
@ -1299,5 +1299,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
|
||||
|
Loading…
Reference in New Issue
Block a user