diff --git a/podump/adl_sensor.cpp b/podump/adl_sensor.cpp index ab8f8dfe..e229df4f 100644 --- a/podump/adl_sensor.cpp +++ b/podump/adl_sensor.cpp @@ -32,6 +32,31 @@ void sample_adl_sensor(void) { } +/* + * ::sample_adl_sensor_data + */ +void sample_adl_sensor_data(void) { + using namespace visus::power_overwhelming; + + try { + std::vector sensors; + sensors.resize(adl_sensor::for_all(nullptr, 0)); + adl_sensor::for_all(sensors.data(), sensors.size()); + + for (auto &s : sensors) { + std::wcout << s.name() << L":" << std::endl; + auto m = s.sample_data(); + std::wcout << m.timestamp() << L": " + << m.voltage() << L" V, " + << m.current() << L" A, " + << m.power() << L" W" << std::endl; + } + } catch (std::exception &ex) { + std::cerr << ex.what() << std::endl; + } +} + + /* * ::sample_adl_sensor_async */ diff --git a/podump/adl_sensor.h b/podump/adl_sensor.h index 29d9a447..7bf66707 100644 --- a/podump/adl_sensor.h +++ b/podump/adl_sensor.h @@ -11,6 +11,11 @@ /// void sample_adl_sensor(void); +/// +/// Print data for all supported AMD cards using the pure sample method. +/// +void sample_adl_sensor_data(void); + /// /// Sample all supported ADL sensors for the specified number of seconds. /// diff --git a/podump/emi_sensor.cpp b/podump/emi_sensor.cpp index c5d8b857..e64c3a8e 100644 --- a/podump/emi_sensor.cpp +++ b/podump/emi_sensor.cpp @@ -37,6 +37,31 @@ void sample_emi_sensor(void) { } +/* + * ::sample_emi_sensor_data + */ +void sample_emi_sensor_data(void) { + using namespace visus::power_overwhelming; + +#if defined(_WIN32) + try { + std::vector sensors; + sensors.resize(emi_sensor::for_all(nullptr, 0)); + emi_sensor::for_all(sensors.data(), sensors.size()); + + for (auto &s : sensors) { + std::wcout << s.name() << L":" << std::endl; + auto m = s.sample_data(); + std::wcout << m.timestamp() << L": " + << m.power() << L" W" << std::endl; + } + } catch (std::exception &ex) { + std::cerr << ex.what() << std::endl; + } +#endif /* defined(_WIN32) */ +} + + /* * ::sample_emi_sensor_async */ diff --git a/podump/emi_sensor.h b/podump/emi_sensor.h index bcba8cf4..c5bfce64 100644 --- a/podump/emi_sensor.h +++ b/podump/emi_sensor.h @@ -11,6 +11,12 @@ /// void sample_emi_sensor(void); +/// +/// Samples all EMI sensors once using the pure sampling API and prints their +/// values on the console. +/// +void sample_emi_sensor_data(void); + /// /// Samples all EMI sensors for the specified number of seconds. /// diff --git a/podump/msr_sensor.cpp b/podump/msr_sensor.cpp index a3dc7d6c..1ff03f04 100644 --- a/podump/msr_sensor.cpp +++ b/podump/msr_sensor.cpp @@ -30,6 +30,29 @@ void sample_msr_sensor(void) { } +/* + * ::sample_msr_sensor_data + */ +void sample_msr_sensor_data(void) { + using namespace visus::power_overwhelming; + + try { + std::vector sensors; + sensors.resize(msr_sensor::for_all(nullptr, 0)); + msr_sensor::for_all(sensors.data(), sensors.size()); + + for (auto &s : sensors) { + std::wcout << s.name() << L":" << std::endl; + auto m = s.sample_data(); + std::wcout << m.timestamp() << L": " + << m.power() << L" W" << std::endl; + } + } catch (std::exception &ex) { + std::cerr << ex.what() << std::endl; + } +} + + /* * ::sample_msr_sensor_async */ diff --git a/podump/msr_sensor.h b/podump/msr_sensor.h index 1b731542..0dec79aa 100644 --- a/podump/msr_sensor.h +++ b/podump/msr_sensor.h @@ -7,10 +7,15 @@ /// -/// Print data for all CPU cores cards. +/// Print data for all CPU cores. /// void sample_msr_sensor(void); +/// +/// Print data for all CPU cores using the pure sampling API. +/// +void sample_msr_sensor_data(void); + /// /// Sample all supported MSR sensors for the specified number of seconds. /// diff --git a/podump/nvml_sensor.cpp b/podump/nvml_sensor.cpp index 221b55c8..e28bc041 100644 --- a/podump/nvml_sensor.cpp +++ b/podump/nvml_sensor.cpp @@ -30,6 +30,29 @@ void sample_nvml_sensor(void) { } +/* + * ::sample_nvml_sensor_data + */ +void sample_nvml_sensor_data(void) { + using namespace visus::power_overwhelming; + + try { + std::vector sensors; + sensors.resize(nvml_sensor::for_all(nullptr, 0)); + nvml_sensor::for_all(sensors.data(), sensors.size()); + + for (auto &s : sensors) { + std::wcout << s.name() << L":" << std::endl; + auto m = s.sample_data(); + std::wcout << m.timestamp() << L": " << m.power() << L" W" + << std::endl; + } + } catch (std::exception &ex) { + std::cerr << ex.what() << std::endl; + } +} + + /* * ::sample_nvml_sensor_async */ diff --git a/podump/nvml_sensor.h b/podump/nvml_sensor.h index bd4fe162..f1cd78a1 100644 --- a/podump/nvml_sensor.h +++ b/podump/nvml_sensor.h @@ -11,6 +11,11 @@ /// void sample_nvml_sensor(void); +/// +/// Print data for all supported NVIDIA cards using the pure sample method. +/// +void sample_nvml_sensor_data(void); + /// /// Sample all supported NVML sensors for the specified number of seconds. /// diff --git a/podump/podump.cpp b/podump/podump.cpp index f9eef326..5f352a5f 100644 --- a/podump/podump.cpp +++ b/podump/podump.cpp @@ -33,11 +33,15 @@ int _tmain(const int argc, const TCHAR **argv) { #endif // AMD sensors -#if false +#if true #if true ::sample_adl_sensor(); #endif +#if true + ::sample_adl_sensor_data(); +#endif + #if true ::sample_adl_sensor_async(5); #endif @@ -54,6 +58,10 @@ int _tmain(const int argc, const TCHAR **argv) { ::sample_emi_sensor(); #endif +#if true + ::sample_emi_sensor_data(); +#endif + #if true ::sample_emi_sensor_async(5); #endif @@ -71,11 +79,15 @@ int _tmain(const int argc, const TCHAR **argv) { #endif // NVML sensors -#if false +#if true #if true ::sample_nvml_sensor(); #endif +#if true + ::sample_nvml_sensor_data(); +#endif + #if true ::sample_nvml_sensor_async(5); #endif @@ -87,6 +99,10 @@ int _tmain(const int argc, const TCHAR **argv) { ::sample_tinkerforge_sensor(); #endif +#if true + ::sample_tinkerforge_sensor_data(); +#endif + #if true ::sample_tinkerforge_sensor_async(5); #endif diff --git a/podump/tinkerforge.cpp b/podump/tinkerforge.cpp index d3cc0fee..e8bfab88 100644 --- a/podump/tinkerforge.cpp +++ b/podump/tinkerforge.cpp @@ -40,6 +40,39 @@ void sample_tinkerforge_sensor(void) { } +/* + * ::sample_tinkerforge_sensor_data + */ +void sample_tinkerforge_sensor_data(void) { + using namespace visus::power_overwhelming; + + try { + std::vector descs; + descs.resize(tinkerforge_sensor::get_definitions(nullptr, 0)); + auto cnt = tinkerforge_sensor::get_definitions(descs.data(), + descs.size()); + + if (cnt < descs.size()) { + descs.resize(cnt); + } + + for (auto &d : descs) { + tinkerforge_sensor s(d); + std::wcout << s.name() << L":" << std::endl; + auto m = s.sample_data(); + std::wcout << m.timestamp() << L": " + << m.voltage() << " V * " + << m.current() << " A = " + << m.power() << L" W" + << std::endl; + } + + } catch (std::exception &ex) { + std::cerr << ex.what() << std::endl; + } +} + + /* * ::sample_tinkerforge_sensor_async */ diff --git a/podump/tinkerforge.h b/podump/tinkerforge.h index a1b842bd..5590345a 100644 --- a/podump/tinkerforge.h +++ b/podump/tinkerforge.h @@ -11,6 +11,11 @@ /// void sample_tinkerforge_sensor(void); +/// +/// Print values of all Tinkerforge bricklets attached to the machine using the +/// pure sampling API. +/// +void sample_tinkerforge_sensor_data(void); /// /// Samples all Tinkerforge bricklets attached to the machine for the specified diff --git a/power_overwhelming/include/power_overwhelming/adl_sensor.h b/power_overwhelming/include/power_overwhelming/adl_sensor.h index e71ce6b9..6f8088b1 100644 --- a/power_overwhelming/include/power_overwhelming/adl_sensor.h +++ b/power_overwhelming/include/power_overwhelming/adl_sensor.h @@ -134,20 +134,6 @@ namespace power_overwhelming { virtual _Ret_maybenull_z_ const wchar_t *name( void) const noexcept override; - /// - /// Sample the sensor. - /// - /// The temporal resolution of the timestamp - /// to be returned. - /// A sensor sample with the information about power - /// consumption that is available via ADL. - /// If a sensor that has been moved - /// is sampled. - /// If the sensor could not be sampled. - /// - virtual measurement sample( - _In_ const timestamp_resolution resolution) const override; - /// /// Asynchronously sample the sensor every /// microseconds. @@ -246,6 +232,12 @@ namespace power_overwhelming { /// otherwise. virtual operator bool(void) const noexcept override; + protected: + + /// + measurement_data sample_sync( + _In_ const timestamp_resolution resolution) const override; + private: detail::adl_sensor_impl *_impl; diff --git a/power_overwhelming/include/power_overwhelming/emi_sensor.h b/power_overwhelming/include/power_overwhelming/emi_sensor.h index ebf08c31..4c0e476b 100644 --- a/power_overwhelming/include/power_overwhelming/emi_sensor.h +++ b/power_overwhelming/include/power_overwhelming/emi_sensor.h @@ -223,10 +223,6 @@ namespace power_overwhelming { /// is invalid. _Ret_maybenull_z_ const char_type *path(void) const noexcept; - /// - virtual measurement sample( - _In_ const timestamp_resolution resolution) const override; - /// /// Asynchronously sample the sensor every /// microseconds. @@ -322,6 +318,12 @@ namespace power_overwhelming { /// virtual operator bool(void) const noexcept override; + protected: + + /// + measurement_data sample_sync( + _In_ const timestamp_resolution resolution) const override; + private: detail::emi_sensor_impl *_impl; diff --git a/power_overwhelming/include/power_overwhelming/hmc8015_sensor.h b/power_overwhelming/include/power_overwhelming/hmc8015_sensor.h index e46e855f..9c8b504a 100644 --- a/power_overwhelming/include/power_overwhelming/hmc8015_sensor.h +++ b/power_overwhelming/include/power_overwhelming/hmc8015_sensor.h @@ -266,19 +266,6 @@ namespace power_overwhelming { /// processed successfully. virtual void reset(void) override; - /// - /// Samples the sensor one time. - /// - /// The resolution of the timestamp to be - /// generated for the measurement. - /// The measurement received from the instrument. - /// If the method is called on an - /// object that has been disposed by moving it. - /// If the VISA command was not - /// processed successfully. - virtual measurement sample( - _In_ const timestamp_resolution resolution) const override; - using sensor::sample; /// @@ -318,6 +305,12 @@ namespace power_overwhelming { return *this; } + protected: + + /// + measurement_data sample_sync( + _In_ const timestamp_resolution resolution) const override; + private: void configure(void); diff --git a/power_overwhelming/include/power_overwhelming/measurement.h b/power_overwhelming/include/power_overwhelming/measurement.h index c4711c40..652657c5 100644 --- a/power_overwhelming/include/power_overwhelming/measurement.h +++ b/power_overwhelming/include/power_overwhelming/measurement.h @@ -5,12 +5,11 @@ #pragma once -#include -#include #include #include "power_overwhelming/convert_string.h" #include "power_overwhelming/csv_iomanip.h" +#include "power_overwhelming/measurement_data.h" #include "power_overwhelming/quote.h" @@ -20,7 +19,7 @@ namespace power_overwhelming { /// /// Represents a single measurement sample for current, voltage and power. /// - class POWER_OVERWHELMING_API measurement { + class POWER_OVERWHELMING_API measurement final { public: @@ -32,12 +31,12 @@ namespace power_overwhelming { /// /// The type of a timestamp associated with a measurement. /// - typedef std::int64_t timestamp_type; + typedef measurement_data::timestamp_type timestamp_type; /// /// The type of current and voltage measurements. /// - typedef float value_type; + typedef measurement_data::value_type value_type; /// /// The value used to represent invalid measurements. @@ -88,12 +87,23 @@ namespace power_overwhelming { _In_ const timestamp_type timestamp, _In_ const value_type power); + /// + /// Initialises a new instance. + /// + /// The name of the sensor from which the + /// measurement originates. + /// The actual measurement data of the sample. + /// + measurement(_In_z_ const char_type *sensor, + _In_ const measurement_data& data); + /// /// Clone . /// /// The object to be cloned. - inline measurement(const measurement& rhs) : _sensor(nullptr) { - *this = rhs; + inline measurement(_In_ const measurement& rhs) + : _data(rhs._data), _sensor(nullptr) { + this->set_sensor(rhs._sensor); } /// @@ -101,8 +111,9 @@ namespace power_overwhelming { /// /// /// - inline measurement(measurement&& rhs) noexcept : _sensor(nullptr) { - *this = std::move(rhs); + inline measurement(measurement&& rhs) noexcept + : _data(std::move(rhs._data)), _sensor(rhs._sensor) { + rhs._sensor = nullptr; } /// @@ -114,9 +125,19 @@ namespace power_overwhelming { /// Gets the electric current (in Amperes) measured at the given point /// in time. /// - /// + /// The electric current if it was measured, or + /// if the sample only contains the + /// power. inline value_type current(void) const noexcept { - return this->_current; + return this->_data.current(); + } + + /// + /// Gets the pure of the sample. + /// + /// The data of the sample. + inline const measurement_data& data(void) const noexcept { + return this->_data; } /// @@ -127,66 +148,67 @@ namespace power_overwhelming { /// If the specified power is negative, it is considered as not given /// and computed from current and voltage on the fly. /// - /// + /// The electric power. inline value_type power(void) const noexcept { - return (this->_power > static_cast(0)) - ? this->_power - : this->_current * this->_voltage; + return this->_data.power(); } /// /// Gets the name of the sensor the measurement comes from. /// - /// - inline _Ret_z_ const char_type *sensor(void) const noexcept { + /// The name of the sensor, which may be nullptr if the + /// sample has been moved. + inline _Ret_maybenull_z_ const char_type *sensor(void) const noexcept { return this->_sensor; } /// /// Gets the timestamp of the measurement. /// - /// + /// The timestamp in the unit requested from the sensor. + /// inline timestamp_type timestamp(void) const noexcept { - return this->_timestamp; + return this->_data.timestamp(); } /// /// Gets the electric potential (in Volts) measured at the given point /// in time. /// - /// + /// The electric potential if it was measured, or + /// if the sample only contains the + /// power. inline value_type voltage(void) const noexcept { - return this->_voltage; + return this->_data.voltage(); } /// /// Assignment. /// - /// + /// The right-hand side operand. /// *this measurement& operator =(const measurement& rhs); /// /// Move assignment. /// - /// + /// The right-hand side operand. /// *this measurement& operator =(measurement&& rhs) noexcept; /// /// Test whether the measurement is valid. /// - /// - /// + /// true if the measurement is valid, false + /// if it has been invalidated by moving it. operator bool(void) const noexcept; private: - value_type _current; - value_type _power; + void set_sensor(_In_z_ const char_type *sensor); + + measurement_data _data; char_type *_sensor; - timestamp_type _timestamp; - value_type _voltage; }; diff --git a/power_overwhelming/include/power_overwhelming/measurement_data.h b/power_overwhelming/include/power_overwhelming/measurement_data.h new file mode 100644 index 00000000..cf82774f --- /dev/null +++ b/power_overwhelming/include/power_overwhelming/measurement_data.h @@ -0,0 +1,179 @@ +// +// Copyright © 2023 Visualisierungsinstitut der Universität Stuttgart. Alle Rechte vorbehalten. +// +// Christoph Müller + +#pragma once + +#include +#include + +#include "power_overwhelming/power_overwhelming_api.h" + + +namespace visus { +namespace power_overwhelming { + + /// + /// Container for the raw measurement data of a single sample for current, + /// voltage and power. + /// + /// + /// This class has been newly introduced to reduce the overhead of code that + /// manually tracks the source of samples instead of relying on the sensor + /// embedding its name into a sample. + /// + class POWER_OVERWHELMING_API measurement_data final { + + public: + + /// + /// The type of a timestamp associated with a measurement. + /// + typedef std::int64_t timestamp_type; + + /// + /// The type of current and voltage measurements. + /// + typedef float value_type; + + /// + /// The value used to represent invalid measurements. + /// + static const value_type invalid_value; + + /// + /// Initialises a new instance. + /// + /// The timestamp of the sensor. The unit is + /// defined by the configuration of the sensor. + /// The measured voltage in Volts. + /// The measured current in Amperes. + /// The measured power in Watts. + measurement_data(_In_ const timestamp_type timestamp, + _In_ const value_type voltage, + _In_ const value_type current, + _In_ const value_type power); + + /// + /// Initialises a new instance. + /// + /// The timestamp of the sensor. The unit is + /// defined by the configuration of the sensor. + /// The measured voltage in Volts. + /// The measured current in Amperes. + /// If any of + /// or is + /// . + measurement_data(_In_ const timestamp_type timestamp, + _In_ const value_type voltage, + _In_ const value_type current); + + /// + /// Initialises a new instance. + /// + /// The timestamp of the sensor. The unit is + /// defined by the configuration of the sensor. + /// + /// The measured power in Watts. + /// If + /// is . + measurement_data(_In_ const timestamp_type timestamp, + _In_ const value_type power); + + /// + /// Clone . + /// + /// The object to be cloned. + measurement_data(const measurement_data& rhs) = default; + + /// + /// Move to a new object. + /// + /// The object to be moved. + inline measurement_data(measurement_data&& rhs) noexcept { + *this = std::move(rhs); + } + + /// + /// Finalises the instance. + /// + ~measurement_data(void) = default; + + /// + /// Gets the electric current (in Amperes) measured at the given point + /// in time. + /// + /// The electric current if it was measured, or + /// if the sample only contains the + /// power. + inline value_type current(void) const noexcept { + return this->_current; + } + + /// + /// Gets the electric power (in Watts) measured at the given point in + /// time. + /// + /// + /// If the specified power is negative, it is considered as not given + /// and computed from current and voltage on the fly. + /// + /// The electric power. + inline value_type power(void) const noexcept { + return (this->_power > static_cast(0)) + ? this->_power + : this->_current * this->_voltage; + } + + /// + /// Gets the timestamp of the measurement. + /// + /// The timestamp in the unit requested from the sensor. + /// + inline timestamp_type timestamp(void) const noexcept { + return this->_timestamp; + } + + /// + /// Gets the electric potential (in Volts) measured at the given point + /// in time. + /// + /// The electric potential if it was measured, or + /// if the sample only contains the + /// power. + inline value_type voltage(void) const noexcept { + return this->_voltage; + } + + /// + /// Assignment. + /// + /// The right-hand side operand. + /// *this + measurement_data& operator =(const measurement_data& rhs) = default; + + /// + /// Move assignment. + /// + /// The right-hand side operand. + /// *this + measurement_data& operator =(measurement_data&& rhs) noexcept; + + /// + /// Test whether the measurement is valid. + /// + /// true if the object contains valid measurement + /// data, false otherwise. + operator bool(void) const noexcept; + + private: + + value_type _current; + value_type _power; + timestamp_type _timestamp; + value_type _voltage; + }; + +} /* namespace power_overwhelming */ +} /* namespace visus */ diff --git a/power_overwhelming/include/power_overwhelming/msr_sensor.h b/power_overwhelming/include/power_overwhelming/msr_sensor.h index ada76e5b..51deeb80 100644 --- a/power_overwhelming/include/power_overwhelming/msr_sensor.h +++ b/power_overwhelming/include/power_overwhelming/msr_sensor.h @@ -155,10 +155,6 @@ namespace power_overwhelming { virtual _Ret_maybenull_z_ const wchar_t *name( void) const noexcept override; - /// - virtual measurement sample( - _In_ const timestamp_resolution resolution) const override; - using sensor::sample; /// @@ -199,6 +195,12 @@ namespace power_overwhelming { /// virtual operator bool(void) const noexcept override; + protected: + + /// + measurement_data sample_sync( + _In_ const timestamp_resolution resolution) const override; + private: detail::msr_sensor_impl *_impl; diff --git a/power_overwhelming/include/power_overwhelming/nvml_sensor.h b/power_overwhelming/include/power_overwhelming/nvml_sensor.h index 8131a045..0a9dcff5 100644 --- a/power_overwhelming/include/power_overwhelming/nvml_sensor.h +++ b/power_overwhelming/include/power_overwhelming/nvml_sensor.h @@ -151,10 +151,6 @@ namespace power_overwhelming { virtual _Ret_maybenull_z_ const wchar_t *name( void) const noexcept override; - /// - virtual measurement sample( - _In_ const timestamp_resolution resolution) const override; - using sensor::sample; /// @@ -190,6 +186,12 @@ namespace power_overwhelming { /// virtual operator bool(void) const noexcept override; + protected: + + /// + measurement_data sample_sync( + _In_ const timestamp_resolution resolution) const override; + private: detail::nvml_sensor_impl *_impl; diff --git a/power_overwhelming/include/power_overwhelming/rtb_sensor.h b/power_overwhelming/include/power_overwhelming/rtb_sensor.h index e3e9dc9c..943c5b8e 100644 --- a/power_overwhelming/include/power_overwhelming/rtb_sensor.h +++ b/power_overwhelming/include/power_overwhelming/rtb_sensor.h @@ -138,10 +138,6 @@ namespace power_overwhelming { //void log_file(const char *path, const bool overwrite = false, // const bool use_usb = false); - /// - virtual measurement sample( - _In_ const timestamp_resolution resolution) const override; - /// /// Sets the unit of the specified channel. /// @@ -163,6 +159,12 @@ namespace power_overwhelming { return *this; } + protected: + + /// + measurement_data sample_sync( + _In_ const timestamp_resolution resolution) const override; + }; } /* namespace power_overwhelming */ diff --git a/power_overwhelming/include/power_overwhelming/sensor.h b/power_overwhelming/include/power_overwhelming/sensor.h index 960764b0..a7fb8f4f 100644 --- a/power_overwhelming/include/power_overwhelming/sensor.h +++ b/power_overwhelming/include/power_overwhelming/sensor.h @@ -55,7 +55,8 @@ namespace power_overwhelming { /// /// The resolution of the timestamp to be /// created. This value basically determines the unit in which the - /// timestamp in the return value is measured. + /// timestamp in the return value is measured. This parameter defaults + /// to . /// A single measurement made by the sensor. /// If a sensor that has been moved /// (and therefore disposed) is sampled. @@ -67,12 +68,42 @@ namespace power_overwhelming { /// could not be sampled. /// If a sensor based on a VISA /// instrument could not be sampled. - virtual measurement sample( - _In_ const timestamp_resolution resolution) const = 0; + /// If a sensor could not be sampled + /// due to a system call failing. + measurement sample(_In_ const timestamp_resolution resolution + = timestamp_resolution::milliseconds) const; /// - /// Sample the sensor using a timestamp with millisecond resolution. + /// Sample the sensor using a timestamp with the specified resolution, + /// but do not attach the sensor that produces the data to the sample. /// + /// + /// This new method is an alternative to + /// that does not incur the cost for + /// copying the name of the sensor producing the data to the sample. It + /// is suitable for applications that keep track of the sensors and the + /// samples on their own and that cause the least possible overhead on + /// the machine the code is running on. This is specifically interesting + /// for applications using sensors that can only be sampled on the + /// machine under observation, like GPU power sensors and the RAPL + /// registers. + /// Please be aware that you might not be able to obtain all + /// information about the sensor that the data originate from when + /// using this method. This is the case if the underlying API can + /// produce samples from different sources. Such sensors must be + /// configured to make sure that they only return the data expected + /// when using this method for sampling. + /// Rationale: The naming of this method (and of + /// ) is a bit weird, which is due to the + /// fact that samples without the originating sensor embedded have been + /// added later to the library. The previous type and method names have + /// not been changed at this point in order to not break existing code + /// relying on the library. + /// + /// The resolution of the timestamp to be + /// created. This value basically determines the unit in which the + /// timestamp in the return value is measured. This parameter defaults + /// to . /// A single measurement made by the sensor. /// If a sensor that has been moved /// (and therefore disposed) is sampled. @@ -84,8 +115,12 @@ namespace power_overwhelming { /// could not be sampled. /// If a sensor based on a VISA /// instrument could not be sampled. - inline measurement sample(void) const { - return this->sample(timestamp_resolution::milliseconds); + /// If a sensor could not be sampled + /// due to a system call failing. + inline measurement_data sample_data( + _In_ const timestamp_resolution resolution + = timestamp_resolution::milliseconds) const { + return this->sample_sync(resolution); } /// @@ -117,6 +152,16 @@ namespace power_overwhelming { /// If a sensor that has been moved /// (and therefore disposed) is sampled. void check_not_disposed(void) const; + + /// + /// Synchronously sample the sensor using a timestamp with the specified + /// resolution. + /// + /// The resolution of the timestamp to be + /// created. + /// A single measurement made by the sensor. + virtual measurement_data sample_sync( + _In_ const timestamp_resolution resolution) const = 0; }; } /* namespace power_overwhelming */ diff --git a/power_overwhelming/include/power_overwhelming/tinkerforge_sensor.h b/power_overwhelming/include/power_overwhelming/tinkerforge_sensor.h index 26e05227..342fdbb9 100644 --- a/power_overwhelming/include/power_overwhelming/tinkerforge_sensor.h +++ b/power_overwhelming/include/power_overwhelming/tinkerforge_sensor.h @@ -357,23 +357,6 @@ namespace power_overwhelming { /// void reset(void); - /// - /// Sample the sensor. - /// - /// The temporal resolution of the timestamp - /// to be returned. - /// A sensor sample with the information about power - /// consumption that is available via Tinkerforge bricklets. - /// If - /// does not designate a valid resolution - /// for timestamps. - /// If a sensor that has been moved - /// is sampled.If the sensor could not be - /// sampled. - virtual measurement sample( - _In_ const timestamp_resolution resolution) const override; - using sensor::sample; /// @@ -427,6 +410,12 @@ namespace power_overwhelming { /// otherwise. virtual operator bool(void) const noexcept override; + protected: + + /// + measurement_data sample_sync( + _In_ const timestamp_resolution resolution) const override; + private: detail::tinkerforge_sensor_impl *_impl; diff --git a/power_overwhelming/src/adl_sensor.cpp b/power_overwhelming/src/adl_sensor.cpp index 97ffdd2d..10c3d24e 100644 --- a/power_overwhelming/src/adl_sensor.cpp +++ b/power_overwhelming/src/adl_sensor.cpp @@ -305,32 +305,6 @@ _Ret_maybenull_z_ const wchar_t *visus::power_overwhelming::adl_sensor::name( } -/* - * visus::power_overwhelming::adl_sensor::sample - */ -visus::power_overwhelming::measurement -visus::power_overwhelming::adl_sensor::sample( - _In_ const timestamp_resolution resolution) const { - this->check_not_disposed(); - const auto is_running = this->_impl->running(); - - if (!is_running) { - // If the sensor is not running asynchronously, start it for obtaining - // a single sample. - this->_impl->start(0); - } - - auto retval = this->_impl->sample(resolution); - - if (!is_running) { - // If we started the sensor here, stop it. - this->_impl->stop(); - } - - return retval; -} - - /* * visus::power_overwhelming::adl_sensor::sample */ @@ -441,3 +415,29 @@ visus::power_overwhelming::adl_sensor::operator =( visus::power_overwhelming::adl_sensor::operator bool(void) const noexcept { return (this->_impl != nullptr); } + + +/* + * visus::power_overwhelming::adl_sensor::sample_sync + */ +visus::power_overwhelming::measurement_data +visus::power_overwhelming::adl_sensor::sample_sync( + _In_ const timestamp_resolution resolution) const { + this->check_not_disposed(); + const auto is_running = this->_impl->running(); + + if (!is_running) { + // If the sensor is not running asynchronously, start it for obtaining + // a single sample. + this->_impl->start(0); + } + + auto retval = this->_impl->sample(resolution); + + if (!is_running) { + // If we started the sensor here, stop it. + this->_impl->stop(); + } + + return retval; +} diff --git a/power_overwhelming/src/adl_sensor_impl.cpp b/power_overwhelming/src/adl_sensor_impl.cpp index 7bb8772d..99fb14f3 100644 --- a/power_overwhelming/src/adl_sensor_impl.cpp +++ b/power_overwhelming/src/adl_sensor_impl.cpp @@ -318,7 +318,7 @@ void visus::power_overwhelming::detail::adl_sensor_impl::configure_source( /* * visus::power_overwhelming::detail::adl_sensor_impl::sample */ -visus::power_overwhelming::measurement +visus::power_overwhelming::measurement_data visus::power_overwhelming::detail::adl_sensor_impl::sample( const timestamp_resolution resolution) { assert(this->state.load() == 1); @@ -342,18 +342,18 @@ visus::power_overwhelming::detail::adl_sensor_impl::sample( case 1: // If we have one reading, it must be a power reading due to the way // we enumerate the sensors in get_sensor_ids. - return measurement(this->sensor_name.c_str(), timestamp, + return measurement_data(timestamp, static_cast(power)); case 2: // If we have two readings, it must be voltage and current. - return measurement(this->sensor_name.c_str(), timestamp, + return measurement_data(timestamp, static_cast(voltage) / thousand, static_cast(current)); case 3: // This must be voltage, current and power. - return measurement(this->sensor_name.c_str(), timestamp, + return measurement_data(timestamp, static_cast(voltage) / thousand, static_cast(current), static_cast(power)); diff --git a/power_overwhelming/src/adl_sensor_impl.h b/power_overwhelming/src/adl_sensor_impl.h index f32884fd..b9be02fa 100644 --- a/power_overwhelming/src/adl_sensor_impl.h +++ b/power_overwhelming/src/adl_sensor_impl.h @@ -235,7 +235,7 @@ namespace detail { /// The resolution of the timestamp being /// returned. /// The current measurement from the sensor. - measurement sample(const timestamp_resolution resolution + measurement_data sample(const timestamp_resolution resolution = timestamp_resolution::milliseconds); /// diff --git a/power_overwhelming/src/default_sampler_context.inl b/power_overwhelming/src/default_sampler_context.inl index 3d583be3..fb7cdb0e 100644 --- a/power_overwhelming/src/default_sampler_context.inl +++ b/power_overwhelming/src/default_sampler_context.inl @@ -46,7 +46,9 @@ void visus::power_overwhelming::detail::default_sampler_context { std::lock_guardlock)> l(this->lock); for (auto& s : this->sensors) { - s.second.first(s.first->sample(), s.second.second); + // TODO + s.second.first(measurement(s.first->sensor_name.c_str(), + s.first->sample()), s.second.second); } have_sensors = !this->sensors.empty(); diff --git a/power_overwhelming/src/emi_sampler_context.cpp b/power_overwhelming/src/emi_sampler_context.cpp index 83abe7bc..7cc3a576 100644 --- a/power_overwhelming/src/emi_sampler_context.cpp +++ b/power_overwhelming/src/emi_sampler_context.cpp @@ -109,8 +109,10 @@ void visus::power_overwhelming::detail::emi_sampler_context::sample(void) { sample = sensor->sample(); } - callback(sensor->evaluate(sample, version, - timestamp_resolution::milliseconds), context); + // TODO + callback(measurement(s.first->sensor_name.c_str(), + sensor->evaluate(sample, version, + timestamp_resolution::milliseconds)), context); } sample.clear(); diff --git a/power_overwhelming/src/emi_sensor.cpp b/power_overwhelming/src/emi_sensor.cpp index 9d6716f1..10d5e269 100644 --- a/power_overwhelming/src/emi_sensor.cpp +++ b/power_overwhelming/src/emi_sensor.cpp @@ -228,38 +228,6 @@ visus::power_overwhelming::emi_sensor::path(void) const noexcept { } -/* - * visus::power_overwhelming::emi_sensor::sample - */ -visus::power_overwhelming::measurement -visus::power_overwhelming::emi_sensor::sample( - _In_ const timestamp_resolution resolution) const { -#if defined(_WIN32) - this->check_not_disposed(); - - switch (this->version()) { - case EMI_VERSION_V1: { - EMI_MEASUREMENT_DATA_V1 s; - this->_impl->sample(&s, sizeof(s)); - return this->_impl->evaluate(s, resolution); - } - - case EMI_VERSION_V2: { - auto m = this->_impl->sample(); - auto s = reinterpret_cast(m.data()); - return this->_impl->evaluate(*s, resolution); - } - - default: - throw std::logic_error("The specified version of the Energy " - "Meter Interface is not supported by the implementation."); - } -#else /* defined(_WIN32) */ - throw std::logic_error(ERROR_MSG_NOT_SUPPORTED); -#endif /* defined(_WIN32) */ -} - - /* * visus::power_overwhelming::emi_sensor::sample */ @@ -370,3 +338,35 @@ visus::power_overwhelming::emi_sensor::operator bool(void) const noexcept { return false; #endif /* defined(_WIN32) */ } + + +/* + * visus::power_overwhelming::emi_sensor::sample_sync + */ +visus::power_overwhelming::measurement_data +visus::power_overwhelming::emi_sensor::sample_sync( + _In_ const timestamp_resolution resolution) const { +#if defined(_WIN32) + this->check_not_disposed(); + + switch (this->version()) { + case EMI_VERSION_V1: { + EMI_MEASUREMENT_DATA_V1 s; + this->_impl->sample(&s, sizeof(s)); + return this->_impl->evaluate(s, resolution); + } + + case EMI_VERSION_V2: { + auto m = this->_impl->sample(); + auto s = reinterpret_cast(m.data()); + return this->_impl->evaluate(*s, resolution); + } + + default: + throw std::logic_error("The specified version of the Energy " + "Meter Interface is not supported by the implementation."); + } +#else /* defined(_WIN32) */ + throw std::logic_error(ERROR_MSG_NOT_SUPPORTED); +#endif /* defined(_WIN32) */ +} diff --git a/power_overwhelming/src/emi_sensor_impl.cpp b/power_overwhelming/src/emi_sensor_impl.cpp index 53c1ccc9..cc96a6da 100644 --- a/power_overwhelming/src/emi_sensor_impl.cpp +++ b/power_overwhelming/src/emi_sensor_impl.cpp @@ -33,7 +33,7 @@ visus::power_overwhelming::detail::emi_sensor_impl::~emi_sensor_impl(void) { /* * visus::power_overwhelming::detail::emi_sensor_impl::evaluate */ -visus::power_overwhelming::measurement +visus::power_overwhelming::measurement_data visus::power_overwhelming::detail::emi_sensor_impl::evaluate( const EMI_CHANNEL_MEASUREMENT_DATA& data, const timestamp_resolution resolution) { @@ -54,7 +54,7 @@ visus::power_overwhelming::detail::emi_sensor_impl::evaluate( auto time = data.AbsoluteTime - dt / 2 + this->time_offset; time = convert(time, resolution); - return measurement(this->sensor_name.c_str(), time, value); + return measurement_data(time, value); } default: @@ -67,7 +67,7 @@ visus::power_overwhelming::detail::emi_sensor_impl::evaluate( /* * visus::power_overwhelming::detail::emi_sensor_impl::evaluate */ -visus::power_overwhelming::measurement +visus::power_overwhelming::measurement_data visus::power_overwhelming::detail::emi_sensor_impl::evaluate( const std::vector& data, const emi_sensor::version_type version, diff --git a/power_overwhelming/src/emi_sensor_impl.h b/power_overwhelming/src/emi_sensor_impl.h index cf3434cb..fa100590 100644 --- a/power_overwhelming/src/emi_sensor_impl.h +++ b/power_overwhelming/src/emi_sensor_impl.h @@ -153,7 +153,7 @@ namespace detail { /// /// /// - measurement evaluate(const EMI_CHANNEL_MEASUREMENT_DATA& data, + measurement_data evaluate(const EMI_CHANNEL_MEASUREMENT_DATA& data, const timestamp_resolution resolution); /// @@ -165,7 +165,7 @@ namespace detail { /// /// /// - inline measurement evaluate(const EMI_MEASUREMENT_DATA_V2& data, + inline measurement_data evaluate(const EMI_MEASUREMENT_DATA_V2& data, const timestamp_resolution resolution) { assert(this->channel < this->device->channels()); return this->evaluate(data.ChannelData[this->channel], @@ -182,7 +182,7 @@ namespace detail { /// /// /// - measurement evaluate(const std::vector& data, + measurement_data evaluate(const std::vector& data, const emi_sensor::version_type version, const timestamp_resolution resolution); diff --git a/power_overwhelming/src/hmc8015_sensor.cpp b/power_overwhelming/src/hmc8015_sensor.cpp index 6b2f5765..cda13d89 100644 --- a/power_overwhelming/src/hmc8015_sensor.cpp +++ b/power_overwhelming/src/hmc8015_sensor.cpp @@ -351,10 +351,10 @@ void visus::power_overwhelming::hmc8015_sensor::reset(void) { /* - * visus::power_overwhelming::hmc8015_sensor::sample + * visus::power_overwhelming::hmc8015_sensor::sample_sync */ -visus::power_overwhelming::measurement -visus::power_overwhelming::hmc8015_sensor::sample( +visus::power_overwhelming::measurement_data +visus::power_overwhelming::hmc8015_sensor::sample_sync( _In_ const timestamp_resolution resolution) const { auto impl = static_cast(*this); auto response = impl.query("CHAN1:MEAS:DATA?\n"); @@ -366,12 +366,10 @@ visus::power_overwhelming::hmc8015_sensor::sample( auto c = static_cast(::atof(tokens[1].c_str())); auto p = static_cast(::atof(tokens[2].c_str())); - _Analysis_assume_(this->name() != nullptr); - return measurement(this->name(), timestamp, v, c, p); + return measurement_data(timestamp, v, c, p); } - /* * visus::power_overwhelming::hmc8015_sensor::configure */ diff --git a/power_overwhelming/src/measurement.cpp b/power_overwhelming/src/measurement.cpp index be624d6a..b6e34fc0 100644 --- a/power_overwhelming/src/measurement.cpp +++ b/power_overwhelming/src/measurement.cpp @@ -1,11 +1,11 @@ // -// Copyright © 2021 Visualisierungsinstitut der Universität Stuttgart. Alle Rechte vorbehalten. +// Copyright © 2021 - 2023 Visualisierungsinstitut der Universität Stuttgart. Alle Rechte vorbehalten. // // Christoph Müller #include "power_overwhelming/measurement.h" -#include +#include #include @@ -14,7 +14,7 @@ */ const visus::power_overwhelming::measurement::value_type visus::power_overwhelming::measurement::invalid_value - = std::numeric_limits::lowest(); + = visus::power_overwhelming::measurement_data::invalid_value; /* @@ -26,16 +26,8 @@ visus::power_overwhelming::measurement::measurement( _In_ const value_type voltage, _In_ const value_type current, _In_ const value_type power) - :_current(current), _power(power), _sensor(nullptr), - _timestamp(timestamp), _voltage(voltage) { - if (sensor == nullptr) { - throw std::invalid_argument("A valid sensor name must be specified."); - } - - this->_sensor = ::wcsdup(sensor); - if (this->_sensor == nullptr) { - throw std::bad_alloc(); - } + : _data(timestamp, voltage, current, power), _sensor(nullptr) { + this->set_sensor(sensor); } @@ -47,24 +39,8 @@ visus::power_overwhelming::measurement::measurement( _In_ const timestamp_type timestamp, _In_ const value_type voltage, _In_ const value_type current) - :_current(current), _power(invalid_value), _sensor(nullptr), - _timestamp(timestamp), _voltage(voltage) { - if (sensor == nullptr) { - throw std::invalid_argument("A valid sensor name must be specified."); - } - if (voltage == invalid_value) { - throw std::invalid_argument("A valid voltage measurement must be " - "specified."); - } - if (current == invalid_value) { - throw std::invalid_argument("A valid current measurement must be " - "specified."); - } - - this->_sensor = ::wcsdup(sensor); - if (this->_sensor == nullptr) { - throw std::bad_alloc(); - } + : _data(timestamp, voltage, current), _sensor(nullptr) { + this->set_sensor(sensor); } @@ -75,20 +51,19 @@ visus::power_overwhelming::measurement::measurement( _In_z_ const char_type *sensor, _In_ const timestamp_type timestamp, _In_ const value_type power) - :_current(invalid_value), _power(power), _sensor(nullptr), - _timestamp(timestamp), _voltage(invalid_value) { - if (sensor == nullptr) { - throw std::invalid_argument("A valid sensor name must be specified."); - } - if (power == invalid_value) { - throw std::invalid_argument("A valid power measurement must be " - "specified."); - } + : _data(timestamp, power), _sensor(nullptr) { + this->set_sensor(sensor); +} - this->_sensor = ::wcsdup(sensor); - if (this->_sensor == nullptr) { - throw std::bad_alloc(); - } + +/* + * visus::power_overwhelming::measurement::measurement + */ +visus::power_overwhelming::measurement::measurement( + _In_z_ const char_type *sensor, + _In_ const measurement_data& data) + : _data(data), _sensor(nullptr) { + this->set_sensor(sensor); } @@ -108,14 +83,8 @@ visus::power_overwhelming::measurement::~measurement(void) { visus::power_overwhelming::measurement& visus::power_overwhelming::measurement::operator =(const measurement& rhs) { if (this != std::addressof(rhs)) { - this->_current = rhs._current; - this->_power = rhs._power; - this->_sensor = ::wcsdup(rhs._sensor); - if (this->_sensor == nullptr) { - throw std::bad_alloc(); - } - this->_timestamp = rhs._timestamp; - this->_voltage = rhs._voltage; + this->_data = rhs._data; + this->set_sensor(rhs._sensor); } return *this; @@ -128,16 +97,9 @@ visus::power_overwhelming::measurement::operator =(const measurement& rhs) { visus::power_overwhelming::measurement& visus::power_overwhelming::measurement::operator =(measurement&& rhs) noexcept { if (this != std::addressof(rhs)) { - this->_current = rhs._current; - rhs._current = invalid_value; - this->_power = rhs._power; - rhs._power = invalid_value; + this->_data = std::move(rhs._data); this->_sensor = rhs._sensor; rhs._sensor = nullptr; - this->_timestamp = rhs._timestamp; - rhs._timestamp = 0; - this->_voltage = rhs._voltage; - rhs._voltage = invalid_value; } return *this; @@ -148,9 +110,25 @@ visus::power_overwhelming::measurement::operator =(measurement&& rhs) noexcept { * visus::power_overwhelming::measurement::operator bool */ visus::power_overwhelming::measurement::operator bool(void) const noexcept { - auto isPowerValid = (this->_power != invalid_value); - auto isSeparateValid = (this->_current != invalid_value) - && (this->_voltage != invalid_value); + return (this->_sensor != nullptr) && static_cast(this->_data); +} + + +/* + * visus::power_overwhelming::measurement::set_sensor + */ +void visus::power_overwhelming::measurement::set_sensor( + _In_z_ const char_type *sensor) { + if (sensor == nullptr) { + throw std::invalid_argument("A valid sensor name must be specified."); + } + + if (this->_sensor != nullptr) { + ::free(this->_sensor); + } - return (this->_sensor != nullptr) && (isPowerValid || isSeparateValid); + this->_sensor = ::wcsdup(sensor); + if (this->_sensor == nullptr) { + throw std::bad_alloc(); + } } diff --git a/power_overwhelming/src/measurement_data.cpp b/power_overwhelming/src/measurement_data.cpp new file mode 100644 index 00000000..dd79da33 --- /dev/null +++ b/power_overwhelming/src/measurement_data.cpp @@ -0,0 +1,96 @@ +// +// Copyright © 2023 Visualisierungsinstitut der Universität Stuttgart. Alle Rechte vorbehalten. +// +// Christoph Müller + +#include "power_overwhelming/measurement_data.h" + +#include +#include + + +/* + * visus::power_overwhelming::measurement_data::invalid_value + */ +const visus::power_overwhelming::measurement_data::value_type +visus::power_overwhelming::measurement_data::invalid_value + = std::numeric_limits::lowest(); + + +/* + * visus::power_overwhelming::measurement_data::measurement_data + */ +visus::power_overwhelming::measurement_data::measurement_data( + _In_ const timestamp_type timestamp, + _In_ const value_type voltage, + _In_ const value_type current, + _In_ const value_type power) + :_current(current), _power(power), _timestamp(timestamp), + _voltage(voltage) { } + + +/* + * visus::power_overwhelming::measurement_data::measurement_data + */ +visus::power_overwhelming::measurement_data::measurement_data( + _In_ const timestamp_type timestamp, + _In_ const value_type voltage, + _In_ const value_type current) + :_current(current), _power(invalid_value), _timestamp(timestamp), + _voltage(voltage) { + if (voltage == invalid_value) { + throw std::invalid_argument("A valid voltage measurement_data must be " + "specified."); + } + if (current == invalid_value) { + throw std::invalid_argument("A valid current measurement_data must be " + "specified."); + } +} + + +/* + * visus::power_overwhelming::measurement_data::measurement_data + */ +visus::power_overwhelming::measurement_data::measurement_data( + _In_ const timestamp_type timestamp, + _In_ const value_type power) + : _current(invalid_value), _power(power), _timestamp(timestamp), + _voltage(invalid_value) { + if (power == invalid_value) { + throw std::invalid_argument("A valid power measurement_data must be " + "specified."); + } +} + + +/* + * visus::power_overwhelming::measurement_data::operator = + */ +visus::power_overwhelming::measurement_data& +visus::power_overwhelming::measurement_data::operator =( + measurement_data&& rhs) noexcept { + if (this != std::addressof(rhs)) { + this->_current = rhs._current; + rhs._current = invalid_value; + this->_power = rhs._power; + rhs._power = invalid_value; + this->_timestamp = rhs._timestamp; + rhs._timestamp = 0; + this->_voltage = rhs._voltage; + rhs._voltage = invalid_value; + } + + return *this; +} + + +/* + * visus::power_overwhelming::measurement_data::operator bool + */ +visus::power_overwhelming::measurement_data::operator bool(void) const noexcept { + auto isPowerValid = (this->_power != invalid_value); + auto isSeparateValid = (this->_current != invalid_value) + && (this->_voltage != invalid_value); + return (isPowerValid || isSeparateValid); +} diff --git a/power_overwhelming/src/msr_sampler_context.cpp b/power_overwhelming/src/msr_sampler_context.cpp index 798d2e47..968c82a7 100644 --- a/power_overwhelming/src/msr_sampler_context.cpp +++ b/power_overwhelming/src/msr_sampler_context.cpp @@ -97,7 +97,9 @@ void visus::power_overwhelming::detail::msr_sampler_context::sample(void) { for (auto s : sensors) { auto sensor = s.first; - s.second.callback(sensor->sample(s.second.resolution), + // TODO + s.second.callback(measurement(s.first->sensor_name.c_str(), + sensor->sample(s.second.resolution)), s.second.context); } diff --git a/power_overwhelming/src/msr_sensor.cpp b/power_overwhelming/src/msr_sensor.cpp index db8890c1..140a9736 100644 --- a/power_overwhelming/src/msr_sensor.cpp +++ b/power_overwhelming/src/msr_sensor.cpp @@ -166,17 +166,6 @@ const wchar_t *visus::power_overwhelming::msr_sensor::name( } -/* - * visus::power_overwhelming::msr_sensor::sample - */ -visus::power_overwhelming::measurement -visus::power_overwhelming::msr_sensor::sample( - _In_ const timestamp_resolution resolution) const { - this->check_not_disposed(); - return this->_impl->sample(resolution); -} - - /* * visus::power_overwhelming::msr_sensor::sample */ @@ -227,3 +216,14 @@ visus::power_overwhelming::msr_sensor::operator bool(void) const noexcept { return ((this->_impl != nullptr) && (this->_impl->device != nullptr) && *this->_impl->device); } + + +/* + * visus::power_overwhelming::msr_sensor::sample_sync + */ +visus::power_overwhelming::measurement_data +visus::power_overwhelming::msr_sensor::sample_sync( + _In_ const timestamp_resolution resolution) const { + this->check_not_disposed(); + return this->_impl->sample(resolution); +} diff --git a/power_overwhelming/src/msr_sensor_impl.cpp b/power_overwhelming/src/msr_sensor_impl.cpp index 9254b0f2..160bd546 100644 --- a/power_overwhelming/src/msr_sensor_impl.cpp +++ b/power_overwhelming/src/msr_sensor_impl.cpp @@ -132,11 +132,11 @@ void visus::power_overwhelming::detail::msr_sensor_impl::sample(void) { /* * visus::power_overwhelming::detail::msr_sensor_impl::sample */ -visus::power_overwhelming::measurement +visus::power_overwhelming::measurement_data visus::power_overwhelming::detail::msr_sensor_impl::sample( _In_ const timestamp_resolution resolution) const { assert(this->device != nullptr); - typedef std::chrono::duration seconds_type; + typedef std::chrono::duration seconds_type; // Obtain new readings. const auto value = this->device->read(this->offset); @@ -145,7 +145,7 @@ visus::power_overwhelming::detail::msr_sensor_impl::sample( // Compute the difference and convert it to Joules by applying the // divisor obtained during initialisation. const auto dv = value - this->last_sample; - auto sample_value = static_cast(dv) + auto sample_value = static_cast(dv) / this->unit_divisor; // Compute the time elapsed since the last call to the method. We use that @@ -160,7 +160,7 @@ visus::power_overwhelming::detail::msr_sensor_impl::sample( this->last_sample = value; this->last_time = now; - return measurement(this->sensor_name.c_str(), timestamp, sample_value); + return measurement_data(timestamp, sample_value); } diff --git a/power_overwhelming/src/msr_sensor_impl.h b/power_overwhelming/src/msr_sensor_impl.h index 1f1e71c7..604f0c4a 100644 --- a/power_overwhelming/src/msr_sensor_impl.h +++ b/power_overwhelming/src/msr_sensor_impl.h @@ -127,7 +127,7 @@ namespace detail { /// The resolution of the timestamp being /// created. /// The result of the measurement. - measurement sample(_In_ const timestamp_resolution resolution) const; + measurement_data sample(_In_ const timestamp_resolution resolution) const; /// /// Sets the initial parameters. diff --git a/power_overwhelming/src/nvml_sensor.cpp b/power_overwhelming/src/nvml_sensor.cpp index cd29b6fb..755c37fc 100644 --- a/power_overwhelming/src/nvml_sensor.cpp +++ b/power_overwhelming/src/nvml_sensor.cpp @@ -202,17 +202,6 @@ _Ret_maybenull_z_ const wchar_t *visus::power_overwhelming::nvml_sensor::name( } -/* - * visus::power_overwhelming::nvml_sensor::sample - */ -visus::power_overwhelming::measurement -visus::power_overwhelming::nvml_sensor::sample( - _In_ const timestamp_resolution resolution) const { - this->check_not_disposed(); - return this->_impl->sample(resolution); -} - - /* * visus::power_overwhelming::nvml_sensor::sample */ @@ -259,3 +248,14 @@ visus::power_overwhelming::nvml_sensor::operator =( visus::power_overwhelming::nvml_sensor::operator bool(void) const noexcept { return (this->_impl != nullptr); } + + +/* + * visus::power_overwhelming::nvml_sensor::sample_sync + */ +visus::power_overwhelming::measurement_data +visus::power_overwhelming::nvml_sensor::sample_sync( + _In_ const timestamp_resolution resolution) const { + this->check_not_disposed(); + return this->_impl->sample(resolution); +} diff --git a/power_overwhelming/src/nvml_sensor_impl.cpp b/power_overwhelming/src/nvml_sensor_impl.cpp index a16988f0..2d69ab74 100644 --- a/power_overwhelming/src/nvml_sensor_impl.cpp +++ b/power_overwhelming/src/nvml_sensor_impl.cpp @@ -80,10 +80,10 @@ void visus::power_overwhelming::detail::nvml_sensor_impl::load_device_name( /* * visus::power_overwhelming::detail::nvml_sensor_impl::sample */ -visus::power_overwhelming::measurement +visus::power_overwhelming::measurement_data visus::power_overwhelming::detail::nvml_sensor_impl::sample( const timestamp_resolution resolution) const { - static constexpr auto thousand = static_cast(1000); + static constexpr auto thousand = static_cast(1000); const auto timestamp = create_timestamp(resolution); // Get the power usage in milliwatts. @@ -94,6 +94,6 @@ visus::power_overwhelming::detail::nvml_sensor_impl::sample( throw nvml_exception(status); } - return measurement(this->sensor_name.c_str(), timestamp, - static_cast(mw) / thousand); + return measurement_data(timestamp, + static_cast(mw) / thousand); } diff --git a/power_overwhelming/src/nvml_sensor_impl.h b/power_overwhelming/src/nvml_sensor_impl.h index db249f3a..6fbbeb45 100644 --- a/power_overwhelming/src/nvml_sensor_impl.h +++ b/power_overwhelming/src/nvml_sensor_impl.h @@ -79,7 +79,7 @@ namespace detail { /// The resolution of the timestamp to be /// generated, which defaults to milliseconds. /// A measurement from the sensor. - measurement sample(const timestamp_resolution resolution + measurement_data sample(const timestamp_resolution resolution = timestamp_resolution::milliseconds) const; }; diff --git a/power_overwhelming/src/rtb_sensor.cpp b/power_overwhelming/src/rtb_sensor.cpp index 1b02b7c0..e4916de8 100644 --- a/power_overwhelming/src/rtb_sensor.cpp +++ b/power_overwhelming/src/rtb_sensor.cpp @@ -162,16 +162,6 @@ void visus::power_overwhelming::rtb_sensor::expression( } -/* - * visus::power_overwhelming::rtb_sensor::sample - */ -visus::power_overwhelming::measurement -visus::power_overwhelming::rtb_sensor::sample( - _In_ const timestamp_resolution resolution) const { - throw "TODO"; -} - - /* * visus::power_overwhelming::rtb_sensor::unit */ @@ -187,6 +177,16 @@ void visus::power_overwhelming::rtb_sensor::unit( } +/* + * visus::power_overwhelming::rtb_sensor::sample_sync + */ +visus::power_overwhelming::measurement_data +visus::power_overwhelming::rtb_sensor::sample_sync( + _In_ const timestamp_resolution resolution) const { + throw "TODO"; + +} + // TIM:SCAL 5 //CHAN2:STAT OFF diff --git a/power_overwhelming/src/sensor.cpp b/power_overwhelming/src/sensor.cpp index 793480b9..8680b71e 100644 --- a/power_overwhelming/src/sensor.cpp +++ b/power_overwhelming/src/sensor.cpp @@ -1,11 +1,23 @@ -// -// Copyright © 2021 Visualisierungsinstitut der Universität Stuttgart. Alle Rechte vorbehalten. +// +// Copyright © 2021 -2023 Visualisierungsinstitut der Universität Stuttgart. Alle Rechte vorbehalten. // // Christoph Müller #include "power_overwhelming/sensor.h" +/* + * visus::power_overwhelming::sensor::sample + */ +visus::power_overwhelming::measurement +visus::power_overwhelming::sensor::sample( + _In_ const timestamp_resolution resolution) const { + auto name = this->name(); + _Analysis_assume_(name != nullptr); + return measurement(name, this->sample_sync(resolution)); +} + + /* * visus::power_overwhelming::sensor::check_not_disposed */ diff --git a/power_overwhelming/src/tinkerforge_sensor.cpp b/power_overwhelming/src/tinkerforge_sensor.cpp index eaefd4e6..e01eb4d7 100644 --- a/power_overwhelming/src/tinkerforge_sensor.cpp +++ b/power_overwhelming/src/tinkerforge_sensor.cpp @@ -290,54 +290,6 @@ void visus::power_overwhelming::tinkerforge_sensor::reset(void) { } -/* - * visus::power_overwhelming::tinkerforge_sensor::sample - */ -visus::power_overwhelming::measurement -visus::power_overwhelming::tinkerforge_sensor::sample( - _In_ const timestamp_resolution resolution) const { - if (!*this) { - throw std::runtime_error("A disposed instance of tinkerforge_sensor " - "cannot be sampled."); - } - - static const auto thousand = static_cast(1000); - std::int32_t current = 0; // Current in mA. - std::int32_t power = 0; // Power in mW. - std::int32_t voltage = 0; // Voltage in mV. - - { - auto status = ::voltage_current_v2_get_voltage(&this->_impl->bricklet, - &voltage); - if (status < 0) { - throw tinkerforge_exception(status); - } - } - - { - auto status = ::voltage_current_v2_get_current(&this->_impl->bricklet, - &voltage); - if (status < 0) { - throw tinkerforge_exception(status); - } - } - - { - auto status = ::voltage_current_v2_get_power(&this->_impl->bricklet, - &power); - if (status < 0) { - throw tinkerforge_exception(status); - } - } - - return measurement(this->_impl->sensor_name.c_str(), - detail::create_timestamp(resolution), - static_cast(voltage) / thousand, - static_cast(current) / thousand, - static_cast(power) / thousand); -} - - /* * visus::power_overwhelming::tinkerforge_sensor::sample */ @@ -428,3 +380,47 @@ visus::power_overwhelming::tinkerforge_sensor::operator bool( void) const noexcept { return (this->_impl != nullptr); } + + +/* + * visus::power_overwhelming::tinkerforge_sensor::sample_sync + */ +visus::power_overwhelming::measurement_data +visus::power_overwhelming::tinkerforge_sensor::sample_sync( + _In_ const timestamp_resolution resolution) const { + this->check_not_disposed(); + + static const auto thousand = static_cast(1000); + std::int32_t current = 0; // Current in mA. + std::int32_t power = 0; // Power in mW. + std::int32_t voltage = 0; // Voltage in mV. + + { + auto status = ::voltage_current_v2_get_voltage(&this->_impl->bricklet, + &voltage); + if (status < 0) { + throw tinkerforge_exception(status); + } + } + + { + auto status = ::voltage_current_v2_get_current(&this->_impl->bricklet, + &voltage); + if (status < 0) { + throw tinkerforge_exception(status); + } + } + + { + auto status = ::voltage_current_v2_get_power(&this->_impl->bricklet, + &power); + if (status < 0) { + throw tinkerforge_exception(status); + } + } + + return measurement_data(detail::create_timestamp(resolution), + static_cast(voltage) / thousand, + static_cast(current) / thousand, + static_cast(power) / thousand); +} diff --git a/test/measurement_data_test.cpp b/test/measurement_data_test.cpp new file mode 100644 index 00000000..104494f0 --- /dev/null +++ b/test/measurement_data_test.cpp @@ -0,0 +1,93 @@ +// +// Copyright © 2023 Visualisierungsinstitut der Universität Stuttgart. Alle Rechte vorbehalten. +// +// Christoph Müller + +#include "pch.h" +#include "CppUnitTest.h" + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + + +namespace visus { +namespace power_overwhelming { +namespace test { + + TEST_CLASS(measurement_data_test) { + + public: + + TEST_METHOD(test_construction) { + { + auto m = measurement_data(42, 2.0f, 3.0f, 6.1f); + Assert::AreEqual(2.0f, m.voltage(), L"voltage", LINE_INFO()); + Assert::AreEqual(3.0f, m.current(), L"current", LINE_INFO()); + Assert::AreEqual(6.1f, m.power(), L"power", LINE_INFO()); + Assert::AreEqual(std::int64_t(42), m.timestamp(), L"timestamp", LINE_INFO()); + Assert::IsTrue(m, L"operator bool", LINE_INFO()); + } + + { + auto m = measurement_data(42, 2.0f, 3.0f); + Assert::AreEqual(2.0f, m.voltage(), L"voltage", LINE_INFO()); + Assert::AreEqual(3.0f, m.current(), L"current", LINE_INFO()); + Assert::AreEqual(6.0f, m.power(), L"power", LINE_INFO()); + Assert::AreEqual(std::int64_t(42), m.timestamp(), L"timestamp", LINE_INFO()); + Assert::IsTrue(m, L"operator bool", LINE_INFO()); + } + + { + auto m = measurement_data(42, 2.0f); + Assert::AreEqual(measurement_data::invalid_value, m.voltage(), L"voltage", LINE_INFO()); + Assert::AreEqual(measurement_data::invalid_value, m.current(), L"current", LINE_INFO()); + Assert::AreEqual(2.0f, m.power(), L"power", LINE_INFO()); + Assert::AreEqual(std::int64_t(42), m.timestamp(), L"timestamp", LINE_INFO()); + Assert::IsTrue(m, L"operator bool", LINE_INFO()); + } + + Assert::ExpectException([](void) { + auto m = measurement_data(42, measurement_data::invalid_value, 3.0f); + }); + + Assert::ExpectException([](void) { + auto m = measurement_data(42, 2.0f, measurement_data::invalid_value); + }); + + Assert::ExpectException([](void) { + auto m = measurement_data(42, measurement_data::invalid_value); + }); + } + + TEST_METHOD(test_copy) { + { + auto m = measurement_data(42, 2.0f, 3.0f, 6.1f); + auto n = m; + + Assert::AreEqual(m.voltage(), n.voltage(), L"voltage", LINE_INFO()); + Assert::AreEqual(m.current(), n.current(), L"current", LINE_INFO()); + Assert::AreEqual(m.power(), n.power(), L"power", LINE_INFO()); + Assert::AreEqual(m.timestamp(), n.timestamp(), L"timestamp", LINE_INFO()); + Assert::IsTrue(m, L"source operator bool", LINE_INFO()); + Assert::IsTrue(n, L"destination operator bool", LINE_INFO()); + } + + { + auto m = measurement_data(42, 2.0f, 3.0f, 6.1f); + auto n = std::move(m); + + Assert::AreEqual(measurement_data::invalid_value, m.voltage(), L"voltage", LINE_INFO()); + Assert::AreEqual(measurement_data::invalid_value, m.current(), L"current", LINE_INFO()); + Assert::AreEqual(std::int64_t(0), m.timestamp(), L"timestamp", LINE_INFO()); + Assert::IsFalse(m, L"source operator bool", LINE_INFO()); + + Assert::AreEqual(2.0f, n.voltage(), L"voltage", LINE_INFO()); + Assert::AreEqual(3.0f, n.current(), L"current", LINE_INFO()); + Assert::AreEqual(6.1f, n.power(), L"power", LINE_INFO()); + Assert::AreEqual(std::int64_t(42), n.timestamp(), L"timestamp", LINE_INFO()); + Assert::IsTrue(n, L"destination operator bool", LINE_INFO()); + } + } + }; +} /* namespace test */ +} /* namespace power_overwhelming */ +} /* namespace visus */ diff --git a/test/pch.h b/test/pch.h index 86fd851c..825e49ce 100644 --- a/test/pch.h +++ b/test/pch.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include