measure.h 10.3 KB
/* 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<context, valueType, numBuckets>::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<context, valueType, numBuckets>::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