diff options
Diffstat (limited to 'tests/framework/instruments')
-rw-r--r-- | tests/framework/instruments/Instrument.h | 27 | ||||
-rw-r--r-- | tests/framework/instruments/Instruments.cpp | 5 | ||||
-rw-r--r-- | tests/framework/instruments/Instruments.h | 29 | ||||
-rw-r--r-- | tests/framework/instruments/Measurement.h | 102 | ||||
-rw-r--r-- | tests/framework/instruments/PMU.cpp | 99 | ||||
-rw-r--r-- | tests/framework/instruments/PMU.h | 96 | ||||
-rw-r--r-- | tests/framework/instruments/PMUCounter.cpp | 118 | ||||
-rw-r--r-- | tests/framework/instruments/PMUCounter.h | 33 | ||||
-rw-r--r-- | tests/framework/instruments/WallClockTimer.cpp | 4 | ||||
-rw-r--r-- | tests/framework/instruments/WallClockTimer.h | 8 |
10 files changed, 352 insertions, 169 deletions
diff --git a/tests/framework/instruments/Instrument.h b/tests/framework/instruments/Instrument.h index 895a64738c..560bdf6a35 100644 --- a/tests/framework/instruments/Instrument.h +++ b/tests/framework/instruments/Instrument.h @@ -25,9 +25,10 @@ #define ARM_COMPUTE_TEST_INSTRUMENT #include "../Utils.h" +#include "Measurement.h" +#include <map> #include <memory> -#include <ostream> #include <string> namespace arm_compute @@ -47,20 +48,6 @@ public: template <typename T> static std::unique_ptr<Instrument> make_instrument(); - /** Struct representing measurement consisting of value and unit. */ - struct Measurement final - { - Measurement(double value, std::string unit) - : value{ value }, unit{ std::move(unit) } - { - } - - friend std::ostream &operator<<(std::ostream &os, const Measurement &measurement); - - double value; - std::string unit; - }; - Instrument() = default; Instrument(const Instrument &) = default; Instrument(Instrument &&) = default; @@ -77,16 +64,12 @@ public: /** Stop measuring. */ virtual void stop() = 0; + using MeasurementsMap = std::map<std::string, Measurement>; + /** Return the latest measurement. */ - virtual Measurement measurement() const = 0; + virtual MeasurementsMap measurements() const = 0; }; -inline std::ostream &operator<<(std::ostream &os, const Instrument::Measurement &measurement) -{ - os << measurement.value << measurement.unit; - return os; -} - template <typename T> inline std::unique_ptr<Instrument> Instrument::make_instrument() { diff --git a/tests/framework/instruments/Instruments.cpp b/tests/framework/instruments/Instruments.cpp index 797a7242ae..699a11d700 100644 --- a/tests/framework/instruments/Instruments.cpp +++ b/tests/framework/instruments/Instruments.cpp @@ -41,8 +41,9 @@ InstrumentType instrument_type_from_name(const std::string &name) { "all", InstrumentType::ALL }, { "none", InstrumentType::NONE }, { "wall_clock", InstrumentType::WALL_CLOCK_TIMER }, - { "cycles", InstrumentType::PMU_CYCLE_COUNTER }, - { "instructions", InstrumentType::PMU_INSTRUCTION_COUNTER }, + { "pmu", InstrumentType::PMU }, + { "pmu_cycles", InstrumentType::PMU_CYCLE_COUNTER }, + { "pmu_instructions", InstrumentType::PMU_INSTRUCTION_COUNTER }, }; try diff --git a/tests/framework/instruments/Instruments.h b/tests/framework/instruments/Instruments.h index 034fa168f5..aa37f9cf62 100644 --- a/tests/framework/instruments/Instruments.h +++ b/tests/framework/instruments/Instruments.h @@ -40,32 +40,14 @@ enum class InstrumentType : unsigned int { ALL = ~0U, NONE = 0, - WALL_CLOCK_TIMER = 1, - PMU_CYCLE_COUNTER = 2, - PMU_INSTRUCTION_COUNTER = 4 + WALL_CLOCK_TIMER = 0x0100, + PMU = 0x0200, + PMU_CYCLE_COUNTER = 0x0201, + PMU_INSTRUCTION_COUNTER = 0x0202, }; InstrumentType instrument_type_from_name(const std::string &name); -inline InstrumentType operator&(InstrumentType t1, InstrumentType t2) -{ - using type = std::underlying_type<InstrumentType>::type; - return static_cast<InstrumentType>(static_cast<type>(t1) & static_cast<type>(t2)); -} - -inline InstrumentType operator|(InstrumentType t1, InstrumentType t2) -{ - using type = std::underlying_type<InstrumentType>::type; - return static_cast<InstrumentType>(static_cast<type>(t1) | static_cast<type>(t2)); -} - -inline InstrumentType &operator|=(InstrumentType &t1, InstrumentType t2) -{ - using type = std::underlying_type<InstrumentType>::type; - t1 = static_cast<InstrumentType>(static_cast<type>(t1) | static_cast<type>(t2)); - return t1; -} - inline ::std::stringstream &operator>>(::std::stringstream &stream, InstrumentType &instrument) { std::string value; @@ -81,6 +63,9 @@ inline ::std::stringstream &operator<<(::std::stringstream &stream, InstrumentTy case InstrumentType::WALL_CLOCK_TIMER: stream << "WALL_CLOCK_TIMER"; break; + case InstrumentType::PMU: + stream << "PMU"; + break; case InstrumentType::PMU_CYCLE_COUNTER: stream << "PMU_CYCLE_COUNTER"; break; diff --git a/tests/framework/instruments/Measurement.h b/tests/framework/instruments/Measurement.h new file mode 100644 index 0000000000..32874e0a6a --- /dev/null +++ b/tests/framework/instruments/Measurement.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2017 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * 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 ARM_COMPUTE_TEST_MEASUREMENT +#define ARM_COMPUTE_TEST_MEASUREMENT + +#include "../Utils.h" + +#include <ostream> +#include <string> + +namespace arm_compute +{ +namespace test +{ +namespace framework +{ +/** Abstract measurement. + * + * Every measurement needs to define it's unit. + */ +struct IMeasurement +{ + /** Constructor. + * + * @param[in] unit Unit of the measurement. + */ + explicit IMeasurement(std::string unit) + : unit{ std::move(unit) } + { + } + + const std::string unit; +}; + +/** Meaurement of a specific type. */ +template <typename T> +struct TypedMeasurement : public IMeasurement +{ + /** Constructor. + * + * @param[in] value Measured value. + * @param[in] unit Unit of the Measurement. + */ + TypedMeasurement(T value, std::string unit) + : IMeasurement(std::move(unit)), value{ value } + { + } + + T value; +}; + +/** Stream output operator to print the measurement. + * + * Prints value and unit. + */ +template <typename T> +inline std::ostream &operator<<(std::ostream &os, const TypedMeasurement<T> &measurement) +{ + os << measurement.value << measurement.unit; + return os; +} + +/** Generic measurement that stores values as double. */ +struct Measurement : public TypedMeasurement<double> +{ + using TypedMeasurement::TypedMeasurement; + + /** Conversion constructor. + * + * @param[in] measurement Typed measurement. + */ + template <typename T> + Measurement(TypedMeasurement<T> measurement) + : Measurement(measurement.value, measurement.unit) + { + } +}; +} // namespace framework +} // namespace test +} // namespace arm_compute +#endif /* ARM_COMPUTE_TEST_MEASUREMENT */ diff --git a/tests/framework/instruments/PMU.cpp b/tests/framework/instruments/PMU.cpp new file mode 100644 index 0000000000..0594e96cb2 --- /dev/null +++ b/tests/framework/instruments/PMU.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * 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. + */ +#include "PMU.h" + +#include <asm/unistd.h> +#include <cstring> +#include <stdexcept> +#include <sys/ioctl.h> + +namespace arm_compute +{ +namespace test +{ +namespace framework +{ +PMU::PMU() + : _perf_config() +{ + _perf_config.type = PERF_TYPE_HARDWARE; + _perf_config.size = sizeof(perf_event_attr); + + // Start disabled + _perf_config.disabled = 1; + // The inherit bit specifies that this counter should count events of child + // tasks as well as the task specified + _perf_config.inherit = 1; + // Enables saving of event counts on context switch for inherited tasks + _perf_config.inherit_stat = 1; +} + +PMU::PMU(uint64_t config) + : PMU() +{ + open(config); +} + +PMU::~PMU() +{ + close(); +} + +void PMU::open(uint64_t config) +{ + _perf_config.config = config; + open(_perf_config); +} + +void PMU::open(const perf_event_attr &perf_config) +{ + // Measure this process/thread (+ children) on any CPU + _fd = syscall(__NR_perf_event_open, &perf_config, 0, -1, -1, 0); + + ARM_COMPUTE_ERROR_ON_MSG(_fd < 0, "perf_event_open failed"); + + const int result = ioctl(_fd, PERF_EVENT_IOC_ENABLE, 0); + + ARM_COMPUTE_ERROR_ON_MSG(result == -1, "Failed to enable PMU counter: %d", errno); + ARM_COMPUTE_UNUSED(result); +} + +void PMU::close() +{ + if(_fd != -1) + { + ::close(_fd); + _fd = -1; + } +} + +void PMU::reset() +{ + const int result = ioctl(_fd, PERF_EVENT_IOC_RESET, 0); + ARM_COMPUTE_ERROR_ON_MSG(result == -1, "Failed to reset PMU counter: %d", errno); + ARM_COMPUTE_UNUSED(result); +} +} // namespace framework +} // namespace test +} // namespace arm_compute diff --git a/tests/framework/instruments/PMU.h b/tests/framework/instruments/PMU.h new file mode 100644 index 0000000000..571edb984d --- /dev/null +++ b/tests/framework/instruments/PMU.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2017 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * 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 ARM_COMPUTE_TEST_PMU +#define ARM_COMPUTE_TEST_PMU + +#include "arm_compute/core/Error.h" + +#include <cstdint> +#include <linux/perf_event.h> +#include <stdexcept> +#include <unistd.h> + +namespace arm_compute +{ +namespace test +{ +namespace framework +{ +/** Class provides access to CPU hardware counters. */ +class PMU +{ +public: + /** Default constructor. */ + PMU(); + + /** Create PMU with specified counter. + * + * This constructor automatically calls @ref open with the default + * configuration. + * + * @param[in] config Counter identifier. + */ + explicit PMU(uint64_t config); + + /** Default destructor. */ + ~PMU(); + + /** Get the counter value. + * + * @return Counter value casted to the specified type. */ + template <typename T> + T get_value() const; + + /** Open the specified counter based on the default configuration. */ + void open(uint64_t config); + + /** Open the specified configuration. */ + void open(const perf_event_attr &perf_config); + + /** Close the currently open counter. */ + void close(); + + /** Reset counter. */ + void reset(); + +private: + perf_event_attr _perf_config; + long _fd{ -1 }; +}; + +template <typename T> +T PMU::get_value() const +{ + T value{}; + const ssize_t result = read(_fd, &value, sizeof(T)); + + ARM_COMPUTE_ERROR_ON_MSG(result == -1, "Can't get PMU counter value: %d", errno); + ARM_COMPUTE_UNUSED(result); + + return value; +} +} // namespace framework +} // namespace test +} // namespace arm_compute +#endif /* ARM_COMPUTE_TEST_PMU */ diff --git a/tests/framework/instruments/PMUCounter.cpp b/tests/framework/instruments/PMUCounter.cpp index 7994a15862..b962bd9b2b 100644 --- a/tests/framework/instruments/PMUCounter.cpp +++ b/tests/framework/instruments/PMUCounter.cpp @@ -23,117 +23,51 @@ */ #include "PMUCounter.h" -#define _GNU_SOURCE 1 -#include <asm/unistd.h> -#include <csignal> -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include <fcntl.h> -#include <linux/hw_breakpoint.h> -#include <linux/perf_event.h> -#include <sys/ioctl.h> -#include <unistd.h> -#undef _GNU_SOURCE - -#include <stdexcept> - namespace arm_compute { namespace test { namespace framework { -CycleCounter::CycleCounter() -{ - const pid_t pid = getpid(); - - struct perf_event_attr perf_config; //NOLINT - memset(&perf_config, 0, sizeof(struct perf_event_attr)); - - perf_config.config = PERF_COUNT_HW_CPU_CYCLES; - perf_config.size = sizeof(struct perf_event_attr); - perf_config.type = PERF_TYPE_HARDWARE; - // The inherit bit specifies that this counter should count events of child - // tasks as well as the task specified - perf_config.inherit = 1; - // Enables saving of event counts on context switch for inherited tasks - perf_config.inherit_stat = 1; - - _fd = syscall(__NR_perf_event_open, &perf_config, pid, -1, -1, 0); - - if(_fd < 0) - { - throw std::runtime_error("perf_event_open for cycles failed"); - } -} - -std::string CycleCounter::id() const -{ - return "Cycle Counter"; -} - -void CycleCounter::start() +std::string PMUCounter::id() const { - ioctl(_fd, PERF_EVENT_IOC_RESET, 0); - ioctl(_fd, PERF_EVENT_IOC_ENABLE, 0); + return "PMU Counter"; } -void CycleCounter::stop() +void PMUCounter::start() { - ioctl(_fd, PERF_EVENT_IOC_DISABLE, 0); - read(_fd, &_cycles, sizeof(_cycles)); + _pmu_cycles.reset(); + _pmu_instructions.reset(); } -Instrument::Measurement CycleCounter::measurement() const +void PMUCounter::stop() { - return Measurement(_cycles, "cycles"); -} - -InstructionCounter::InstructionCounter() -{ - const pid_t pid = getpid(); - - struct perf_event_attr perf_config; //NOLINT - memset(&perf_config, 0, sizeof(struct perf_event_attr)); - - perf_config.config = PERF_COUNT_HW_INSTRUCTIONS; - perf_config.size = sizeof(struct perf_event_attr); - perf_config.type = PERF_TYPE_HARDWARE; - // The inherit bit specifies that this counter should count events of child - // tasks as well as the task specified - perf_config.inherit = 1; - // Enables saving of event counts on context switch for inherited tasks - perf_config.inherit_stat = 1; - - _fd = syscall(__NR_perf_event_open, &perf_config, pid, -1, -1, 0); - - if(_fd < 0) + try { - throw std::runtime_error("perf_event_open for instructions failed"); + _cycles = _pmu_cycles.get_value<long long>(); + } + catch(const std::runtime_error &) + { + _cycles = 0; } -} - -std::string InstructionCounter::id() const -{ - return "Instruction Counter"; -} - -void InstructionCounter::start() -{ - ioctl(_fd, PERF_EVENT_IOC_RESET, 0); - ioctl(_fd, PERF_EVENT_IOC_ENABLE, 0); -} -void InstructionCounter::stop() -{ - ioctl(_fd, PERF_EVENT_IOC_DISABLE, 0); - read(_fd, &_instructions, sizeof(_instructions)); + try + { + _instructions = _pmu_instructions.get_value<long long>(); + } + catch(const std::runtime_error &) + { + _instructions = 0; + } } -Instrument::Measurement InstructionCounter::measurement() const +Instrument::MeasurementsMap PMUCounter::measurements() const { - return Measurement(_instructions, "instructions"); + return MeasurementsMap + { + { "CPU cycles", Measurement(_cycles, "cycles") }, + { "CPU instructions", Measurement(_instructions, "instructions") }, + }; } } // namespace framework } // namespace test diff --git a/tests/framework/instruments/PMUCounter.h b/tests/framework/instruments/PMUCounter.h index f407be602f..7beb6d931d 100644 --- a/tests/framework/instruments/PMUCounter.h +++ b/tests/framework/instruments/PMUCounter.h @@ -25,6 +25,7 @@ #define ARM_COMPUTE_TEST_PMU_COUNTER #include "Instrument.h" +#include "PMU.h" namespace arm_compute { @@ -33,36 +34,18 @@ namespace test namespace framework { /** Implementation of an instrument to count CPU cycles. */ -class CycleCounter : public Instrument +class PMUCounter : public Instrument { public: - /** Initialise the cycle counter. */ - CycleCounter(); - - std::string id() const override; - void start() override; - void stop() override; - Measurement measurement() const override; + std::string id() const override; + void start() override; + void stop() override; + MeasurementsMap measurements() const override; private: - long _fd{ -1 }; + PMU _pmu_cycles{ PERF_COUNT_HW_CPU_CYCLES }; + PMU _pmu_instructions{ PERF_COUNT_HW_INSTRUCTIONS }; long long _cycles{ 0 }; -}; - -/** Implementation of an instrument to count executed CPU instructions. */ -class InstructionCounter : public Instrument -{ -public: - /** Initialise the instruction counter. */ - InstructionCounter(); - - std::string id() const override; - void start() override; - void stop() override; - Measurement measurement() const override; - -private: - long _fd{ -1 }; long long _instructions{ 0 }; }; } // namespace framework diff --git a/tests/framework/instruments/WallClockTimer.cpp b/tests/framework/instruments/WallClockTimer.cpp index 37db0c7f05..c6384a3ab5 100644 --- a/tests/framework/instruments/WallClockTimer.cpp +++ b/tests/framework/instruments/WallClockTimer.cpp @@ -47,10 +47,10 @@ void WallClockTimer::stop() _stop = std::chrono::high_resolution_clock::now(); } -Instrument::Measurement WallClockTimer::measurement() const +Instrument::MeasurementsMap WallClockTimer::measurements() const { const auto delta = std::chrono::duration_cast<std::chrono::microseconds>(_stop - _start); - return Instrument::Measurement(delta.count(), "us"); + return MeasurementsMap{ { "Wall clock time", Measurement(delta.count(), "us") } }; } } // namespace framework } // namespace test diff --git a/tests/framework/instruments/WallClockTimer.h b/tests/framework/instruments/WallClockTimer.h index b7c390f691..fd2b18c3fb 100644 --- a/tests/framework/instruments/WallClockTimer.h +++ b/tests/framework/instruments/WallClockTimer.h @@ -38,10 +38,10 @@ namespace framework class WallClockTimer : public Instrument { public: - std::string id() const override; - void start() override; - void stop() override; - Measurement measurement() const override; + std::string id() const override; + void start() override; + void stop() override; + MeasurementsMap measurements() const override; private: std::chrono::high_resolution_clock::time_point _start{}; |