Merge pull request #20 from ARM-software/fix-pmu-counters

Resetting and sampling PMU counters at a high frequency seems to yield incorrect result.
This PR adds differential readings which yield more reliable results.
diff --git a/vendor/arm/pmu/pmu_counter.cpp b/vendor/arm/pmu/pmu_counter.cpp
index b82aa5a..a7b1f2c 100644
--- a/vendor/arm/pmu/pmu_counter.cpp
+++ b/vendor/arm/pmu/pmu_counter.cpp
@@ -90,6 +90,12 @@
 bool PmuCounter::reset()
 {
 	const int result = ioctl(_fd, PERF_EVENT_IOC_RESET, 0);
+
+	if (result == -1)
+	{
+		throw std::runtime_error("Failed to reset PMU counter: " + std::string(std::strerror(errno)));
+	}
+
 	return result != -1;
 }
 
diff --git a/vendor/arm/pmu/pmu_counter.h b/vendor/arm/pmu/pmu_counter.h
index a1bbdfc..183dcda 100644
--- a/vendor/arm/pmu/pmu_counter.h
+++ b/vendor/arm/pmu/pmu_counter.h
@@ -49,7 +49,7 @@
      *
      * @param[in] config Counter identifier.
      */
-	explicit PmuCounter(uint64_t config);
+	PmuCounter(uint64_t config);
 
 	/** Default destructor. */
 	~PmuCounter();
diff --git a/vendor/arm/pmu/pmu_profiler.cpp b/vendor/arm/pmu/pmu_profiler.cpp
index 52b49cf..d6af31b 100644
--- a/vendor/arm/pmu/pmu_profiler.cpp
+++ b/vendor/arm/pmu/pmu_profiler.cpp
@@ -49,11 +49,11 @@
 			try
 			{
 				// Create a PMU counter with the specified configuration
-				auto pmu_counter_res = pmu_counters_.emplace(counter, PmuCounter{pmu_config->second});
+				auto pmu_counter_res = pmu_counters_.emplace(counter, pmu_config->second);
 
 				// Try reading a value from the counter to check that it opened correctly
 				auto &pmu_counter = pmu_counter_res.first->second;
-				pmu_counter.get_value<double>();
+				pmu_counter.get_value<long long>();
 
 				// PMU counter is created and can retrieve values
 				available_counters_.insert(counter);
@@ -77,6 +77,7 @@
 	for (auto &pmu_counter : pmu_counters_)
 	{
 		pmu_counter.second.reset();
+		prev_measurements_[pmu_counter.first] = Value{};
 	}
 }
 
@@ -92,8 +93,12 @@
 
 		try
 		{
-			measurements_[pmu_counter->first] = pmu_counter->second.get_value<long long>();
-			pmu_counter->second.reset();
+			auto value = pmu_counter->second.get_value<long long>();
+
+			// Resetting the PMU counter every frame seems to alter the data,
+			// so we make a differential reading.
+			measurements_[pmu_counter->first]      = value - prev_measurements_[pmu_counter->first].get<long long>();
+			prev_measurements_[pmu_counter->first] = value;
 		}
 		catch (const std::runtime_error &e)
 		{
diff --git a/vendor/arm/pmu/pmu_profiler.h b/vendor/arm/pmu/pmu_profiler.h
index 14fdc89..3a003e2 100644
--- a/vendor/arm/pmu/pmu_profiler.h
+++ b/vendor/arm/pmu/pmu_profiler.h
@@ -70,6 +70,7 @@
 
 	bool            running_{false};
 	CpuMeasurements measurements_{};
+	CpuMeasurements prev_measurements_{};
 
 	std::unordered_map<CpuCounter, PmuCounter, CpuCounterHash> pmu_counters_{};
 };