/* 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 . SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef GKFS_COMMON_STATS_HPP #define GKFS_COMMON_STATS_HPP #include #include #include #include #include #include #include #include #include #include /** * Provides storage capabilities to provide stats about GekkoFS * The information is per server. * We do not provide accurate stats for 1-5-10 minute stats * */ namespace gkfs::utils { /* Number of operations (Create, write/ read, remove, mkdir...) Size of database (metadata keys, should be not needed, any) Size of data (+write - delete) Server Bandwidth (write / read operations) mean, (lifetime of the server) 1 minute mean 5 minute mean 10 minute mean To provide the stats that we need, we need to store the info and the timestamp to calculate it A vector should work, with a maximum of elements, The stats will only be calculated when requested a cached value will be send (with a deadline) */ class Stats { public: enum class IOPS_OP { IOPS_CREATE, IOPS_WRITE, IOPS_READ, IOPS_MKDIR, IOPS_RMDIR, IOPS_REMOVE, }; enum class SIZE_OP { METADATA_SIZE, WRITE_SIZE, READ_SIZE, DATA_SIZE }; private: constexpr static const std::initializer_list all_IOPS_OP = { IOPS_OP::IOPS_CREATE, IOPS_OP::IOPS_WRITE, IOPS_OP::IOPS_READ, IOPS_OP::IOPS_MKDIR, IOPS_OP::IOPS_RMDIR, IOPS_OP::IOPS_REMOVE}; constexpr static const std::initializer_list all_SIZE_OP = { SIZE_OP::METADATA_SIZE, SIZE_OP::DATA_SIZE, SIZE_OP::WRITE_SIZE, SIZE_OP::READ_SIZE}; const std::vector IOPS_OP_S = {"IOPS_CREATE", "IOPS_WRITE", "IOPS_READ", "IOPS_MKDIR", "IOPS_RMDIR", "IOPS_REMOVE"}; const std::vector SIZE_OP_S = {"METADATA_SIZE", "WRITE_SIZE", "READ_SIZE", "DATA_SIZE"}; std::chrono::time_point last_cached; /* Measures when we started the server */ std::chrono::time_point start; // How many stats will be stored const unsigned int MAX_STATS = 1000000; // Stores total value for global mean std::map IOPS; std::map SIZE; // Stores timestamp when an operation comes // removes if first operation if > 10 minutes // Different means will be stored and cached 1 minuted std::map>> TIME_IOPS; // We will store 1, 5, and 10 minute mean; std::map> CACHED_IOPS; // For size operations we need to store the timestamp and // the size std::map, unsigned long long>>> TIME_SIZE; // We will store 1, 5, and 10 minute mean; std::map> CACHED_SIZE; // Thread that outputs stats info std::thread t_output; bool output_thread_; // Controls the destruction of the class/stops the thread bool running = true; /** * @brief Sends all the stats to the screen * Debug Function * * @param d is the time between output */ void output(std::chrono::seconds d); public: /** * @brief Starts the Stats module and initializes structures * */ Stats(bool output_thread); /** * @brief Destroys the class, and any associated thread * */ ~Stats(); /** * Add a new value for a IOPS, that does not involve any size * No value needed as they are simple (1 create, 1 read...) * Size operations internally call this operation (read,write) * * @param IOPS_OP Which operation to add */ void add_value_iops(enum IOPS_OP); /** * @brief Store a new stat point, with a size value. * If it involves a IO operations it will call the corresponding * operation * * @param SIZE_OP Which operation we refer * @param value to store (SIZE_OP) */ void add_value_size(enum SIZE_OP, unsigned long long value); /** * @brief Get the total mean value of the asked stat * This can be provided inmediately without cost * @return mean value */ double get_mean(enum IOPS_OP); /** * @brief Get the total mean value of the asked stat * This can be provided inmediately without cost * @return mean value */ double get_mean(enum SIZE_OP); /** * @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 * * @return std::vector< double > with 4 means */ std::vector get_four_means(enum SIZE_OP); /** * @brief Get all the means (total, 1,5 and 10 minutes) for a IOPS_OP * Returns precalculated values if we just calculated them 1 minute ago * * @return std::vector< double > with 4 means */ std::vector get_four_means(enum IOPS_OP); /** * @brief Dumps all the means from the stats * */ void dump(); }; } // namespace gkfs::utils #endif // GKFS_COMMON_STATS_HPP