aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMoritz Pflanzer <moritz.pflanzer@arm.com>2017-08-30 12:47:06 +0100
committerAnthony Barbier <anthony.barbier@arm.com>2018-11-02 16:35:24 +0000
commit09e4f98e31a9bb77bebeccd59c70f0715ab2c292 (patch)
treedcf5992df5961042a221cb426372eeb21a2d8023
parent906443f38fe2c168f4a0b2db5cd9852865fc4922 (diff)
downloadComputeLibrary-09e4f98e31a9bb77bebeccd59c70f0715ab2c292.tar.gz
COMPMID-482: Refactor PMU counters
Change-Id: I9b254ce693363ecbbd7c188d211c85471134a91e Reviewed-on: http://mpd-gerrit.cambridge.arm.com/84328 Reviewed-by: Anthony Barbier <anthony.barbier@arm.com> Tested-by: Kaizen <jeremy.johnson+kaizengerrit@arm.com>
-rw-r--r--tests/SConscript1
-rw-r--r--tests/framework/Framework.cpp26
-rw-r--r--tests/framework/Framework.h2
-rw-r--r--tests/framework/Profiler.cpp5
-rw-r--r--tests/framework/Profiler.h3
-rw-r--r--tests/framework/SConscript4
-rw-r--r--tests/framework/instruments/Instrument.h27
-rw-r--r--tests/framework/instruments/Instruments.cpp5
-rw-r--r--tests/framework/instruments/Instruments.h29
-rw-r--r--tests/framework/instruments/Measurement.h102
-rw-r--r--tests/framework/instruments/PMU.cpp99
-rw-r--r--tests/framework/instruments/PMU.h96
-rw-r--r--tests/framework/instruments/PMUCounter.cpp118
-rw-r--r--tests/framework/instruments/PMUCounter.h33
-rw-r--r--tests/framework/instruments/WallClockTimer.cpp4
-rw-r--r--tests/framework/instruments/WallClockTimer.h8
-rw-r--r--tests/framework/printers/JSONPrinter.cpp9
-rw-r--r--tests/framework/printers/PrettyPrinter.cpp9
18 files changed, 386 insertions, 194 deletions
diff --git a/tests/SConscript b/tests/SConscript
index 9be03adeb7..cec8d697c2 100644
--- a/tests/SConscript
+++ b/tests/SConscript
@@ -34,7 +34,6 @@ SConscript('./validation_old/SConscript', duplicate=0)
variables = [
#FIXME Remove before release (And remove all references to INTERNAL_ONLY)
BoolVariable("internal_only", "Enable ARM internal only tests", True),
- BoolVariable("pmu", "Enable PMU counters", False),
BoolVariable("validation_tests", "Build validation test programs", True),
BoolVariable("benchmark_tests", "Build benchmark test programs", True)
]
diff --git a/tests/framework/Framework.cpp b/tests/framework/Framework.cpp
index 8d015c69d2..7b761d5936 100644
--- a/tests/framework/Framework.cpp
+++ b/tests/framework/Framework.cpp
@@ -45,8 +45,7 @@ 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>);
+ _available_instruments.emplace(InstrumentType::PMU, Instrument::make_instrument<PMUCounter>);
#endif /* PMU_ENABLED */
}
@@ -86,12 +85,7 @@ void Framework::init(const std::vector<InstrumentType> &instruments, int num_ite
_num_iterations = num_iterations;
_log_level = log_level;
- _instruments = InstrumentType::NONE;
-
- for(const auto &instrument : instruments)
- {
- _instruments |= instrument;
- }
+ _instruments = std::set<InstrumentType>(instruments.begin(), instruments.end());
}
std::string Framework::current_suite_name() const
@@ -461,9 +455,23 @@ Profiler Framework::get_profiler() const
{
Profiler profiler;
+ const bool all_instruments = std::any_of(
+ _instruments.begin(),
+ _instruments.end(),
+ [](InstrumentType type) -> bool { return type == InstrumentType::ALL; });
+
+ auto is_selected = [&](InstrumentType instrument) -> bool
+ {
+ return std::find_if(_instruments.begin(), _instruments.end(), [&](InstrumentType type) -> bool {
+ const auto group = static_cast<InstrumentType>(static_cast<uint64_t>(type) & 0xFF00);
+ return group == instrument;
+ })
+ != _instruments.end();
+ };
+
for(const auto &instrument : _available_instruments)
{
- if((instrument.first & _instruments) != InstrumentType::NONE)
+ if(all_instruments || is_selected(instrument.first))
{
profiler.add(instrument.second());
}
diff --git a/tests/framework/Framework.h b/tests/framework/Framework.h
index 6a26c29b80..d77a1b2549 100644
--- a/tests/framework/Framework.h
+++ b/tests/framework/Framework.h
@@ -313,7 +313,7 @@ private:
using create_function = std::unique_ptr<Instrument>();
std::map<InstrumentType, create_function *> _available_instruments{};
- InstrumentType _instruments{ InstrumentType::NONE };
+ std::set<InstrumentType> _instruments{ InstrumentType::NONE };
TestFilter _test_filter{};
LogLevel _log_level{ LogLevel::ALL };
TestResult *_current_test_result{ nullptr };
diff --git a/tests/framework/Profiler.cpp b/tests/framework/Profiler.cpp
index 76de9a818f..646c66556c 100644
--- a/tests/framework/Profiler.cpp
+++ b/tests/framework/Profiler.cpp
@@ -54,7 +54,10 @@ void Profiler::stop()
for(const auto &instrument : _instruments)
{
- _measurements[instrument->id()].push_back(instrument->measurement());
+ for(const auto &measurement : instrument->measurements())
+ {
+ _measurements[instrument->id() + "/" + measurement.first].push_back(measurement.second);
+ }
}
}
diff --git a/tests/framework/Profiler.h b/tests/framework/Profiler.h
index 1454c0f875..930075e214 100644
--- a/tests/framework/Profiler.h
+++ b/tests/framework/Profiler.h
@@ -25,6 +25,7 @@
#define ARM_COMPUTE_TEST_PROFILER
#include "instruments/Instrument.h"
+#include "instruments/Measurement.h"
#include <map>
#include <memory>
@@ -45,7 +46,7 @@ class Profiler
{
public:
/** Mapping from instrument ids to their measurements. */
- using MeasurementsMap = std::map<std::string, std::vector<Instrument::Measurement>>;
+ using MeasurementsMap = std::map<std::string, std::vector<Measurement>>;
/** Add @p instrument to the performance monitor.
*
diff --git a/tests/framework/SConscript b/tests/framework/SConscript
index 36632515a3..62837f849f 100644
--- a/tests/framework/SConscript
+++ b/tests/framework/SConscript
@@ -43,10 +43,6 @@ vars.Update(framework_env)
Help(new_options.GenerateHelpText(framework_env))
-if env['os'] == 'android' and framework_env['pmu']:
- print("pmu=1 is not supported for os=android")
- Exit(1)
-
if(env['opencl']):
framework_env.Append(CPPDEFINES=['ARM_COMPUTE_CL'])
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{};
diff --git a/tests/framework/printers/JSONPrinter.cpp b/tests/framework/printers/JSONPrinter.cpp
index bf8fce7844..ae19cae67c 100644
--- a/tests/framework/printers/JSONPrinter.cpp
+++ b/tests/framework/printers/JSONPrinter.cpp
@@ -23,7 +23,8 @@
*/
#include "JSONPrinter.h"
-#include "tests/framework/Framework.h"
+#include "../Framework.h"
+#include "../instruments/Measurement.h"
#include <algorithm>
@@ -133,12 +134,12 @@ void JSONPrinter::print_measurements(const Profiler::MeasurementsMap &measuremen
{
*_stream << R"(")" << i_it->first << R"(" : {)";
- auto add_measurements = [](double a, const Instrument::Measurement & b)
+ auto add_measurements = [](double a, const Measurement & b)
{
return a + b.value;
};
- auto cmp_measurements = [](const Instrument::Measurement & a, const Instrument::Measurement & b)
+ auto cmp_measurements = [](const Measurement & a, const Measurement & b)
{
return a.value < b.value;
};
@@ -153,7 +154,7 @@ void JSONPrinter::print_measurements(const Profiler::MeasurementsMap &measuremen
num_values -= 2;
}
- auto measurement_to_string = [](const Instrument::Measurement & measurement)
+ auto measurement_to_string = [](const Measurement & measurement)
{
return support::cpp11::to_string(measurement.value);
};
diff --git a/tests/framework/printers/PrettyPrinter.cpp b/tests/framework/printers/PrettyPrinter.cpp
index b0892a4a50..2f7df1837a 100644
--- a/tests/framework/printers/PrettyPrinter.cpp
+++ b/tests/framework/printers/PrettyPrinter.cpp
@@ -23,7 +23,8 @@
*/
#include "PrettyPrinter.h"
-#include "tests/framework/Framework.h"
+#include "../Framework.h"
+#include "../instruments/Measurement.h"
#include <algorithm>
@@ -112,12 +113,12 @@ void PrettyPrinter::print_measurements(const Profiler::MeasurementsMap &measurem
{
*_stream << begin_color("3") << " " << instrument.first << ":";
- auto add_measurements = [](double a, const Instrument::Measurement & b)
+ auto add_measurements = [](double a, const Measurement & b)
{
return a + b.value;
};
- auto cmp_measurements = [](const Instrument::Measurement & a, const Instrument::Measurement & b)
+ auto cmp_measurements = [](const Measurement & a, const Measurement & b)
{
return a.value < b.value;
};
@@ -132,7 +133,7 @@ void PrettyPrinter::print_measurements(const Profiler::MeasurementsMap &measurem
num_values -= 2;
}
- Instrument::Measurement avg{ sum_values / num_values, minmax_values.first->unit };
+ Measurement avg{ sum_values / num_values, minmax_values.first->unit };
*_stream << " ";
*_stream << "AVG=" << avg << ", ";