/* Copyright (C) 2019 * * This file is part of the osdev components suite * * 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 2, 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef OSDEV_COMPONENTS_MQTT_MEASUREMENT_MEASURE_H #define OSDEV_COMPONENTS_MQTT_MEASUREMENT_MEASURE_H #include "macrodefs.h" #include "histogramprovider.h" #include "timemeasurement.h" namespace osdev { namespace components { namespace mqtt { namespace measurement { inline std::string createId(const std::string& operationName, const std::string& dynamicId) { return operationName + (dynamicId.empty() ? std::string{} : std::string(" ") + dynamicId); } } // End namespace measurement } // End namespace mqtt } // End namespace components } // End namespace osdev #define OSDEV_COMPONENTS_MEASUREMENT_LOCATION \ (OSDEV_COMPONENTS_MANAGEDBASEFILENAME + OSDEV_COMPONENTS_CSTRING(":" OSDEV_COMPONENTS_TOSTRING(__LINE__))).chars /** * @brief Macro helper that sets up a TimeMeasurement on an operation. * The operation must have observable side effects otherwise the compiler might move the operation from in between the time measurements. * @param operationName The name of the operation. This is part of the id under which the measurements are registered. * @param dynamicId The dynamic identification of this measurement. This id makes different instances of the same operation unique. * The dynamicId must be an expression that yields a string like object. The dynamic id is part of the id under which the * measurements are registered. * @param operation The operation to perform. * @param context The context tag used to identify the HistogramProvider. * @param valueType A datatype that can be used by HistogramProvider. * @param numBuckets The number of buckets to use for the histogram. * @param boolOnDestroy Boolean value that makes the measurement measure on destruction. */ #define OSDEV_COMPONENTS_MEASUREMENT_MEASURE_HELPER(operationName, dynamicId, operation, context, valueType, numBuckets, boolOnDestroy) \ static const std::string OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(ID__, __LINE__), __) = \ std::string(OSDEV_COMPONENTS_CSTRING(#operationName).chars); \ osdev::components::mqtt::measurement::TimeMeasurement OSDEV_COMPONENTS_COMBINE( \ OSDEV_COMPONENTS_COMBINE(TM__, __LINE__), __)( \ osdev::components::mqtt::measurement::createId(OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(ID__, __LINE__), __), dynamicId), \ [](const std::string& id, std::chrono::steady_clock::time_point, std::chrono::microseconds, std::chrono::microseconds sinceLast) { \ osdev::components::mqtt::measurement::HistogramProvider::instance().addValue(id, sinceLast); \ }, \ boolOnDestroy); \ operation; /** * @brief Make a measurement before and after an operation. * The operation must have observable side effects otherwise the compiler might move the operation from in between the time measurements. * @param operationName The name under which the measurements are registered. * @param operation The operation to perform. * @param context The context tag used to identify the HistogramProvider. * @param valueType A datatype that can be used by HistogramProvider. * @param numBuckets The number of buckets to use for the histogram. */ #define OSDEV_COMPONENTS_MEASUREMENT_MEASURE(operationName, operation, context, valueType, numBuckets) \ OSDEV_COMPONENTS_MEASUREMENT_MEASURE_HELPER(operationName, OSDEV_COMPONENTS_MEASUREMENT_LOCATION, operation, context, valueType, numBuckets, false) \ OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(TM__, __LINE__), __).measure(); /** * @brief Make a measurement on a return operation. * The operation must have observable side effects otherwise the compiler might move the operation from in between the time measurements. * @param operationName The name under which the measurements are registered. * @param operation The operation to perform. * @param context The context tag used to identify the HistogramProvider. * @param valueType A datatype that can be used by HistogramProvider. * @param numBuckets The number of buckets to use for the histogram. */ #define OSDEV_COMPONENTS_MEASUREMENT_MEASURE_ONDESTROY(operationName, operation, context, valueType, numBuckets) \ OSDEV_COMPONENTS_MEASUREMENT_MEASURE_HELPER(operationName, OSDEV_COMPONENTS_MEASUREMENT_LOCATION, operation, context, valueType, numBuckets, true) /** * @brief Make a measurement on a return operation. * The operation must have observable side effects otherwise the compiler might move the operation from in between the time measurements. * @param operationName The name under which the measurements are registered. * @param dynamicId An extra identification to discern between instances of the same operation. The dynamicId must be an expression that * yields a string like object. * @param operation The operation to perform. * @param context The context tag used to identify the HistogramProvider. * @param valueType A datatype that can be used by HistogramProvider. * @param numBuckets The number of buckets to use for the histogram. */ #define OSDEV_COMPONENTS_MEASUREMENT_MEASURE_SPECIFIC_ONDESTROY(operationName, dynamicId, operation, context, valueType, numBuckets) \ OSDEV_COMPONENTS_MEASUREMENT_MEASURE_HELPER(operationName, dynamicId, operation, context, valueType, numBuckets, true) /** * @brief Nop version that only performs the operation. */ #define OSDEV_COMPONENTS_MEASUREMENT_MEASURE_ONDESTROY_NOP(operationName, operation, context, valueType, numBuckets) operation; /** * @brief Nop version that only performs the operation. */ #define OSDEV_COMPONENTS_MEASUREMENT_MEASURE_NOP(operationName, operation, context, valueType, numBuckets) operation; /** * @brief Nop version that only performs the operation. */ #define OSDEV_COMPONENTS_MEASUREMENT_MEASURE_SPECIFIC_ONDESTROY_NOP(operationName, dynamicId, operation, context, valueType, numBuckets) operation; /** * @brief Make a measurement before and after an operation for a specific instance of the operation. * The operation must have observable side effects otherwise the compiler might move the operation from in between the time measurements. * @param dynamicId An extra identification to discern between instances of the same operation. * @param operationName The name under which the measurements are registered. * @param operation The operation to perform. * @param context The context tag used to identify the HistogramProvider. * @param valueType A datatype that can be used by HistogramProvider. * @param numBuckets The number of buckets to use for the histogram. */ #define OSDEV_COMPONENTS_MEASUREMENT_MEASURE_SPECIFIC(dynamicId, operationName, operation, context, valueType, numBuckets) \ auto OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(IDPREFIX__, __LINE__), __) = \ OSDEV_COMPONENTS_MANAGEDBASEFILENAME + OSDEV_COMPONENTS_CSTRING(":" OSDEV_COMPONENTS_TOSTRING(__LINE__) ", function "); \ auto OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(IDPOSTFIX__, __LINE__), __) = OSDEV_COMPONENTS_CSTRING(", " #operationName " "); \ static const std::string OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(ID__, __LINE__), __) = \ std::string(OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(IDPREFIX__, __LINE__), __).chars) + \ std::string(__func__) + \ OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(IDPOSTFIX__, __LINE__), __).chars; \ osdev::components::mqtt::measurement::TimeMeasurement OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(TM__, __LINE__), __)( \ OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(ID__, __LINE__), __) + dynamicId, \ [](const std::string& id, std::chrono::steady_clock::time_point, std::chrono::microseconds, std::chrono::microseconds sinceLast) { \ osdev::components::mqtt::measurement::HistogramProvider::instance().addValue(id, sinceLast); \ }, \ false); \ operation; \ OSDEV_COMPONENTS_COMBINE(OSDEV_COMPONENTS_COMBINE(TM__, __LINE__), __).measure(); /** * @brief Nop version that only performs the operation. */ #define OSDEV_COMPONENTS_MEASUREMENT_MEASURE_SPECIFIC_NOP(dynamicId, operationName, operation, context, valueType, numBuckets) operation; #endif // OSDEV_COMPONENTS_MEASUREMENT_MEASUREMENT_H