Newer
Older
/*
Copyright 2018-2022, Barcelona Supercomputing Center (BSC), Spain
Copyright 2015-2022, Johannes Gutenberg Universitaet Mainz, Germany
This software was partially supported by the
EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).
This software was partially supported by the
ADA-FS project under the SPPEXA project funded by the DFG.
This file is part of GekkoFS.
GekkoFS 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.
GekkoFS 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 GekkoFS. If not, see <https://www.gnu.org/licenses/>.
SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifdef GKFS_ENABLE_PROMETHEUS
static std::string
GetHostName() {
char hostname[1024];
if(::gethostname(hostname, sizeof(hostname))) {
return {};
}
return hostname;
}
#endif
Stats::setup_Prometheus(const std::string& gateway_ip,
const std::string& gateway_port) {
// Prometheus Push model. Gateway
#ifdef GKFS_ENABLE_PROMETHEUS
const auto labels = Gateway::GetInstanceLabel(GetHostName());
gateway = std::make_shared<Gateway>(gateway_ip, gateway_port, "GekkoFS",
labels);
.Name("IOPS")
.Help("Number of IOPS")
.Register(*registry);
for(auto e : all_IopsOp) {
iops_Prometheus[e] = &family_counter->Add(
{{"operation", IopsOp_s[static_cast<int>(e)]}});
.Name("SIZE")
.Help("Size of OPs")
.Register(*registry);
for(auto e : all_SizeOp) {
size_Prometheus[e] = &family_summary->Add(
{{"operation", SizeOp_s[static_cast<int>(e)]}},
Stats::Stats(bool enable_chunkstats, bool enable_prometheus,
const std::string& stats_file,
const std::string& prometheus_gateway)
: enable_prometheus_(enable_prometheus),
enable_chunkstats_(enable_chunkstats) {
// Init clocks
start = std::chrono::steady_clock::now();
// To simplify the control we add an element into the different maps
// Statistaclly will be negligible... and we get a faster flow
TimeSize[e].push_back(pair(std::chrono::steady_clock::now(), 0.0));
auto pos_separator = prometheus_gateway.find(":");
setup_Prometheus(prometheus_gateway.substr(0, pos_separator),
prometheus_gateway.substr(pos_separator + 1));
if(!stats_file.empty() || enable_prometheus_) {
output_thread_ = true;
t_output = std::thread([this, stats_file] {
output(std::chrono::duration(10s), stats_file);
});
if(output_thread_) {
Stats::add_read(const std::string& path, unsigned long long chunk) {
chunkRead[pair(path, chunk)]++;
}
void
Stats::add_write(const std::string& path, unsigned long long chunk) {
chunkWrite[pair(path, chunk)]++;
}
void
Stats::output_map(std::ofstream& output) {
// Ordering
map<unsigned int, std::set<pair<std::string, unsigned long long>>>
map<unsigned int, std::set<pair<std::string, unsigned long long>>>
}
}
[](std::string caption,
map<unsigned int,
std::ofstream& output) {
output << caption << std::endl;
output << k.first << " -- ";
for(auto v : k.second) {
output << v.first << " // " << v.second << endl;
}
}
};
chunkMap("READ CHUNK MAP", orderRead, output);
chunkMap("WRITE CHUNK MAP", orderWrite, output);
}
const std::lock_guard<std::mutex> lock(time_iops_mutex);
if((now - TimeIops[iop].front()) > std::chrono::duration(10s)) {
TimeIops[iop].pop_front();
} else if(TimeIops[iop].size() >= gkfs::config::stats::max_stats)
TimeIops[iop].pop_front();
if(enable_prometheus_) {
iops_Prometheus[iop]->Increment();
}
Stats::add_value_size(enum SizeOp iop, unsigned long long value) {
auto now = std::chrono::steady_clock::now();
SIZE[iop] += value;
const std::lock_guard<std::mutex> lock(size_iops_mutex);
if((now - TimeSize[iop].front().first) > std::chrono::duration(10s)) {
TimeSize[iop].pop_front();
} else if(TimeSize[iop].size() >= gkfs::config::stats::max_stats)
TimeSize[iop].pop_front();
TimeSize[iop].push_back(pair(std::chrono::steady_clock::now(), value));
if(enable_prometheus_) {
size_Prometheus[iop]->Observe(value);
}
if(iop == SizeOp::read_size)
add_value_iops(IopsOp::iops_read);
else if(iop == SizeOp::write_size)
add_value_iops(IopsOp::iops_write);
}
/**
* @brief Get the total mean value of the asked stat
* This can be provided inmediately without cost
* @return mean value
*/
double
auto now = std::chrono::steady_clock::now();
auto duration =
std::chrono::duration_cast<std::chrono::seconds>(now - start);
double value = (double) SIZE[sop] / (double) duration.count();
return value;
}
double
auto now = std::chrono::steady_clock::now();
auto duration =
std::chrono::duration_cast<std::chrono::seconds>(now - start);
double value = (double) IOPS[iop] / (double) duration.count();
return value;
}
std::vector<double> results = {0, 0, 0, 0};
auto now = std::chrono::steady_clock::now();
const std::lock_guard<std::mutex> lock(size_iops_mutex);
auto duration =
std::chrono::duration_cast<std::chrono::minutes>(now - e.first)
.count();
if(duration > 10)
break;
results[3] += e.second;
if(duration > 5)
continue;
results[2] += e.second;
if(duration > 1)
continue;
results[1] += e.second;
}
// Mean in MB/s
results[0] = get_mean(sop) / (1024.0 * 1024.0);
results[3] /= 10 * 60 * (1024.0 * 1024.0);
results[2] /= 5 * 60 * (1024.0 * 1024.0);
results[1] /= 60 * (1024.0 * 1024.0);
std::vector<double> results = {0, 0, 0, 0};
auto now = std::chrono::steady_clock::now();
const std::lock_guard<std::mutex> lock(time_iops_mutex);
auto duration =
std::chrono::duration_cast<std::chrono::minutes>(now - e)
.count();
if(duration > 10)
break;
results[3]++;
if(duration > 5)
continue;
results[2]++;
if(duration > 1)
continue;
results[1]++;
results[0] = get_mean(iop);
results[3] /= 10 * 60;
results[2] /= 5 * 60;
results[1] /= 60;
Stats::dump(std::ofstream& of) {
<< " IOPS/s (avg, 1 min, 5 min, 10 min) \t\t";
of << std::setprecision(4) << std::setw(9) << mean << " - ";
of << std::endl;
<< " MB/s (avg, 1 min, 5 min, 10 min) \t\t";
of << std::setprecision(4) << std::setw(9) << mean << " - ";
of << std::endl;
of << std::endl;
Stats::output(std::chrono::seconds d, std::string file_output) {
int times = 0;
std::optional<std::ofstream> of;
if(!file_output.empty())
of = std::ofstream(file_output, std::ios_base::openmode::_S_trunc);
std::chrono::seconds a = 0s;
times++;
if(enable_chunkstats_ && of) {
while(running && a < d) {
a += 1s;
std::this_thread::sleep_for(1s);
}