aboutsummaryrefslogtreecommitdiff
path: root/src/backends/neon
diff options
context:
space:
mode:
Diffstat (limited to 'src/backends/neon')
-rw-r--r--src/backends/neon/CMakeLists.txt4
-rw-r--r--src/backends/neon/NeonInterceptorScheduler.cpp47
-rw-r--r--src/backends/neon/NeonInterceptorScheduler.hpp38
-rw-r--r--src/backends/neon/NeonTimer.cpp63
-rw-r--r--src/backends/neon/NeonTimer.hpp43
-rw-r--r--src/backends/neon/backend.mk2
-rw-r--r--src/backends/neon/test/CMakeLists.txt2
-rw-r--r--src/backends/neon/test/NeonCreateWorkloadTests.cpp5
-rw-r--r--src/backends/neon/test/NeonMemCopyTests.cpp39
-rw-r--r--src/backends/neon/test/NeonTimerTest.cpp105
-rw-r--r--src/backends/neon/workloads/NeonWorkloadUtils.hpp4
11 files changed, 348 insertions, 4 deletions
diff --git a/src/backends/neon/CMakeLists.txt b/src/backends/neon/CMakeLists.txt
index 93c7955a5f..152955aa06 100644
--- a/src/backends/neon/CMakeLists.txt
+++ b/src/backends/neon/CMakeLists.txt
@@ -7,11 +7,15 @@ if(ARMCOMPUTENEON)
list(APPEND armnnNeonBackend_sources
NeonBackend.cpp
NeonBackend.hpp
+ NeonInterceptorScheduler.hpp
+ NeonInterceptorScheduler.cpp
NeonLayerSupport.cpp
NeonLayerSupport.hpp
NeonWorkloadFactory.cpp
NeonWorkloadFactory.hpp
NeonTensorHandle.hpp
+ NeonTimer.hpp
+ NeonTimer.cpp
)
add_subdirectory(workloads)
diff --git a/src/backends/neon/NeonInterceptorScheduler.cpp b/src/backends/neon/NeonInterceptorScheduler.cpp
new file mode 100644
index 0000000000..03b4670296
--- /dev/null
+++ b/src/backends/neon/NeonInterceptorScheduler.cpp
@@ -0,0 +1,47 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "NeonInterceptorScheduler.hpp"
+
+#include <boost/assert.hpp>
+
+namespace armnn{
+
+NeonInterceptorScheduler::NeonInterceptorScheduler(arm_compute::IScheduler &realScheduler)
+ : m_Kernels(nullptr), m_RealScheduler(realScheduler)
+{
+}
+
+void NeonInterceptorScheduler::set_num_threads(unsigned int numThreads)
+{
+ m_RealScheduler.set_num_threads(numThreads);
+}
+
+unsigned int NeonInterceptorScheduler::num_threads() const
+{
+ return m_RealScheduler.num_threads();
+}
+
+void NeonInterceptorScheduler::schedule(arm_compute::ICPPKernel* kernel, const Hints& hints)
+{
+ WallClockTimer::clock::time_point startTime = WallClockTimer::clock::now();
+ m_RealScheduler.schedule(kernel, hints.split_dimension());
+ WallClockTimer::clock::time_point stopTime = WallClockTimer::clock::now();
+
+ const auto delta = std::chrono::duration<double, std::micro>(stopTime - startTime);
+ m_Kernels->emplace_back(kernel->name(), delta.count(), Measurement::Unit::TIME_US);
+}
+
+void NeonInterceptorScheduler::run_workloads(std::vector <Workload>& workloads)
+{
+ WallClockTimer::clock::time_point startTime = WallClockTimer::clock::now();
+ m_RealScheduler.run_tagged_workloads(workloads, nullptr);
+ WallClockTimer::clock::time_point stopTime = WallClockTimer::clock::now();
+
+ const auto delta = std::chrono::duration<double, std::micro>(stopTime - startTime);
+ m_Kernels->emplace_back(std::string("Workload"), delta.count(), Measurement::Unit::TIME_US);
+}
+
+} // namespace armnn \ No newline at end of file
diff --git a/src/backends/neon/NeonInterceptorScheduler.hpp b/src/backends/neon/NeonInterceptorScheduler.hpp
new file mode 100644
index 0000000000..f33b79a2da
--- /dev/null
+++ b/src/backends/neon/NeonInterceptorScheduler.hpp
@@ -0,0 +1,38 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include "NeonTimer.hpp"
+#include "WallClockTimer.hpp"
+
+#include <arm_compute/runtime/IScheduler.h>
+#include <arm_compute/runtime/Scheduler.h>
+#include <arm_compute/core/CPP/ICPPKernel.h>
+
+namespace armnn
+{
+
+class NeonInterceptorScheduler : public arm_compute::IScheduler
+{
+public:
+ NeonInterceptorScheduler(arm_compute::IScheduler &realScheduler);
+ ~NeonInterceptorScheduler() = default;
+
+ void set_num_threads(unsigned int numThreads) override;
+
+ unsigned int num_threads() const override;
+
+ void schedule(arm_compute::ICPPKernel *kernel, const Hints &hints) override;
+
+ void run_workloads(std::vector<Workload> &workloads) override;
+
+ void SetKernels(NeonTimer::KernelMeasurements* kernels) { m_Kernels = kernels; }
+ NeonTimer::KernelMeasurements* GetKernels() { return m_Kernels; }
+private:
+ NeonTimer::KernelMeasurements* m_Kernels;
+ arm_compute::IScheduler& m_RealScheduler;
+};
+
+} // namespace armnn
diff --git a/src/backends/neon/NeonTimer.cpp b/src/backends/neon/NeonTimer.cpp
new file mode 100644
index 0000000000..219edc9680
--- /dev/null
+++ b/src/backends/neon/NeonTimer.cpp
@@ -0,0 +1,63 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "NeonTimer.hpp"
+#include "NeonInterceptorScheduler.hpp"
+
+#include <memory>
+
+#include <boost/assert.hpp>
+#include <boost/format.hpp>
+
+namespace armnn
+{
+namespace
+{
+static thread_local auto g_Interceptor = std::make_shared<NeonInterceptorScheduler>(arm_compute::Scheduler::get());
+}
+
+void NeonTimer::Start()
+{
+ m_Kernels.clear();
+ BOOST_ASSERT(g_Interceptor->GetKernels() == nullptr);
+ g_Interceptor->SetKernels(&m_Kernels);
+
+ m_RealSchedulerType = arm_compute::Scheduler::get_type();
+ //Note: We can't currently replace a custom scheduler
+ if(m_RealSchedulerType != arm_compute::Scheduler::Type::CUSTOM)
+ {
+ // Keep the real schedule and add NeonInterceptorScheduler as an interceptor
+ m_RealScheduler = &arm_compute::Scheduler::get();
+ arm_compute::Scheduler::set(std::static_pointer_cast<arm_compute::IScheduler>(g_Interceptor));
+ }
+}
+
+void NeonTimer::Stop()
+{
+ // Restore real scheduler
+ g_Interceptor->SetKernels(nullptr);
+ arm_compute::Scheduler::set(m_RealSchedulerType);
+ m_RealScheduler = nullptr;
+}
+
+std::vector<Measurement> NeonTimer::GetMeasurements() const
+{
+ std::vector<Measurement> measurements = m_Kernels;
+ unsigned int kernel_number = 0;
+ for (auto & kernel : measurements)
+ {
+ std::string kernelName = std::string(this->GetName()) + "/" + std::to_string(kernel_number++) + ": " + kernel
+ .m_Name;
+ kernel.m_Name = kernelName;
+ }
+ return measurements;
+}
+
+const char* NeonTimer::GetName() const
+{
+ return "NeonKernelTimer";
+}
+
+}
diff --git a/src/backends/neon/NeonTimer.hpp b/src/backends/neon/NeonTimer.hpp
new file mode 100644
index 0000000000..31d3e85a7c
--- /dev/null
+++ b/src/backends/neon/NeonTimer.hpp
@@ -0,0 +1,43 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "Instrument.hpp"
+
+#include <arm_compute/runtime/IScheduler.h>
+#include <arm_compute/runtime/Scheduler.h>
+#include <arm_compute/core/CPP/ICPPKernel.h>
+
+#include <chrono>
+#include <map>
+#include <list>
+
+namespace armnn
+{
+
+class NeonTimer : public Instrument
+{
+public:
+ using KernelMeasurements = std::vector<Measurement>;
+
+ NeonTimer() = default;
+ ~NeonTimer() = default;
+
+ void Start() override;
+
+ void Stop() override;
+
+ std::vector<Measurement> GetMeasurements() const override;
+
+ const char* GetName() const override;
+
+private:
+ KernelMeasurements m_Kernels;
+ arm_compute::IScheduler* m_RealScheduler;
+ arm_compute::Scheduler::Type m_RealSchedulerType;
+};
+
+} \ No newline at end of file
diff --git a/src/backends/neon/backend.mk b/src/backends/neon/backend.mk
index 132328ba72..af83fb1321 100644
--- a/src/backends/neon/backend.mk
+++ b/src/backends/neon/backend.mk
@@ -9,7 +9,9 @@
BACKEND_SOURCES := \
NeonBackend.cpp \
+ NeonInterceptorScheduler.cpp \
NeonLayerSupport.cpp \
+ NeonTimer.cpp \
NeonWorkloadFactory.cpp \
workloads/NeonActivationWorkload.cpp \
workloads/NeonAdditionFloatWorkload.cpp \
diff --git a/src/backends/neon/test/CMakeLists.txt b/src/backends/neon/test/CMakeLists.txt
index 87da01e9e2..4a3380c3f9 100644
--- a/src/backends/neon/test/CMakeLists.txt
+++ b/src/backends/neon/test/CMakeLists.txt
@@ -7,6 +7,8 @@ list(APPEND armnnNeonBackendUnitTests_sources
NeonCreateWorkloadTests.cpp
NeonLayerSupportTests.cpp
NeonLayerTests.cpp
+ NeonMemCopyTests.cpp
+ NeonTimerTest.cpp
)
add_library(armnnNeonBackendUnitTests OBJECT ${armnnNeonBackendUnitTests_sources})
diff --git a/src/backends/neon/test/NeonCreateWorkloadTests.cpp b/src/backends/neon/test/NeonCreateWorkloadTests.cpp
index 2c4d0ae0f9..ec8fe803a1 100644
--- a/src/backends/neon/test/NeonCreateWorkloadTests.cpp
+++ b/src/backends/neon/test/NeonCreateWorkloadTests.cpp
@@ -3,9 +3,10 @@
// SPDX-License-Identifier: MIT
//
-#include <armnn/test/CreateWorkloadClNeon.hpp>
-
#include <backends/MemCopyWorkload.hpp>
+
+#include <backends/aclCommon/test/CreateWorkloadClNeon.hpp>
+
#include <backends/neon/NeonWorkloadFactory.hpp>
#include <backends/neon/NeonTensorHandle.hpp>
#include <backends/neon/workloads/NeonWorkloadUtils.hpp>
diff --git a/src/backends/neon/test/NeonMemCopyTests.cpp b/src/backends/neon/test/NeonMemCopyTests.cpp
new file mode 100644
index 0000000000..ddb47343a1
--- /dev/null
+++ b/src/backends/neon/test/NeonMemCopyTests.cpp
@@ -0,0 +1,39 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <backends/neon/NeonWorkloadFactory.hpp>
+#include <backends/reference/RefWorkloadFactory.hpp>
+
+#include <backends/test/MemCopyTestImpl.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(NeonMemCopy)
+
+BOOST_AUTO_TEST_CASE(CopyBetweenCpuAndNeon)
+{
+ LayerTestResult<float, 4> result = MemCopyTest<armnn::RefWorkloadFactory, armnn::NeonWorkloadFactory>(false);
+ BOOST_TEST(CompareTensors(result.output, result.outputExpected));
+}
+
+BOOST_AUTO_TEST_CASE(CopyBetweenNeonAndCpu)
+{
+ LayerTestResult<float, 4> result = MemCopyTest<armnn::NeonWorkloadFactory, armnn::RefWorkloadFactory>(false);
+ BOOST_TEST(CompareTensors(result.output, result.outputExpected));
+}
+
+BOOST_AUTO_TEST_CASE(CopyBetweenCpuAndNeonWithSubtensors)
+{
+ LayerTestResult<float, 4> result = MemCopyTest<armnn::RefWorkloadFactory, armnn::NeonWorkloadFactory>(true);
+ BOOST_TEST(CompareTensors(result.output, result.outputExpected));
+}
+
+BOOST_AUTO_TEST_CASE(CopyBetweenNeonAndCpuWithSubtensors)
+{
+ LayerTestResult<float, 4> result = MemCopyTest<armnn::NeonWorkloadFactory, armnn::RefWorkloadFactory>(true);
+ BOOST_TEST(CompareTensors(result.output, result.outputExpected));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/backends/neon/test/NeonTimerTest.cpp b/src/backends/neon/test/NeonTimerTest.cpp
new file mode 100644
index 0000000000..06f19c6ec3
--- /dev/null
+++ b/src/backends/neon/test/NeonTimerTest.cpp
@@ -0,0 +1,105 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <armnn/ArmNN.hpp>
+
+#include <armnn/test/TensorHelpers.hpp>
+
+#include <backends/CpuTensorHandle.hpp>
+#include <backends/WorkloadFactory.hpp>
+
+#include <backends/neon/NeonTimer.hpp>
+#include <backends/neon/NeonWorkloadFactory.hpp>
+
+#include <backends/test/LayerTests.hpp>
+#include <backends/test/TensorCopyUtils.hpp>
+#include <backends/test/WorkloadTestUtils.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#include <cstdlib>
+#include <algorithm>
+
+using namespace armnn;
+
+BOOST_AUTO_TEST_SUITE(NeonTimerInstrument)
+
+
+BOOST_AUTO_TEST_CASE(NeonTimerGetName)
+{
+ NeonTimer neonTimer;
+ BOOST_CHECK_EQUAL(neonTimer.GetName(), "NeonKernelTimer");
+}
+
+BOOST_AUTO_TEST_CASE(NeonTimerMeasure)
+{
+ NeonWorkloadFactory workloadFactory;
+
+ unsigned int inputWidth = 4000u;
+ unsigned int inputHeight = 5000u;
+ unsigned int inputChannels = 1u;
+ unsigned int inputBatchSize = 1u;
+
+ float upperBound = 1.0f;
+ float lowerBound = -1.0f;
+
+ size_t inputSize = inputWidth * inputHeight * inputChannels * inputBatchSize;
+ std::vector<float> inputData(inputSize, 0.f);
+ std::generate(inputData.begin(), inputData.end(), [](){
+ return (static_cast<float>(rand()) / static_cast<float>(RAND_MAX / 3)) + 1.f; });
+
+ unsigned int outputWidth = inputWidth;
+ unsigned int outputHeight = inputHeight;
+ unsigned int outputChannels = inputChannels;
+ unsigned int outputBatchSize = inputBatchSize;
+
+ armnn::TensorInfo inputTensorInfo({ inputBatchSize, inputChannels, inputHeight, inputWidth },
+ armnn::GetDataType<float>());
+
+ armnn::TensorInfo outputTensorInfo({ outputBatchSize, outputChannels, outputHeight, outputWidth },
+ armnn::GetDataType<float>());
+
+ LayerTestResult<float, 4> result(inputTensorInfo);
+
+ auto input = MakeTensor<float, 4>(inputTensorInfo, inputData);
+
+ std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
+ std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
+
+ // Setup bounded ReLu
+ armnn::ActivationQueueDescriptor descriptor;
+ armnn::WorkloadInfo workloadInfo;
+ AddInputToWorkload(descriptor, workloadInfo, inputTensorInfo, inputHandle.get());
+ AddOutputToWorkload(descriptor, workloadInfo, outputTensorInfo, outputHandle.get());
+
+ descriptor.m_Parameters.m_Function = armnn::ActivationFunction::BoundedReLu;
+ descriptor.m_Parameters.m_A = upperBound;
+ descriptor.m_Parameters.m_B = lowerBound;
+
+ std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateActivation(descriptor, workloadInfo);
+
+ inputHandle->Allocate();
+ outputHandle->Allocate();
+
+ CopyDataToITensorHandle(inputHandle.get(), &input[0][0][0][0]);
+
+ NeonTimer neonTimer;
+ // Start the timer.
+ neonTimer.Start();
+ // Execute the workload.
+ workload->Execute();
+ // Stop the timer.
+ neonTimer.Stop();
+
+ std::vector<Measurement> measurements = neonTimer.GetMeasurements();
+
+ BOOST_CHECK_EQUAL(measurements.size(), 2);
+ BOOST_CHECK_EQUAL(measurements[0].m_Name, "NeonKernelTimer/0: NEFillBorderKernel");
+ BOOST_CHECK(measurements[0].m_Value > 0.0);
+ BOOST_CHECK_EQUAL(measurements[1].m_Name, "NeonKernelTimer/1: NEActivationLayerKernel");
+ BOOST_CHECK(measurements[1].m_Value > 0.0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/backends/neon/workloads/NeonWorkloadUtils.hpp b/src/backends/neon/workloads/NeonWorkloadUtils.hpp
index 22668f6f4b..c4accd6c89 100644
--- a/src/backends/neon/workloads/NeonWorkloadUtils.hpp
+++ b/src/backends/neon/workloads/NeonWorkloadUtils.hpp
@@ -5,9 +5,9 @@
#pragma once
#include <backends/Workload.hpp>
-#include <backends/neon/NeonTensorHandle.hpp>
-#include "NeonTimer.hpp"
+#include <backends/neon/NeonTensorHandle.hpp>
+#include <backends/neon/NeonTimer.hpp>
#include <arm_compute/core/Types.h>
#include <arm_compute/core/Helpers.h>