diff options
Diffstat (limited to 'src/backends/neon')
-rw-r--r-- | src/backends/neon/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/backends/neon/NeonInterceptorScheduler.cpp | 47 | ||||
-rw-r--r-- | src/backends/neon/NeonInterceptorScheduler.hpp | 38 | ||||
-rw-r--r-- | src/backends/neon/NeonTimer.cpp | 63 | ||||
-rw-r--r-- | src/backends/neon/NeonTimer.hpp | 43 | ||||
-rw-r--r-- | src/backends/neon/backend.mk | 2 | ||||
-rw-r--r-- | src/backends/neon/test/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/backends/neon/test/NeonCreateWorkloadTests.cpp | 5 | ||||
-rw-r--r-- | src/backends/neon/test/NeonMemCopyTests.cpp | 39 | ||||
-rw-r--r-- | src/backends/neon/test/NeonTimerTest.cpp | 105 | ||||
-rw-r--r-- | src/backends/neon/workloads/NeonWorkloadUtils.hpp | 4 |
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> |