stats.cpp 6.03 KiB
Newer Older
Ramon Nou's avatar
Ramon Nou committed
/*
  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
*/


Ramon Nou's avatar
Ramon Nou committed
#include <common/statistics/stats.hpp>
Ramon Nou's avatar
Ramon Nou committed

using namespace std;

Ramon Nou's avatar
Ramon Nou committed
namespace gkfs::utils {
Ramon Nou's avatar
Ramon Nou committed

Ramon Nou's avatar
Ramon Nou committed
Stats::Stats(bool output_thread) {
Ramon Nou's avatar
Ramon Nou committed

Ramon Nou's avatar
Ramon Nou committed
    // Init clocks
    start = std::chrono::steady_clock::now();
    last_cached = std::chrono::steady_clock::now();
    // Init cached (4 mean values)
Ramon Nou's avatar
Ramon Nou committed

Ramon Nou's avatar
Ramon Nou committed
    for(auto e : all_IOPS_OP)
        for(int i = 0; i < 4; i++) CACHED_IOPS[e].push_back(0.0);
Ramon Nou's avatar
Ramon Nou committed

Ramon Nou's avatar
Ramon Nou committed
    for(auto e : all_SIZE_OP)
        for(int i = 0; i < 4; i++) CACHED_SIZE[e].push_back(0.0);
Ramon Nou's avatar
Ramon Nou committed


Ramon Nou's avatar
Ramon Nou committed
    // To simplify the control we add an element into the different maps
    // Statistaclly will be negligible... and we get a faster flow
Ramon Nou's avatar
Ramon Nou committed

Ramon Nou's avatar
Ramon Nou committed
    for(auto e : all_IOPS_OP) {
        IOPS[e] = 0;
        TIME_IOPS[e].push_back(std::chrono::steady_clock::now());
Ramon Nou's avatar
Ramon Nou committed
    }

Ramon Nou's avatar
Ramon Nou committed
    for(auto e : all_SIZE_OP) {
        SIZE[e] = 0;
        TIME_SIZE[e].push_back(pair(std::chrono::steady_clock::now(), 0.0));
    }
Ramon Nou's avatar
Ramon Nou committed

Ramon Nou's avatar
Ramon Nou committed
    output_thread_ = output_thread;
Ramon Nou's avatar
Ramon Nou committed

Ramon Nou's avatar
Ramon Nou committed
    if (output_thread_) {
        t_output = std::thread([this] { output(std::chrono::duration(10s)); });
Ramon Nou's avatar
Ramon Nou committed
    }
Ramon Nou's avatar
Ramon Nou committed
}
Ramon Nou's avatar
Ramon Nou committed

Ramon Nou's avatar
Ramon Nou committed
Stats::~Stats() {
    // We do not need a mutex for that
    if (output_thread_) {
        running = false;
        t_output.join();
Ramon Nou's avatar
Ramon Nou committed
    }
Ramon Nou's avatar
Ramon Nou committed
}
Ramon Nou's avatar
Ramon Nou committed

Ramon Nou's avatar
Ramon Nou committed
void
Stats::add_value_iops(enum IOPS_OP iop) {
    IOPS[iop]++;
    auto now = std::chrono::steady_clock::now();
Ramon Nou's avatar
Ramon Nou committed


Ramon Nou's avatar
Ramon Nou committed
    if((now - TIME_IOPS[iop].front()) > std::chrono::duration(10s)) {
        TIME_IOPS[iop].pop_front();
    } else if(TIME_IOPS[iop].size() >= MAX_STATS)
        TIME_IOPS[iop].pop_front();

    TIME_IOPS[iop].push_back(std::chrono::steady_clock::now());
}

void
Stats::add_value_size(enum SIZE_OP iop, unsigned long long value) {
    auto now = std::chrono::steady_clock::now();
    SIZE[iop] += value;
    if((now - TIME_SIZE[iop].front().first) > std::chrono::duration(10s)) {
        TIME_SIZE[iop].pop_front();
    } else if(TIME_SIZE[iop].size() >= MAX_STATS)
        TIME_SIZE[iop].pop_front();

    TIME_SIZE[iop].push_back(pair(std::chrono::steady_clock::now(), value));

    if(iop == SIZE_OP::READ_SIZE)
        IOPS[IOPS_OP::IOPS_READ]++;
    else if(iop == SIZE_OP::WRITE_SIZE)
        IOPS[IOPS_OP::IOPS_WRITE]++;
}

/**
 * @brief Get the total mean value of the asked stat
 * This can be provided inmediately without cost
 * @return mean value
 */
double
Stats::get_mean(enum SIZE_OP sop) {
    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
Stats::get_mean(enum IOPS_OP iop) {
    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;
}
Ramon Nou's avatar
Ramon Nou committed


/**
 * @brief Get all the means (total, 1,5 and 10 minutes) for a SIZE_OP
 * Returns precalculated values if we just calculated them 1 minute ago
 * // TODO: cache
 * @return std::vector< double > with 4 means
 */
Ramon Nou's avatar
Ramon Nou committed
std::vector<double>
Stats::get_four_means(enum SIZE_OP sop) {
    std::vector<double> results = {0, 0, 0, 0};
    auto now = std::chrono::steady_clock::now();
    for(auto e : TIME_SIZE[sop]) {
        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;
    }
Ramon Nou's avatar
Ramon Nou committed

Ramon Nou's avatar
Ramon Nou committed
    results[0] = get_mean(sop);
    results[3] /= 10 * 60;
    results[2] /= 5 * 60;
    results[1] /= 60;

    return results;
}


std::vector<double>
Stats::get_four_means(enum IOPS_OP iop) {
    std::vector<double> results = {0, 0, 0, 0};
    auto now = std::chrono::steady_clock::now();
    for(auto e : TIME_IOPS[iop]) {
        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]++;
Ramon Nou's avatar
Ramon Nou committed
    }

Ramon Nou's avatar
Ramon Nou committed
    results[0] = get_mean(iop);
    results[3] /= 10 * 60;
    results[2] /= 5 * 60;
    results[1] /= 60;
Ramon Nou's avatar
Ramon Nou committed

Ramon Nou's avatar
Ramon Nou committed
    return results;
}
Ramon Nou's avatar
Ramon Nou committed

Ramon Nou's avatar
Ramon Nou committed
void
Stats::dump() {
    for(auto e : all_IOPS_OP) {
        auto tmp = get_four_means(e);
Ramon Nou's avatar
Ramon Nou committed

Ramon Nou's avatar
Ramon Nou committed
        std::cout << "Stats " << IOPS_OP_S[static_cast<int>(e)] << " ";
        for(auto mean : tmp) {
            std::cout << mean << " - ";
        }
        std::cout << std::endl;
    }
    for(auto e : all_SIZE_OP) {
        auto tmp = get_four_means(e);
Ramon Nou's avatar
Ramon Nou committed

Ramon Nou's avatar
Ramon Nou committed
        std::cout << "Stats " << SIZE_OP_S[static_cast<int>(e)] << " ";
        for(auto mean : tmp) {
            std::cout << mean << " - ";
        }
        std::cout << std::endl;
Ramon Nou's avatar
Ramon Nou committed
    }
Ramon Nou's avatar
Ramon Nou committed
}
void
Stats::output(std::chrono::seconds d) {
Ramon Nou's avatar
Ramon Nou committed

Ramon Nou's avatar
Ramon Nou committed
    while(running) {
        dump();

        std::this_thread::sleep_for(d);
    }
}
Ramon Nou's avatar
Ramon Nou committed

Ramon Nou's avatar
Ramon Nou committed
} // namespace gkfs::utils