// ---------------------------------------------------------------------- // File: Stat.cc // Author: Andreas-Joachim Peters - CERN // ---------------------------------------------------------------------- /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2011 CERN/Switzerland * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ #include "common/Mapping.hh" #include "common/table_formatter/TableFormatterBase.hh" #include "common/Statistics.hh" #include "mgm/Stat.hh" #include "mgm/FsView.hh" #include "mgm/XrdMgmOfs.hh" #include "mq/XrdMqSharedObject.hh" #include "mgm/Quota.hh" #include "XrdOuc/XrdOucString.hh" EOSMGMNAMESPACE_BEGIN /*----------------------------------------------------------------------------*/ void Stat::Add(const char* tag, uid_t uid, gid_t gid, unsigned long val) { XrdSysMutexHelper lock(mMutex); StatsUid[tag][uid] += val; StatsGid[tag][gid] += val; StatAvgUid[tag][uid].Add(val); StatAvgGid[tag][gid].Add(val); } /*----------------------------------------------------------------------------*/ void Stat::AddExt(const char* tag, uid_t uid, gid_t gid, unsigned long nsample, const double& avgv, const double& minv, const double& maxv) { XrdSysMutexHelper lock(mMutex); StatExtUid[tag][uid].Insert(nsample, avgv, minv, maxv); StatExtGid[tag][gid].Insert(nsample, avgv, minv, maxv); } /*----------------------------------------------------------------------------*/ void Stat::AddExec(const char* tag, float exectime) { XrdSysMutexHelper lock(mMutex); StatExec[tag].push_back(exectime); CumulativeTimeExec[tag] += exectime; // we average over 100 entries if (StatExec[tag].size() > 100) { StatExec[tag].pop_front(); } } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used unsigned long long Stat::GetTotal(const char* tag) { google::sparse_hash_map::const_iterator it; unsigned long long val = 0; if (!StatsUid.count(tag)) { return 0; } for (it = StatsUid[tag].begin(); it != StatsUid[tag].end(); ++it) { val += it->second; } return val; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetCumulativeExecTime(const char* tag) { if (!CumulativeTimeExec.count(tag)) { return 0.0; } return CumulativeTimeExec[tag]; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalAvg3600(const char* tag) { google::sparse_hash_map::iterator it; double val = 0; if (!StatAvgUid.count(tag)) { return 0; } for (it = StatAvgUid[tag].begin(); it != StatAvgUid[tag].end(); ++it) { val += it->second.GetAvg3600(); } return val; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalNExt3600(const char* tag) { google::sparse_hash_map::iterator it; unsigned long n = 0; if (!StatExtUid.count(tag)) { return 0; } for (it = StatExtUid[tag].begin(); it != StatExtUid[tag].end(); ++it) { for (int i = 0; i < 3600; i++) { n += it->second.n3600[i]; } } return (double) n; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalAvgExt3600(const char* tag) { google::sparse_hash_map::iterator it; double val = 0; double totw = 0; if (!StatExtUid.count(tag)) { return 0; } for (it = StatExtUid[tag].begin(); it != StatExtUid[tag].end(); ++it) { double w = 0; for (int i = 0; i < 3600; i++) { w += it->second.n3600[i]; } totw += w; val += it->second.GetAvg3600() * w; } return val / totw; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalMinExt3600(const char* tag) { google::sparse_hash_map::iterator it; double minval = std::numeric_limits::max(); if (!StatExtUid.count(tag)) { return 0; } for (it = StatExtUid[tag].begin(); it != StatExtUid[tag].end(); ++it) { minval = std::min(minval, it->second.GetMin3600()); } return minval; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalMaxExt3600(const char* tag) { google::sparse_hash_map::iterator it; double maxval = std::numeric_limits::min(); if (!StatExtUid.count(tag)) { return 0; } for (it = StatExtUid[tag].begin(); it != StatExtUid[tag].end(); ++it) { maxval = std::max(maxval, it->second.GetMax3600()); } return maxval; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalAvg300(const char* tag) { google::sparse_hash_map::iterator it; double val = 0; if (!StatAvgUid.count(tag)) { return 0; } for (it = StatAvgUid[tag].begin(); it != StatAvgUid[tag].end(); ++it) { val += it->second.GetAvg300(); } return val; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalNExt300(const char* tag) { google::sparse_hash_map::iterator it; unsigned long n = 0; if (!StatExtUid.count(tag)) { return 0; } for (it = StatExtUid[tag].begin(); it != StatExtUid[tag].end(); ++it) { for (int i = 0; i < 300; i++) { n += it->second.n300[i]; } } return (double) n; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalAvgExt300(const char* tag) { google::sparse_hash_map::iterator it; double val = 0; double totw = 0; if (!StatExtUid.count(tag)) { return 0; } for (it = StatExtUid[tag].begin(); it != StatExtUid[tag].end(); ++it) { double w = 0; for (int i = 0; i < 300; i++) { w += it->second.n300[i]; } totw += w; val += it->second.GetAvg300() * w; } return val / totw; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalMinExt300(const char* tag) { google::sparse_hash_map::iterator it; double minval = std::numeric_limits::max(); if (!StatExtUid.count(tag)) { return 0; } for (it = StatExtUid[tag].begin(); it != StatExtUid[tag].end(); ++it) { minval = std::min(minval, it->second.GetMin300()); } return minval; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalMaxExt300(const char* tag) { google::sparse_hash_map::iterator it; double maxval = std::numeric_limits::min(); if (!StatExtUid.count(tag)) { return 0; } for (it = StatExtUid[tag].begin(); it != StatExtUid[tag].end(); ++it) { maxval = std::max(maxval, it->second.GetMax300()); } return maxval; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalAvg60(const char* tag) { google::sparse_hash_map::iterator it; double val = 0; if (!StatAvgUid.count(tag)) { return 0; } for (it = StatAvgUid[tag].begin(); it != StatAvgUid[tag].end(); ++it) { val += it->second.GetAvg60(); } return val; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalNExt60(const char* tag) { google::sparse_hash_map::iterator it; unsigned long n = 0; if (!StatExtUid.count(tag)) { return 0; } for (it = StatExtUid[tag].begin(); it != StatExtUid[tag].end(); ++it) { for (int i = 0; i < 60; i++) { n += it->second.n60[i]; } } return (double) n; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalAvgExt60(const char* tag) { google::sparse_hash_map::iterator it; double val = 0; double totw = 0; if (!StatExtUid.count(tag)) { return 0; } for (it = StatExtUid[tag].begin(); it != StatExtUid[tag].end(); ++it) { double w = 0; for (int i = 0; i < 60; i++) { w += it->second.n60[i]; } totw += w; val += it->second.GetAvg60() * w; } return val / totw; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalMinExt60(const char* tag) { google::sparse_hash_map::iterator it; double minval = std::numeric_limits::max(); if (!StatExtUid.count(tag)) { return 0; } for (it = StatExtUid[tag].begin(); it != StatExtUid[tag].end(); ++it) { minval = std::min(minval, it->second.GetMin60()); } return minval; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalMaxExt60(const char* tag) { google::sparse_hash_map::iterator it; double maxval = std::numeric_limits::min(); if (!StatExtUid.count(tag)) { return 0; } for (it = StatExtUid[tag].begin(); it != StatExtUid[tag].end(); ++it) { maxval = std::max(maxval, it->second.GetMax60()); } return maxval; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalAvg5(const char* tag) { google::sparse_hash_map::iterator it; double val = 0; if (!StatAvgUid.count(tag)) { return 0; } for (it = StatAvgUid[tag].begin(); it != StatAvgUid[tag].end(); ++it) { val += it->second.GetAvg5(); } return val; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalNExt5(const char* tag) { google::sparse_hash_map::iterator it; unsigned long n = 0; if (!StatExtUid.count(tag)) { return 0; } for (it = StatExtUid[tag].begin(); it != StatExtUid[tag].end(); ++it) { for (int i = 0; i < 5; i++) { n += it->second.n5[i]; } } return (double) n; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalAvgExt5(const char* tag) { google::sparse_hash_map::iterator it; double val = 0; double totw = 0; if (!StatExtUid.count(tag)) { return 0; } for (it = StatExtUid[tag].begin(); it != StatExtUid[tag].end(); ++it) { double w = 0; for (int i = 0; i < 5; i++) { w += it->second.n5[i]; } totw += w; val += it->second.GetAvg5() * w; } return val / totw; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalMinExt5(const char* tag) { google::sparse_hash_map::iterator it; double minval = std::numeric_limits::max(); if (!StatExtUid.count(tag)) { return 0; } for (it = StatExtUid[tag].begin(); it != StatExtUid[tag].end(); ++it) { minval = std::min(minval, it->second.GetMin5()); } return minval; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalMaxExt5(const char* tag) { google::sparse_hash_map::iterator it; double maxval = std::numeric_limits::min(); if (!StatExtUid.count(tag)) { return 0; } for (it = StatExtUid[tag].begin(); it != StatExtUid[tag].end(); ++it) { maxval = std::max(maxval, it->second.GetMax5()); } return maxval; } //------------------------------------------------------------------------------ // Calculate the average execution time for 'tag' // warning: you have to lock the mutex if directly used //------------------------------------------------------------------------------ double Stat::GetExec(const char* tag, double& deviation, double& percentile, double& max) { double avg = 0; deviation = 0; max = 0; percentile = 0; std::multiset m; if (StatExec.count(tag)) { std::deque::const_iterator it; for (it = StatExec[tag].begin(); it != StatExec[tag].end(); ++it) { m.insert(*it); } avg = eos::common::Statistics::avg(m); deviation = eos::common::Statistics::sig(m); percentile = eos::common::Statistics::nperc(m, 99); max = eos::common::Statistics::max(m); } return avg; } /*----------------------------------------------------------------------------*/ // warning: you have to lock the mutex if directly used double Stat::GetTotalExec(double& deviation) { // calculates average execution time for all commands google::sparse_hash_map >::const_iterator ittag; double sum = 0; double avg = 0; deviation = 0; int cnt = 0; for (ittag = StatExec.begin(); ittag != StatExec.end(); ittag++) { std::deque::const_iterator it; for (it = ittag->second.begin(); it != ittag->second.end(); it++) { cnt++; sum += *it; } } if (cnt) { avg = sum / cnt; } for (ittag = StatExec.begin(); ittag != StatExec.end(); ittag++) { std::deque::const_iterator it; for (it = ittag->second.begin(); it != ittag->second.end(); it++) { deviation += pow((*it - avg), 2); } } if (cnt) { deviation = sqrt(deviation / cnt); } return avg; } /*----------------------------------------------------------------------------*/ void Stat::Clear() { XrdSysMutexHelper lock(mMutex); for (auto ittag = StatsUid.begin(); ittag != StatsUid.end(); ittag++) { StatsUid[ittag->first].clear(); StatsUid[ittag->first].resize(1000); StatsGid[ittag->first].clear(); StatsGid[ittag->first].resize(1000); StatAvgUid[ittag->first].clear(); StatAvgUid[ittag->first].resize(1000); StatAvgGid[ittag->first].clear(); StatAvgGid[ittag->first].resize(1000); StatExec[ittag->first].clear(); StatExec[ittag->first].resize(1000); CumulativeTimeExec[ittag->first] = 0.0; } } /*----------------------------------------------------------------------------*/ void Stat::PrintOutTotal(XrdOucString& out, bool details, bool monitoring, bool numerical) { mMutex.Lock(); std::vector tags, tags_ext; std::vector::iterator it; google::sparse_hash_map < std::string, google::sparse_hash_map >::iterator tit; google::sparse_hash_map < std::string, google::sparse_hash_map >::iterator tit_ext; for (tit = StatsUid.begin(); tit != StatsUid.end(); ++tit) { tags.push_back(tit->first); } for (tit_ext = StatExtUid.begin(); tit_ext != StatExtUid.end(); ++tit_ext) { tags_ext.push_back(tit_ext->first); } std::sort(tags.begin(), tags.end()); std::sort(tags_ext.begin(), tags_ext.end()); char outline[1024]; double avg = 0; double sig = 0; avg = GetTotalExec(sig); if (!monitoring) { sprintf(outline, "%-8s %-32s %3.02f ± %3.02f\n", "ALL", "Execution Time", avg, sig); } else { sprintf(outline, "uid=all gid=all total.exec.avg=%.02f total.exec.sigma=%.02f\n", avg, sig); } out += outline; std::string na = !monitoring ? "-NA-" : "NA"; std::string format_cmd = !monitoring ? "-s" : "os"; std::string format_s = !monitoring ? "s" : "os"; std::string format_ss = !monitoring ? "-s" : "os"; std::string format_l = !monitoring ? "+l" : "ol"; std::string format_f = !monitoring ? "f" : "of"; std::string format_ff = !monitoring ? "±f" : "of"; // Specification for all users and groups TableFormatterBase table_all; if (!monitoring) { table_all.SetHeader({ std::make_tuple("who", 3, format_ss), std::make_tuple("command", 24, format_cmd), std::make_tuple("sum", 8, format_l), std::make_tuple("5s", 8, format_f), std::make_tuple("1min", 8, format_f), std::make_tuple("5min", 8, format_f), std::make_tuple("1h", 8, format_f), std::make_tuple("exec(ms)", 8, format_f), std::make_tuple("sigma(ms)", 8, format_ff), std::make_tuple("99p(ms)", 8, format_f), std::make_tuple("max(ms)", 8, format_f), std::make_tuple("cumul", 8, format_f) }); } else { table_all.SetHeader({ std::make_tuple("uid", 0, format_ss), std::make_tuple("gid", 0, format_s), std::make_tuple("cmd", 0, format_s), std::make_tuple("total", 0, format_l), std::make_tuple("5s", 0, format_f), std::make_tuple("60s", 0, format_f), std::make_tuple("300s", 0, format_f), std::make_tuple("3600s", 0, format_f), std::make_tuple("exec", 0, format_f), std::make_tuple("execsig", 0, format_ff), std::make_tuple("exec99", 8, format_f), std::make_tuple("execmax", 8, format_f), std::make_tuple("cumulexecms", 8, format_f) }); } for (it = tags.begin(); it != tags.end(); ++it) { const char* tag = it->c_str(); double avg = 0, sig = 0; double max = 0, perc = 0; double cumulativeExecTimeMs = 0; avg = GetExec(tag, sig, max, perc); cumulativeExecTimeMs = GetCumulativeExecTime(tag); TableData table_data; table_data.emplace_back(); table_data.back().push_back(TableCell("all", format_ss)); if (monitoring) { table_data.back().push_back(TableCell("all", format_s)); } table_data.back().push_back(TableCell(tag, format_cmd)); table_data.back().push_back(TableCell(GetTotal(tag), format_l)); table_data.back().push_back(TableCell(GetTotalAvg5(tag), format_f)); table_data.back().push_back(TableCell(GetTotalAvg60(tag), format_f)); table_data.back().push_back(TableCell(GetTotalAvg300(tag), format_f)); table_data.back().push_back(TableCell(GetTotalAvg3600(tag), format_f)); if (avg || monitoring) { table_data.back().push_back(TableCell(avg, format_f)); table_data.back().push_back(TableCell(sig, format_f)); table_data.back().push_back(TableCell(perc, format_f)); table_data.back().push_back(TableCell(max, format_f)); if (!monitoring) { //We want the output to be displayed in day/hours/min/seconds in the table output XrdOucString cumulativeExecTimeStr; common::StringConversion::GetReadableAgeString(cumulativeExecTimeStr, llround(cumulativeExecTimeMs) / 1000); table_data.back().push_back( TableCell(cumulativeExecTimeStr.c_str(), format_ss)); } else { table_data.back().push_back(TableCell(cumulativeExecTimeMs, format_f)); } } else { table_data.back().push_back(TableCell(na, format_s)); table_data.back().push_back(TableCell(na, format_s)); table_data.back().push_back(TableCell(na, format_s)); table_data.back().push_back(TableCell(na, format_s)); table_data.back().push_back(TableCell(na, format_s)); } table_all.AddRows(table_data); } if (details) { for (it = tags_ext.begin(); it != tags_ext.end(); ++it) { const char* tag = it->c_str(); TableData table_data_spl, table_data_min, table_data_avg, table_data_max; table_data_spl.emplace_back(); table_data_min.emplace_back(); table_data_avg.emplace_back(); table_data_max.emplace_back(); table_data_spl.back().push_back(TableCell("all", format_ss)); table_data_min.back().push_back(TableCell("all", format_ss)); table_data_avg.back().push_back(TableCell("all", format_ss)); table_data_max.back().push_back(TableCell("all", format_ss)); if (monitoring) { table_data_spl.back().push_back(TableCell("all", format_s)); table_data_min.back().push_back(TableCell("all", format_s)); table_data_avg.back().push_back(TableCell("all", format_s)); table_data_max.back().push_back(TableCell("all", format_s)); } std::string tag_spl = tag, tag_min = tag, tag_avg = tag, tag_max = tag; tag_spl += ":spl"; tag_min += ":min"; tag_avg += ":avg"; tag_max += ":max"; table_data_spl.back().push_back(TableCell(tag_spl, format_s)); table_data_min.back().push_back(TableCell(tag_min, format_s)); table_data_avg.back().push_back(TableCell(tag_avg, format_s)); table_data_max.back().push_back(TableCell(tag_max, format_s)); table_data_spl.back().push_back(TableCell("", "", "", true)); table_data_min.back().push_back(TableCell("", "", "", true)); table_data_avg.back().push_back(TableCell("", "", "", true)); table_data_max.back().push_back(TableCell("", "", "", true)); table_data_spl.back().push_back(TableCell(GetTotalNExt5(tag), format_f)); if (GetTotalNExt5(tag) < 1) { table_data_min.back().push_back(TableCell(na, format_s)); table_data_avg.back().push_back(TableCell(na, format_s)); table_data_max.back().push_back(TableCell(na, format_s)); } else { table_data_min.back().push_back(TableCell(GetTotalMinExt5(tag), format_f)); table_data_avg.back().push_back(TableCell(GetTotalAvgExt5(tag), format_f)); table_data_max.back().push_back(TableCell(GetTotalMaxExt5(tag), format_f)); } table_data_spl.back().push_back(TableCell(GetTotalNExt60(tag), format_f)); if (GetTotalNExt60(tag) < 1) { table_data_min.back().push_back(TableCell(na, format_s)); table_data_avg.back().push_back(TableCell(na, format_s)); table_data_max.back().push_back(TableCell(na, format_s)); } else { table_data_min.back().push_back(TableCell(GetTotalMinExt60(tag), format_f)); table_data_avg.back().push_back(TableCell(GetTotalAvgExt60(tag), format_f)); table_data_max.back().push_back(TableCell(GetTotalMaxExt60(tag), format_f)); } table_data_spl.back().push_back(TableCell(GetTotalNExt300(tag), format_f)); if (GetTotalNExt300(tag) < 1) { table_data_min.back().push_back(TableCell(na, format_s)); table_data_avg.back().push_back(TableCell(na, format_s)); table_data_max.back().push_back(TableCell(na, format_s)); } else { table_data_min.back().push_back(TableCell(GetTotalMinExt300(tag), format_f)); table_data_avg.back().push_back(TableCell(GetTotalAvgExt300(tag), format_f)); table_data_max.back().push_back(TableCell(GetTotalMaxExt300(tag), format_f)); } table_data_spl.back().push_back(TableCell(GetTotalNExt3600(tag), format_f)); if (GetTotalNExt3600(tag) < 1) { table_data_min.back().push_back(TableCell(na, format_s)); table_data_avg.back().push_back(TableCell(na, format_s)); table_data_max.back().push_back(TableCell(na, format_s)); } else { table_data_min.back().push_back(TableCell(GetTotalMinExt3600(tag), format_f)); table_data_avg.back().push_back(TableCell(GetTotalAvgExt3600(tag), format_f)); table_data_max.back().push_back(TableCell(GetTotalMaxExt3600(tag), format_f)); } table_all.AddRows(table_data_spl); table_all.AddRows(table_data_min); table_all.AddRows(table_data_avg); table_all.AddRows(table_data_max); } } out += table_all.GenerateTable(HEADER).c_str(); if (details) { // Collect uids and gids inside the lock and the do the translation outside // the lock std::set set_uids; std::set set_gids; for (auto tuit = StatAvgUid.begin(); tuit != StatAvgUid.end(); tuit++) { for (auto it = tuit->second.begin(); it != tuit->second.end(); ++it) { set_uids.insert(it->first); } } for (auto tuit_ext = StatExtUid.begin(); tuit_ext != StatExtUid.end(); tuit_ext++) { for (auto it = tuit_ext->second.begin(); it != tuit_ext->second.end(); ++it) { set_uids.insert(it->first); } } for (auto tgit = StatAvgGid.begin(); tgit != StatAvgGid.end(); tgit++) { for (auto it = tgit->second.begin(); it != tgit->second.end(); ++it) { set_gids.insert(it->first); } } for (auto tgit_ext = StatExtGid.begin(); tgit_ext != StatExtGid.end(); tgit_ext++) { for (auto it = tgit_ext->second.begin(); it != tgit_ext->second.end(); ++it) { set_gids.insert(it->first); } } mMutex.UnLock(); std::map umap; std::map gmap; for (const auto numeric_uid : set_uids) { int terrc = 0; std::string username = eos::common::Mapping::UidToUserName(numeric_uid, terrc); umap[numeric_uid] = username; } for (const auto numeric_gid : set_gids) { int terrc = 0; std::string groupname = eos::common::Mapping::GidToGroupName(numeric_gid, terrc); gmap[numeric_gid] = groupname; } mMutex.Lock(); //! User statistic TableFormatterBase table_user; if (!monitoring) { table_user.SetHeader({ std::make_tuple("user", 5, format_ss), std::make_tuple("command", 24, format_cmd), std::make_tuple("sum", 8, format_l), std::make_tuple("5s", 8, format_f), std::make_tuple("1min", 8, format_f), std::make_tuple("5min", 8, format_f), std::make_tuple("1h", 8, format_f) }); } else { table_user.SetHeader({ std::make_tuple("uid", 0, format_ss), std::make_tuple("cmd", 0, format_s), std::make_tuple("total", 0, format_l), std::make_tuple("5s", 0, format_f), std::make_tuple("60s", 0, format_f), std::make_tuple("300s", 0, format_f), std::make_tuple("3600s", 0, format_f) }); } std::vector> table_data; std::vector> table_data_ext; for (auto tuit = StatAvgUid.begin(); tuit != StatAvgUid.end(); tuit++) { for (auto it = tuit->second.begin(); it != tuit->second.end(); ++it) { std::string username; if (numerical) { username = std::to_string(it->first); } else { username = umap.count(it->first) ? umap[it->first] : eos::common::StringConversion::GetSizeString(username, (unsigned long long)it->first); } table_data.push_back(std::make_tuple(0, username, tuit->first.c_str(), StatsUid[tuit->first.c_str()][it->first], it->second.GetAvg5(), it->second.GetAvg60(), it->second.GetAvg300(), it->second.GetAvg3600())); } } for (auto tuit_ext = StatExtUid.begin(); tuit_ext != StatExtUid.end(); tuit_ext++) { for (auto it = tuit_ext->second.begin(); it != tuit_ext->second.end(); ++it) { std::string username; if (numerical) { username = std::to_string(it->first); } else { username = umap.count(it->first) ? umap[it->first] : eos::common::StringConversion::GetSizeString(username, (unsigned long long)it->first); } table_data_ext.push_back(std::make_tuple( 0, username, tuit_ext->first.c_str(), it->second.GetN5(), it->second.GetAvg5(), it->second.GetMin5(), it->second.GetMax5(), it->second.GetN60(), it->second.GetAvg60(), it->second.GetMin60(), it->second.GetMax60(), it->second.GetN300(), it->second.GetAvg300(), it->second.GetMin300(), it->second.GetMax300(), it->second.GetN3600(), it->second.GetAvg3600(), it->second.GetMin3600(), it->second.GetMax3600())); } } //! Group statistic TableFormatterBase table_group; if (!monitoring) { table_group.SetHeader({ std::make_tuple("group", 5, format_ss), std::make_tuple("command", 24, format_cmd), std::make_tuple("sum", 8, format_l), std::make_tuple("5s", 8, format_f), std::make_tuple("1min", 8, format_f), std::make_tuple("5min", 8, format_f), std::make_tuple("1h", 8, format_f) }); } else { table_group.SetHeader({ std::make_tuple("gid", 0, format_ss), std::make_tuple("cmd", 0, format_s), std::make_tuple("total", 0, format_l), std::make_tuple("5s", 0, format_f), std::make_tuple("60s", 0, format_f), std::make_tuple("300s", 0, format_f), std::make_tuple("3600s", 0, format_f) }); } for (auto tgit = StatAvgGid.begin(); tgit != StatAvgGid.end(); tgit++) { for (auto it = tgit->second.begin(); it != tgit->second.end(); ++it) { std::string groupname; if (numerical) { groupname = std::to_string(it->first); } else { groupname = gmap.count(it->first) ? gmap[it->first] : eos::common::StringConversion::GetSizeString(groupname, (unsigned long long)it->first); } table_data.push_back(std::make_tuple(1, groupname, tgit->first.c_str(), StatsGid[tgit->first.c_str()][it->first], it->second.GetAvg5(), it->second.GetAvg60(), it->second.GetAvg300(), it->second.GetAvg3600())); } } for (auto tgit_ext = StatExtGid.begin(); tgit_ext != StatExtGid.end(); tgit_ext++) { for (auto it = tgit_ext->second.begin(); it != tgit_ext->second.end(); ++it) { std::string groupname; if (numerical) { groupname = std::to_string(it->first); } else { groupname = gmap.count(it->first) ? gmap[it->first] : eos::common::StringConversion::GetSizeString(groupname, (unsigned long long)it->first); } table_data_ext.push_back(std::make_tuple( 1, groupname, tgit_ext->first.c_str(), it->second.GetN5(), it->second.GetAvg5(), it->second.GetMin5(), it->second.GetMax5(), it->second.GetN60(), it->second.GetAvg60(), it->second.GetMin60(), it->second.GetMax60(), it->second.GetN300(), it->second.GetAvg300(), it->second.GetMin300(), it->second.GetMax300(), it->second.GetN3600(), it->second.GetAvg3600(), it->second.GetMin3600(), it->second.GetMax3600())); } } // Data sorting std::sort(table_data.begin(), table_data.end()); std::sort(table_data_ext.begin(), table_data_ext.end()); // Output user and group statistic for (int i = 0; i <= 1; i++) { for (auto it : table_data) { if (std::get<0>(it) == i) { TableData table_data_sorted; table_data_sorted.emplace_back(); table_data_sorted.back().push_back(TableCell(std::get<1>(it), format_ss)); table_data_sorted.back().push_back(TableCell(std::get<2>(it), format_s)); table_data_sorted.back().push_back(TableCell(std::get<3>(it), format_l)); table_data_sorted.back().push_back(TableCell(std::get<4>(it), format_f)); table_data_sorted.back().push_back(TableCell(std::get<5>(it), format_f)); table_data_sorted.back().push_back(TableCell(std::get<6>(it), format_f)); table_data_sorted.back().push_back(TableCell(std::get<7>(it), format_f)); if (i == 0) { table_user.AddRows(table_data_sorted); } else if (i == 1) { table_group.AddRows(table_data_sorted); } } } for (auto it : table_data_ext) { if (std::get<0>(it) == i) { TableData table_data_spl, table_data_min, table_data_avg, table_data_max; table_data_spl.emplace_back(); table_data_min.emplace_back(); table_data_avg.emplace_back(); table_data_max.emplace_back(); table_data_spl.back().push_back(TableCell(std::get<1>(it), format_ss)); table_data_min.back().push_back(TableCell(std::get<1>(it), format_ss)); table_data_avg.back().push_back(TableCell(std::get<1>(it), format_ss)); table_data_max.back().push_back(TableCell(std::get<1>(it), format_ss)); std::string tag = std::get<2>(it); std::string tag_spl = tag, tag_min = tag, tag_avg = tag, tag_max = tag; tag_spl += ":spl"; tag_min += ":min"; tag_avg += ":avg"; tag_max += ":max"; table_data_spl.back().push_back(TableCell(tag_spl, format_s)); table_data_min.back().push_back(TableCell(tag_min, format_s)); table_data_avg.back().push_back(TableCell(tag_avg, format_s)); table_data_max.back().push_back(TableCell(tag_max, format_s)); table_data_spl.back().push_back(TableCell("", "", "", true)); table_data_min.back().push_back(TableCell("", "", "", true)); table_data_avg.back().push_back(TableCell("", "", "", true)); table_data_max.back().push_back(TableCell("", "", "", true)); table_data_spl.back().push_back(TableCell(std::get<3>(it), format_f)); if (std::get<3>(it) < 1) { table_data_min.back().push_back(TableCell(na, format_s)); table_data_avg.back().push_back(TableCell(na, format_s)); table_data_max.back().push_back(TableCell(na, format_s)); } else { table_data_min.back().push_back(TableCell(std::get<4>(it), format_f)); table_data_avg.back().push_back(TableCell(std::get<5>(it), format_f)); table_data_max.back().push_back(TableCell(std::get<6>(it), format_f)); } table_data_spl.back().push_back(TableCell(std::get<7>(it), format_f)); if (std::get<7>(it) < 1) { table_data_min.back().push_back(TableCell(na, format_s)); table_data_avg.back().push_back(TableCell(na, format_s)); table_data_max.back().push_back(TableCell(na, format_s)); } else { table_data_min.back().push_back(TableCell(std::get<8>(it), format_f)); table_data_avg.back().push_back(TableCell(std::get<9>(it), format_f)); table_data_max.back().push_back(TableCell(std::get<10>(it), format_f)); } table_data_spl.back().push_back(TableCell(std::get<11>(it), format_f)); if (std::get<11>(it) < 1) { table_data_min.back().push_back(TableCell(na, format_s)); table_data_avg.back().push_back(TableCell(na, format_s)); table_data_max.back().push_back(TableCell(na, format_s)); } else { table_data_min.back().push_back(TableCell(std::get<12>(it), format_f)); table_data_avg.back().push_back(TableCell(std::get<13>(it), format_f)); table_data_max.back().push_back(TableCell(std::get<14>(it), format_f)); } table_data_spl.back().push_back(TableCell(std::get<15>(it), format_f)); if (std::get<15>(it) < 1) { table_data_min.back().push_back(TableCell(na, format_s)); table_data_avg.back().push_back(TableCell(na, format_s)); table_data_max.back().push_back(TableCell(na, format_s)); } else { table_data_min.back().push_back(TableCell(std::get<16>(it), format_f)); table_data_avg.back().push_back(TableCell(std::get<17>(it), format_f)); table_data_max.back().push_back(TableCell(std::get<18>(it), format_f)); } if (i == 0) { table_user.AddRows(table_data_spl); table_user.AddRows(table_data_min); table_user.AddRows(table_data_avg); table_user.AddRows(table_data_max); } else if (i == 1) { table_group.AddRows(table_data_spl); table_group.AddRows(table_data_min); table_group.AddRows(table_data_avg); table_group.AddRows(table_data_max); } } } } out += table_user.GenerateTable(HEADER).c_str(); out += table_group.GenerateTable(HEADER).c_str(); } mMutex.UnLock(); } /*----------------------------------------------------------------------------*/ void Stat::Circulate(ThreadAssistant& assistant) noexcept { unsigned long long l1 = 0; unsigned long long l2 = 0; unsigned long long l3 = 0; unsigned long long l1tmp, l2tmp, l3tmp; #ifdef EOS_INSTRUMENTED_RWMUTEX unsigned long long qu1 = 0; unsigned long long qu2 = 0; unsigned long long ns1 = 0; unsigned long long ns2 = 0; unsigned long long view1 = 0; unsigned long long view2 = 0; eos::common::RWMutex::TimingStats qu12stmp, ns12stmp, view12stmp; unsigned long long ns1tmp = 0ull, ns2tmp = 0ull, view1tmp = 0ull, view2tmp = 0ull, qu1tmp = 0ull, qu2tmp = 0ull; #endif auto chrononow = std::chrono::system_clock::now(); auto chronolast = chrononow; // Empty the circular buffer and extract some Mq statistic values while (!assistant.terminationRequested()) { assistant.wait_for(std::chrono::milliseconds(512)); chrononow = std::chrono::system_clock::now(); // -------------------------------------------- // mq statistics extraction l1tmp = XrdMqSharedHash::sSetCounter.load(); l2tmp = XrdMqSharedHash::sSetNLCounter.load(); l3tmp = XrdMqSharedHash::sGetCounter.load(); #ifdef EOS_INSTRUMENTED_RWMUTEX eos::common::RWMutex* fs_mtx = &FsView::gFsView.ViewMutex; eos::common::RWMutex* quota_mtx = &Quota::pMapMutex; eos::common::RWMutex* ns_mtx = &gOFS->eosViewRWMutex; // fsview statistics extraction view1tmp = fs_mtx->GetReadLockCounter(); view2tmp = fs_mtx->GetWriteLockCounter(); fs_mtx->GetTimingStatistics(view12stmp); fs_mtx->ResetTimingStatistics(); // namespace lock statistics extraction ns1tmp = ns_mtx->GetReadLockCounter(); ns2tmp = ns_mtx->GetWriteLockCounter(); ns_mtx->GetTimingStatistics(ns12stmp); ns_mtx->ResetTimingStatistics(); // quota lock statistics extraction qu1tmp = quota_mtx->GetReadLockCounter(); qu2tmp = quota_mtx->GetWriteLockCounter(); quota_mtx->GetTimingStatistics(qu12stmp); quota_mtx->ResetTimingStatistics(); #endif Add("HashSet", 0, 0, l1tmp - l1); Add("HashSetNoLock", 0, 0, l2tmp - l2); Add("HashGet", 0, 0, l3tmp - l3); #ifdef EOS_INSTRUMENTED_RWMUTEX Add("ViewLockR", 0, 0, view1tmp - view1); Add("ViewLockW", 0, 0, view2tmp - view2); Add("NsLockR", 0, 0, ns1tmp - ns1); Add("NsLockW", 0, 0, ns2tmp - ns2); Add("QuotaLockR", 0, 0, qu1tmp - qu1); Add("QuotaLockW", 0, 0, qu2tmp - qu2); AddExt("ViewLockRWait", 0, 0, (unsigned long) view12stmp.readLockCounterSample, view12stmp.averagewaitread, view12stmp.minwaitread, view12stmp.maxwaitread); AddExt("ViewLockWWait", 0, 0, (unsigned long) view12stmp.writeLockCounterSample, view12stmp.averagewaitwrite, view12stmp.minwaitwrite, view12stmp.maxwaitwrite); AddExt("NsLockRWait", 0, 0, (unsigned long) ns12stmp.readLockCounterSample, ns12stmp.averagewaitread, ns12stmp.minwaitread, ns12stmp.maxwaitread); AddExt("NsLockWWait", 0, 0, (unsigned long) ns12stmp.writeLockCounterSample, ns12stmp.averagewaitwrite, ns12stmp.minwaitwrite, ns12stmp.maxwaitwrite); AddExt("QuotaLockRWait", 0, 0, (unsigned long) qu12stmp.readLockCounterSample, qu12stmp.averagewaitread, ns12stmp.minwaitread, ns12stmp.maxwaitread); AddExt("QuotaLockWWait", 0, 0, (unsigned long) qu12stmp.writeLockCounterSample, qu12stmp.averagewaitwrite, ns12stmp.minwaitwrite, ns12stmp.maxwaitwrite); view1 = view1tmp; view2 = view2tmp; ns1 = ns1tmp; ns2 = ns2tmp; qu1 = qu1tmp; qu2 = qu2tmp; std::chrono::milliseconds elapsed = std::chrono::duration_cast (chrononow-chronolast); Add("NsUsedR", 0, 0, ns_mtx->GetReadLockTime() / elapsed.count()); Add("NsUsedW", 0, 0, ns_mtx->GetWriteLockTime() / elapsed.count()); Add("NsLeadR", 0, 0, ns_mtx->GetReadLockLeadTime() / elapsed.count()); Add("NsLeadW", 0, 0, ns_mtx->GetWriteLockLeadTime() / elapsed.count()); #endif l1 = l1tmp; l2 = l2tmp; l3 = l3tmp; XrdSysMutexHelper lock(mMutex); time_t now = time(NULL); // loop over tags for (auto tit = StatAvgUid.begin(); tit != StatAvgUid.end(); ++tit) { // loop over vids for (auto it = tit->second.begin(); it != tit->second.end(); ++it) { it->second.StampZero(now); } } for (auto tit = StatAvgGid.begin(); tit != StatAvgGid.end(); ++tit) { // loop over vids for (auto it = tit->second.begin(); it != tit->second.end(); ++it) { it->second.StampZero(now); } } for (auto tit_ext = StatExtGid.begin(); tit_ext != StatExtGid.end(); ++tit_ext) { // loop over vids for (auto it = tit_ext->second.begin(); it != tit_ext->second.end(); ++it) { it->second.StampZero(now); } } for (auto tit_ext = StatExtGid.begin(); tit_ext != StatExtGid.end(); ++tit_ext) { // loop over vids for (auto it = tit_ext->second.begin(); it != tit_ext->second.end(); ++it) { it->second.StampZero(now); } } chronolast = chrononow; } } EOSMGMNAMESPACE_END