/* **************************************************************************** * Copyright 2019 Open Systems Development BV * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the "Software"), * * to deal in the Software without restriction, including without limitation * * the rights to use, copy, modify, merge, publish, distribute, sublicense, * * and/or sell copies of the Software, and to permit persons to whom the * * Software is furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included in * * all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * * DEALINGS IN THE SOFTWARE. * * ***************************************************************************/ #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