diff options
author | Moritz Pflanzer <moritz.pflanzer@arm.com> | 2017-07-05 11:02:23 +0100 |
---|---|---|
committer | Anthony Barbier <anthony.barbier@arm.com> | 2018-09-17 14:15:39 +0100 |
commit | a4f711b0fa38aecf0aacdbf61acf86bd25aa674a (patch) | |
tree | 6efb1362fc8ebb50f43095484b6cc42e8394e7f6 | |
parent | 69e44dc073bae7f7f54923d306a52d809b1334d5 (diff) | |
download | ComputeLibrary-a4f711b0fa38aecf0aacdbf61acf86bd25aa674a.tar.gz |
COMPMID-415: New framework - instruments [3/5]
Change-Id: I834c2693566185ce8d8d024fb5db79610a18c8c1
Reviewed-on: http://mpd-gerrit.cambridge.arm.com/79757
Reviewed-by: Anthony Barbier <anthony.barbier@arm.com>
Tested-by: Kaizen <jeremy.johnson+kaizengerrit@arm.com>
-rw-r--r-- | framework/Framework.cpp | 52 | ||||
-rw-r--r-- | framework/Framework.h | 30 | ||||
-rw-r--r-- | framework/Profiler.cpp | 67 | ||||
-rw-r--r-- | framework/Profiler.h | 75 | ||||
-rw-r--r-- | framework/TestResult.h | 15 | ||||
-rw-r--r-- | framework/instruments/Instrument.h | 98 | ||||
-rw-r--r-- | framework/instruments/Instruments.cpp | 57 | ||||
-rw-r--r-- | framework/instruments/Instruments.h | 105 | ||||
-rw-r--r-- | framework/instruments/PMUCounter.cpp | 140 | ||||
-rw-r--r-- | framework/instruments/PMUCounter.h | 71 | ||||
-rw-r--r-- | framework/instruments/WallClockTimer.cpp | 57 | ||||
-rw-r--r-- | framework/instruments/WallClockTimer.h | 53 |
12 files changed, 813 insertions, 7 deletions
diff --git a/framework/Framework.cpp b/framework/Framework.cpp index b54c0c75b6..692e17cb91 100644 --- a/framework/Framework.cpp +++ b/framework/Framework.cpp @@ -37,6 +37,27 @@ namespace test { namespace framework { +Framework::Framework() +{ + _available_instruments.emplace(InstrumentType::WALL_CLOCK_TIMER, Instrument::make_instrument<WallClockTimer>); +#ifdef PMU_ENABLED + _available_instruments.emplace(InstrumentType::PMU_CYCLE_COUNTER, Instrument::make_instrument<CycleCounter>); + _available_instruments.emplace(InstrumentType::PMU_INSTRUCTION_COUNTER, Instrument::make_instrument<InstructionCounter>); +#endif /* PMU_ENABLED */ +} + +std::set<InstrumentType> Framework::available_instruments() const +{ + std::set<InstrumentType> types; + + for(const auto &instrument : _available_instruments) + { + types.emplace(instrument.first); + } + + return types; +} + std::tuple<int, int, int> Framework::count_test_results() const { int passed = 0; @@ -71,11 +92,18 @@ Framework &Framework::get() return instance; } -void Framework::init(int num_iterations, const std::string &name_filter, const std::string &id_filter) +void Framework::init(const std::vector<InstrumentType> &instruments, int num_iterations, const std::string &name_filter, const std::string &id_filter) { _test_name_filter = std::regex{ name_filter }; _test_id_filter = std::regex{ id_filter }; _num_iterations = num_iterations; + + _instruments = InstrumentType::NONE; + + for(const auto &instrument : instruments) + { + _instruments |= instrument; + } } std::string Framework::current_suite_name() const @@ -144,6 +172,7 @@ void Framework::run_test(TestCaseFactory &test_factory) log_test_start(test_case_name); + Profiler profiler = get_profiler(); TestResult result; try @@ -156,7 +185,9 @@ void Framework::run_test(TestCaseFactory &test_factory) for(int i = 0; i < _num_iterations; ++i) { + profiler.start(); test_case->do_run(); + profiler.stop(); } test_case->do_teardown(); @@ -213,6 +244,8 @@ void Framework::run_test(TestCaseFactory &test_factory) } } + result.measurements = profiler.measurements(); + set_test_result(test_case_name, result); log_test_end(test_case_name); } @@ -260,7 +293,22 @@ bool Framework::run() void Framework::set_test_result(std::string test_case_name, TestResult result) { - _test_results.emplace(std::move(test_case_name), result); + _test_results.emplace(std::move(test_case_name), std::move(result)); +} + +Profiler Framework::get_profiler() const +{ + Profiler profiler; + + for(const auto &instrument : _available_instruments) + { + if((instrument.first & _instruments) != InstrumentType::NONE) + { + profiler.add(instrument.second()); + } + } + + return profiler; } std::vector<Framework::TestId> Framework::test_ids() const diff --git a/framework/Framework.h b/framework/Framework.h index e9beafd6eb..fbc95badd6 100644 --- a/framework/Framework.h +++ b/framework/Framework.h @@ -24,10 +24,12 @@ #ifndef ARM_COMPUTE_TEST_FRAMEWORK #define ARM_COMPUTE_TEST_FRAMEWORK +#include "Profiler.h" #include "TestCase.h" #include "TestCaseFactory.h" #include "TestResult.h" #include "Utils.h" +#include "instruments/Instruments.h" #include <algorithm> #include <chrono> @@ -70,13 +72,20 @@ public: */ static Framework &get(); + /** Supported instrument types for benchmarking. + * + * @return Set of all available instrument types. + */ + std::set<InstrumentType> available_instruments() const; + /** Init the framework. * + * @param[in] instruments Instrument types that will be used for benchmarking. * @param[in] num_iterations Number of iterations per test. * @param[in] name_filter Regular expression to filter tests by name. Only matching tests will be executed. * @param[in] id_filter Regular expression to filter tests by id. Only matching tests will be executed. */ - void init(int num_iterations, const std::string &name_filter, const std::string &id_filter); + void init(const std::vector<InstrumentType> &instruments, int num_iterations, const std::string &name_filter, const std::string &id_filter); /** Add a new test suite. * @@ -181,6 +190,15 @@ public: */ void set_test_result(std::string test_case_name, TestResult result); + /** Factory method to obtain a configured profiler. + * + * The profiler enables all instruments that have been passed to the @ref + * init method. + * + * @return Configured profiler to collect benchmark results. + */ + Profiler get_profiler() const; + /** List of @ref TestId's. * * @return Vector with all test ids. @@ -188,7 +206,7 @@ public: std::vector<Framework::TestId> test_ids() const; private: - Framework() = default; + Framework(); ~Framework() = default; Framework(const Framework &) = delete; @@ -214,8 +232,12 @@ private: int _num_iterations{ 1 }; bool _throw_errors{ false }; - std::regex _test_name_filter{ ".*" }; - std::regex _test_id_filter{ ".*" }; + using create_function = std::unique_ptr<Instrument>(); + std::map<InstrumentType, create_function *> _available_instruments{}; + + InstrumentType _instruments{ InstrumentType::NONE }; + std::regex _test_name_filter{ ".*" }; + std::regex _test_id_filter{ ".*" }; }; template <typename T> diff --git a/framework/Profiler.cpp b/framework/Profiler.cpp new file mode 100644 index 0000000000..76de9a818f --- /dev/null +++ b/framework/Profiler.cpp @@ -0,0 +1,67 @@ +/* + * 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 "Profiler.h" + +#include <iostream> +#include <utility> + +namespace arm_compute +{ +namespace test +{ +namespace framework +{ +void Profiler::add(std::unique_ptr<Instrument> instrument) +{ + _instruments.emplace_back(std::move(instrument)); +} + +void Profiler::start() +{ + for(auto &instrument : _instruments) + { + instrument->start(); + } +} + +void Profiler::stop() +{ + for(auto &instrument : _instruments) + { + instrument->stop(); + } + + for(const auto &instrument : _instruments) + { + _measurements[instrument->id()].push_back(instrument->measurement()); + } +} + +const Profiler::MeasurementsMap &Profiler::measurements() const +{ + return _measurements; +} +} // namespace framework +} // namespace test +} // namespace arm_compute diff --git a/framework/Profiler.h b/framework/Profiler.h new file mode 100644 index 0000000000..1454c0f875 --- /dev/null +++ b/framework/Profiler.h @@ -0,0 +1,75 @@ +/* + * 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_PROFILER +#define ARM_COMPUTE_TEST_PROFILER + +#include "instruments/Instrument.h" + +#include <map> +#include <memory> +#include <string> +#include <vector> + +namespace arm_compute +{ +namespace test +{ +namespace framework +{ +/** Profiler class to collect benchmark numbers. + * + * A profiler manages multiple instruments that can collect different types of benchmarking numbers. + */ +class Profiler +{ +public: + /** Mapping from instrument ids to their measurements. */ + using MeasurementsMap = std::map<std::string, std::vector<Instrument::Measurement>>; + + /** Add @p instrument to the performance monitor. + * + * All added instruments will be used when @ref start or @ref stop are + * called to make measurements. + * + * @param[in] instrument Instrument to be used to measure performance. + */ + void add(std::unique_ptr<Instrument> instrument); + + /** Start all added instruments to measure performance. */ + void start(); + + /** Stop all added instruments. */ + void stop(); + + /** Return measurements for all instruments. */ + const MeasurementsMap &measurements() const; + +private: + std::vector<std::unique_ptr<Instrument>> _instruments{}; + MeasurementsMap _measurements{}; +}; +} // namespace framework +} // namespace test +} // namespace arm_compute +#endif /* ARM_COMPUTE_TEST_PROFILER */ diff --git a/framework/TestResult.h b/framework/TestResult.h index c860cbc22c..747c2defb4 100644 --- a/framework/TestResult.h +++ b/framework/TestResult.h @@ -24,6 +24,8 @@ #ifndef ARM_COMPUTE_TEST_TESTRESULT #define ARM_COMPUTE_TEST_TESTRESULT +#include "Profiler.h" + namespace arm_compute { namespace test @@ -58,7 +60,18 @@ struct TestResult { } - Status status{ Status::NOT_RUN }; //< Execution status + /** Initialise the result with a status and profiling information. + * + * @param[in] status Execution status. + * @param[in] measurements Profiling information. + */ + TestResult(Status status, const Profiler::MeasurementsMap &measurements) + : status{ status }, measurements{ measurements } + { + } + + Status status{ Status::NOT_RUN }; //< Execution status + Profiler::MeasurementsMap measurements{}; //< Profiling information }; } // namespace framework } // namespace test diff --git a/framework/instruments/Instrument.h b/framework/instruments/Instrument.h new file mode 100644 index 0000000000..895a64738c --- /dev/null +++ b/framework/instruments/Instrument.h @@ -0,0 +1,98 @@ +/* + * 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_INSTRUMENT +#define ARM_COMPUTE_TEST_INSTRUMENT + +#include "../Utils.h" + +#include <memory> +#include <ostream> +#include <string> + +namespace arm_compute +{ +namespace test +{ +namespace framework +{ +/** Interface for classes that can be used to measure performance. */ +class Instrument +{ +public: + /** Helper function to create an instrument of the given type. + * + * @return Instance of an instrument of the given type. + */ + 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; + Instrument &operator=(const Instrument &) = default; + Instrument &operator=(Instrument &&) = default; + virtual ~Instrument() = default; + + /** Identifier for the instrument */ + virtual std::string id() const = 0; + + /** Start measuring. */ + virtual void start() = 0; + + /** Stop measuring. */ + virtual void stop() = 0; + + /** Return the latest measurement. */ + virtual Measurement measurement() 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() +{ + return support::cpp14::make_unique<T>(); +} +} // namespace framework +} // namespace test +} // namespace arm_compute +#endif /* ARM_COMPUTE_TEST_INSTRUMENT */ diff --git a/framework/instruments/Instruments.cpp b/framework/instruments/Instruments.cpp new file mode 100644 index 0000000000..7a26944d26 --- /dev/null +++ b/framework/instruments/Instruments.cpp @@ -0,0 +1,57 @@ +/* + * 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 "Instruments.h" + +#include <map> +#include <stdexcept> + +namespace arm_compute +{ +namespace test +{ +namespace framework +{ +InstrumentType instrument_type_from_name(const std::string &name) +{ + static const std::map<std::string, InstrumentType> types = + { + { "all", InstrumentType::ALL }, + { "none", InstrumentType::NONE }, + { "wall_clock", InstrumentType::WALL_CLOCK_TIMER }, + { "cycles", InstrumentType::PMU_CYCLE_COUNTER }, + { "instructions", InstrumentType::PMU_INSTRUCTION_COUNTER }, + }; + + try + { + return types.at(name); + } + catch(const std::out_of_range &) + { + throw std::invalid_argument(name); + } +} +} // namespace framework +} // namespace test +} // namespace arm_compute diff --git a/framework/instruments/Instruments.h b/framework/instruments/Instruments.h new file mode 100644 index 0000000000..034fa168f5 --- /dev/null +++ b/framework/instruments/Instruments.h @@ -0,0 +1,105 @@ +/* + * 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_INSTRUMENTS +#define ARM_COMPUTE_TEST_INSTRUMENTS + +#include "PMUCounter.h" +#include "WallClockTimer.h" + +#include <sstream> +#include <string> + +namespace arm_compute +{ +namespace test +{ +namespace framework +{ +enum class InstrumentType : unsigned int +{ + ALL = ~0U, + NONE = 0, + WALL_CLOCK_TIMER = 1, + PMU_CYCLE_COUNTER = 2, + PMU_INSTRUCTION_COUNTER = 4 +}; + +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; + stream >> value; + instrument = instrument_type_from_name(value); + return stream; +} + +inline ::std::stringstream &operator<<(::std::stringstream &stream, InstrumentType instrument) +{ + switch(instrument) + { + case InstrumentType::WALL_CLOCK_TIMER: + stream << "WALL_CLOCK_TIMER"; + break; + case InstrumentType::PMU_CYCLE_COUNTER: + stream << "PMU_CYCLE_COUNTER"; + break; + case InstrumentType::PMU_INSTRUCTION_COUNTER: + stream << "PMU_INSTRUCTION_COUNTER"; + break; + case InstrumentType::ALL: + stream << "ALL"; + break; + case InstrumentType::NONE: + stream << "NONE"; + break; + default: + throw std::invalid_argument("Unsupported instrument type"); + } + + return stream; +} +} // namespace framework +} // namespace test +} // namespace arm_compute +#endif /* ARM_COMPUTE_TEST_INSTRUMENTS */ diff --git a/framework/instruments/PMUCounter.cpp b/framework/instruments/PMUCounter.cpp new file mode 100644 index 0000000000..7994a15862 --- /dev/null +++ b/framework/instruments/PMUCounter.cpp @@ -0,0 +1,140 @@ +/* + * 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 "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() +{ + ioctl(_fd, PERF_EVENT_IOC_RESET, 0); + ioctl(_fd, PERF_EVENT_IOC_ENABLE, 0); +} + +void CycleCounter::stop() +{ + ioctl(_fd, PERF_EVENT_IOC_DISABLE, 0); + read(_fd, &_cycles, sizeof(_cycles)); +} + +Instrument::Measurement CycleCounter::measurement() const +{ + 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) + { + throw std::runtime_error("perf_event_open for instructions failed"); + } +} + +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)); +} + +Instrument::Measurement InstructionCounter::measurement() const +{ + return Measurement(_instructions, "instructions"); +} +} // namespace framework +} // namespace test +} // namespace arm_compute diff --git a/framework/instruments/PMUCounter.h b/framework/instruments/PMUCounter.h new file mode 100644 index 0000000000..f407be602f --- /dev/null +++ b/framework/instruments/PMUCounter.h @@ -0,0 +1,71 @@ +/* + * 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_COUNTER +#define ARM_COMPUTE_TEST_PMU_COUNTER + +#include "Instrument.h" + +namespace arm_compute +{ +namespace test +{ +namespace framework +{ +/** Implementation of an instrument to count CPU cycles. */ +class CycleCounter : public Instrument +{ +public: + /** Initialise the cycle counter. */ + CycleCounter(); + + std::string id() const override; + void start() override; + void stop() override; + Measurement measurement() const override; + +private: + long _fd{ -1 }; + 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 +} // namespace test +} // namespace arm_compute +#endif /* ARM_COMPUTE_TEST_PMU_COUNTER */ diff --git a/framework/instruments/WallClockTimer.cpp b/framework/instruments/WallClockTimer.cpp new file mode 100644 index 0000000000..37db0c7f05 --- /dev/null +++ b/framework/instruments/WallClockTimer.cpp @@ -0,0 +1,57 @@ +/* + * 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 "WallClockTimer.h" + +#include "../Framework.h" +#include "../Utils.h" + +namespace arm_compute +{ +namespace test +{ +namespace framework +{ +std::string WallClockTimer::id() const +{ + return "Wall clock"; +} + +void WallClockTimer::start() +{ + _start = std::chrono::high_resolution_clock::now(); +} + +void WallClockTimer::stop() +{ + _stop = std::chrono::high_resolution_clock::now(); +} + +Instrument::Measurement WallClockTimer::measurement() const +{ + const auto delta = std::chrono::duration_cast<std::chrono::microseconds>(_stop - _start); + return Instrument::Measurement(delta.count(), "us"); +} +} // namespace framework +} // namespace test +} // namespace arm_compute diff --git a/framework/instruments/WallClockTimer.h b/framework/instruments/WallClockTimer.h new file mode 100644 index 0000000000..b7c390f691 --- /dev/null +++ b/framework/instruments/WallClockTimer.h @@ -0,0 +1,53 @@ +/* + * 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_WALL_CLOCK_TIMER +#define ARM_COMPUTE_TEST_WALL_CLOCK_TIMER + +#include "Instrument.h" + +#include <chrono> + +namespace arm_compute +{ +namespace test +{ +namespace framework +{ +/** Implementation of an instrument to measure elapsed wall-clock time in milliseconds. */ +class WallClockTimer : public Instrument +{ +public: + std::string id() const override; + void start() override; + void stop() override; + Measurement measurement() const override; + +private: + std::chrono::high_resolution_clock::time_point _start{}; + std::chrono::high_resolution_clock::time_point _stop{}; +}; +} // namespace framework +} // namespace test +} // namespace arm_compute +#endif /* ARM_COMPUTE_TEST_WALL_CLOCK_TIMER */ |