IVGCVSW-7222 Fix incorrect kernel measurements in profiling output
* Some CL kernels are not run after the first inference and this breaks
the profiler which is expecting a measurement for every kernel each run
* Add a function HasKernelMeasurements() to ascertain if the Event is
returning kernel measurements and if so insert 0.0 values for any missing
kernel measurements.
* Fix ExecuteNetwork to only print a json object after all inferences
have completed
Signed-off-by: Kevin May <kevin.may@arm.com>
Change-Id: I99f2bb0db847f5a52ab4c5705b072155c6b6f333
diff --git a/src/armnn/Instrument.hpp b/src/armnn/Instrument.hpp
index 8dde2ec..11505d1 100644
--- a/src/armnn/Instrument.hpp
+++ b/src/armnn/Instrument.hpp
@@ -61,6 +61,8 @@
virtual const char* GetName() const = 0;
+ virtual bool HasKernelMeasurements() const { return false;}
+
};
} //namespace armnn
diff --git a/src/armnn/Profiling.cpp b/src/armnn/Profiling.cpp
index 805b61e..db2962e 100644
--- a/src/armnn/Profiling.cpp
+++ b/src/armnn/Profiling.cpp
@@ -316,6 +316,20 @@
}
std::vector<Measurement> instrumentMeasurements = parentEvent->GetMeasurements();
unsigned int childIdx = 0;
+ unsigned int numSkippedKernels = 0;
+ if (inferenceIndex > 0)
+ {
+ for (auto &i: parentEvent->GetInstruments())
+ {
+ if (i->HasKernelMeasurements())
+ {
+ numSkippedKernels = static_cast<unsigned int>(parentObject.m_Children.size() -
+ instrumentMeasurements.size());
+ childIdx = numSkippedKernels;
+ }
+ }
+ }
+
for (size_t measurementIndex = 0; measurementIndex < instrumentMeasurements.size(); ++measurementIndex, ++childIdx)
{
if (inferenceIndex == 0)
@@ -328,6 +342,13 @@
ARMNN_ASSERT(parentObject.NumChildren() == childIdx);
parentObject.AddChild(measurementObject);
}
+ else
+ {
+ if (numSkippedKernels > 0)
+ {
+ parentObject.GetChild(--numSkippedKernels).AddMeasurement(0.0);
+ }
+ }
parentObject.GetChild(childIdx).AddMeasurement(instrumentMeasurements[measurementIndex].m_Value);
}
diff --git a/src/armnn/ProfilingEvent.cpp b/src/armnn/ProfilingEvent.cpp
index e341344..9f045ff 100644
--- a/src/armnn/ProfilingEvent.cpp
+++ b/src/armnn/ProfilingEvent.cpp
@@ -66,6 +66,11 @@
return measurements;
}
+const std::vector<Event::InstrumentPtr>& Event::GetInstruments() const
+{
+ return m_Instruments;
+}
+
const std::string& Event::GetName() const
{
return m_EventName;
diff --git a/src/armnn/ProfilingEvent.hpp b/src/armnn/ProfilingEvent.hpp
index 3b9d526..e4e26ec 100644
--- a/src/armnn/ProfilingEvent.hpp
+++ b/src/armnn/ProfilingEvent.hpp
@@ -55,6 +55,10 @@
/// \return Recorded measurements of the event
const std::vector<Measurement> GetMeasurements() const;
+ /// Get the Instruments used by this Event
+ /// \return Return a reference to the collection of Instruments
+ const std::vector<InstrumentPtr>& GetInstruments() const;
+
/// Get the name of the event
/// \return Name of the event
const std::string& GetName() const;
diff --git a/src/backends/cl/OpenClTimer.cpp b/src/backends/cl/OpenClTimer.cpp
index a4958c1..a393775 100644
--- a/src/backends/cl/OpenClTimer.cpp
+++ b/src/backends/cl/OpenClTimer.cpp
@@ -85,6 +85,11 @@
CLSymbols::get().clEnqueueNDRangeKernel_ptr = m_OriginalEnqueueFunction;
}
+bool OpenClTimer::HasKernelMeasurements() const
+{
+ return m_Kernels.size() > 0;
+}
+
std::vector<Measurement> OpenClTimer::GetMeasurements() const
{
std::vector<Measurement> measurements;
diff --git a/src/backends/cl/OpenClTimer.hpp b/src/backends/cl/OpenClTimer.hpp
index 5539e88..e517fa4 100644
--- a/src/backends/cl/OpenClTimer.hpp
+++ b/src/backends/cl/OpenClTimer.hpp
@@ -29,6 +29,9 @@
/// Stop the OpenCl timer
void Stop() override;
+ /// Return true if this Instrument has kernels for recording measurements
+ bool HasKernelMeasurements() const override;
+
/// Get the name of the timer
/// \return Name of the timer
const char* GetName() const override { return "OpenClKernelTimer"; }
diff --git a/src/backends/neon/NeonTimer.cpp b/src/backends/neon/NeonTimer.cpp
index a7d3032..dbb1503 100644
--- a/src/backends/neon/NeonTimer.cpp
+++ b/src/backends/neon/NeonTimer.cpp
@@ -42,6 +42,11 @@
m_RealScheduler = nullptr;
}
+bool NeonTimer::HasKernelMeasurements() const
+{
+ return m_Kernels.size() > 0;
+}
+
std::vector<Measurement> NeonTimer::GetMeasurements() const
{
std::vector<Measurement> measurements = m_Kernels;
diff --git a/src/backends/neon/NeonTimer.hpp b/src/backends/neon/NeonTimer.hpp
index 31d3e85..f2be7dc 100644
--- a/src/backends/neon/NeonTimer.hpp
+++ b/src/backends/neon/NeonTimer.hpp
@@ -30,6 +30,8 @@
void Stop() override;
+ bool HasKernelMeasurements() const override;
+
std::vector<Measurement> GetMeasurements() const override;
const char* GetName() const override;
diff --git a/tests/ExecuteNetwork/ArmNNExecutor.cpp b/tests/ExecuteNetwork/ArmNNExecutor.cpp
index b894db8..b655ef8 100644
--- a/tests/ExecuteNetwork/ArmNNExecutor.cpp
+++ b/tests/ExecuteNetwork/ArmNNExecutor.cpp
@@ -184,7 +184,7 @@
const auto inferenceDuration = armnn::GetTimeDuration(start_time);
// If profiling is enabled print out the results
- if(profiler && profiler->IsProfilingEnabled())
+ if(profiler && profiler->IsProfilingEnabled() && x == (m_Params.m_Iterations - 1))
{
profiler->Print(std::cout);
}