From 12833d063259cb7809a97a4262f821efdc40554f Mon Sep 17 00:00:00 2001 From: Georgios Pinitas Date: Thu, 25 Jul 2019 13:31:10 +0100 Subject: COMPMID-2204: RuntimeContext interface for NEON functions. This patch creates the interfaces for the runtime context for NEON. Only the Neon backend implements the context which currently only holds an instance of the scheduler. The NEActivationLayer function has been updated to use the new context interface and the corresponding validation tests ported. Change-Id: I32e7e6aa888796dcbbfc5039b1e7f784a24f47da Signed-off-by: Pablo Tello Reviewed-on: https://review.mlplatform.org/c/1851 Comments-Addressed: Arm Jenkins Tested-by: Arm Jenkins Reviewed-by: Michele Di Giorgio --- .../runtime/CL/functions/CLActivationLayer.h | 15 +- arm_compute/runtime/CPP/CPPScheduler.h | 21 +-- arm_compute/runtime/DeviceProperties.h | 41 +++++ .../GLES_COMPUTE/functions/GCActivationLayer.h | 17 ++- arm_compute/runtime/IAssetManager.h | 40 +++++ arm_compute/runtime/IRuntimeContext.h | 61 ++++++++ .../runtime/NEON/INESimpleFunctionNoBorder.h | 19 ++- .../runtime/NEON/functions/NEActivationLayer.h | 14 ++ arm_compute/runtime/OMP/OMPScheduler.h | 16 +- arm_compute/runtime/RuntimeContext.h | 64 ++++++++ arm_compute/runtime/Scheduler.h | 8 +- arm_compute/runtime/SchedulerFactory.h | 58 +++++++ arm_compute/runtime/SingleThreadScheduler.h | 17 +-- arm_compute/runtime/Utils.h | 13 +- src/runtime/CL/functions/CLActivationLayer.cpp | 10 +- src/runtime/CPP/CPPScheduler.cpp | 62 +++++--- src/runtime/CPP/SingleThreadScheduler.cpp | 8 +- src/runtime/DeviceProperties.cpp | 34 +++++ .../GLES_COMPUTE/functions/GCActivationLayer.cpp | 10 +- src/runtime/NEON/INESimpleFunctionNoBorder.cpp | 10 +- src/runtime/NEON/functions/NEActivationLayer.cpp | 12 +- src/runtime/OMP/OMPScheduler.cpp | 11 +- src/runtime/RuntimeContext.cpp | 56 +++++++ src/runtime/Scheduler.cpp | 107 ++++++------- src/runtime/SchedulerFactory.cpp | 82 ++++++++++ src/runtime/Utils.cpp | 26 +++- tests/Globals.h | 6 +- tests/ParametersLibrary.cpp | 41 +++++ tests/ParametersLibrary.h | 76 ++++++++++ tests/Utils.h | 3 + tests/benchmark/fixtures/ActivationLayerFixture.h | 13 +- tests/framework/Framework.cpp | 12 +- tests/framework/Framework.h | 9 +- tests/framework/instruments/Instruments.h | 9 +- tests/framework/instruments/SchedulerTimer.cpp | 28 +++- tests/framework/instruments/SchedulerTimer.h | 27 +++- tests/instruments/Helpers.h | 86 +++++++++++ tests/main.cpp | 32 +++- tests/validation/CL/ActivationLayer.cpp | 1 + tests/validation/NEON/ActivationLayer.cpp | 6 +- tests/validation/NEON/UNIT/RuntimeContext.cpp | 166 +++++++++++++++++++++ tests/validation/fixtures/ActivationLayerFixture.h | 3 +- 42 files changed, 1179 insertions(+), 171 deletions(-) create mode 100644 arm_compute/runtime/DeviceProperties.h create mode 100644 arm_compute/runtime/IAssetManager.h create mode 100644 arm_compute/runtime/IRuntimeContext.h create mode 100644 arm_compute/runtime/RuntimeContext.h create mode 100644 arm_compute/runtime/SchedulerFactory.h create mode 100644 src/runtime/DeviceProperties.cpp create mode 100644 src/runtime/RuntimeContext.cpp create mode 100644 src/runtime/SchedulerFactory.cpp create mode 100644 tests/ParametersLibrary.cpp create mode 100644 tests/ParametersLibrary.h create mode 100644 tests/instruments/Helpers.h create mode 100644 tests/validation/NEON/UNIT/RuntimeContext.cpp diff --git a/arm_compute/runtime/CL/functions/CLActivationLayer.h b/arm_compute/runtime/CL/functions/CLActivationLayer.h index c10c5301c2..1201d7d355 100644 --- a/arm_compute/runtime/CL/functions/CLActivationLayer.h +++ b/arm_compute/runtime/CL/functions/CLActivationLayer.h @@ -39,6 +39,19 @@ class ICLTensor; class CLActivationLayer : public ICLSimpleFunction { public: + /** Constructor + * + * @param[in] ctx Runtime context to be used by the function + */ + CLActivationLayer(void *ctx = nullptr); + /** Prevent instances of this class from being copied (As this class contains pointers) */ + CLActivationLayer(const CLActivationLayer &) = delete; + /** Default move constructor */ + CLActivationLayer(CLActivationLayer &&) = default; + /** Prevent instances of this class from being copied (As this class contains pointers) */ + CLActivationLayer &operator=(const CLActivationLayer &) = delete; + /** Default move assignment operator */ + CLActivationLayer &operator=(CLActivationLayer &&) = default; /** Set the input and output tensor. * * @note If the output tensor is a nullptr or is equal to the input, the activation function will be performed in-place @@ -60,5 +73,5 @@ public: */ static Status validate(const ITensorInfo *input, const ITensorInfo *output, const ActivationLayerInfo &act_info); }; -} +} // namespace arm_compute #endif /* __ARM_COMPUTE_CLACTIVATIONLAYER_H__ */ diff --git a/arm_compute/runtime/CPP/CPPScheduler.h b/arm_compute/runtime/CPP/CPPScheduler.h index 17ed8310a4..69cd25f994 100644 --- a/arm_compute/runtime/CPP/CPPScheduler.h +++ b/arm_compute/runtime/CPP/CPPScheduler.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 ARM Limited. + * Copyright (c) 2016-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -26,14 +26,18 @@ #include "arm_compute/runtime/IScheduler.h" -#include +#include namespace arm_compute { /** C++11 implementation of a pool of threads to automatically split a kernel's execution among several threads. */ -class CPPScheduler : public IScheduler +class CPPScheduler final : public IScheduler { public: + /** Constructor: create a pool of threads. */ + CPPScheduler(); + /** Default destructor */ + ~CPPScheduler(); /** Sets the number of threads the scheduler will use to run the kernels. * * @param[in] num_threads If set to 0, then the maximum number of threads supported by C++11 will be used, otherwise the number of threads specified. @@ -47,6 +51,7 @@ public: /** Access the scheduler singleton * + * @note this method has been deprecated and will be remover in the upcoming releases * @return The scheduler */ static CPPScheduler &get(); @@ -69,12 +74,8 @@ protected: void run_workloads(std::vector &workloads) override; private: - class Thread; - /** Constructor: create a pool of threads. */ - CPPScheduler(); - - unsigned int _num_threads; - std::list _threads; + struct Impl; + std::unique_ptr _impl; }; -} +} // namespace arm_compute #endif /* __ARM_COMPUTE_CPPSCHEDULER_H__ */ diff --git a/arm_compute/runtime/DeviceProperties.h b/arm_compute/runtime/DeviceProperties.h new file mode 100644 index 0000000000..b411124a04 --- /dev/null +++ b/arm_compute/runtime/DeviceProperties.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019 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_DEVICE_PROPERTIES_H__ +#define __ARM_COMPUTE_DEVICE_PROPERTIES_H__ + +#include "arm_compute/core/CPP/CPPTypes.h" + +namespace arm_compute +{ +/** Device properties */ +struct DeviceProperties +{ + std::string name{ "unknown" }; + CPUInfo cpu_info{}; // initialised upon creating in the constructor + + DeviceProperties(); +}; + +} // namespace arm_compute +#endif /*__ARM_COMPUTE_DEVICE_PROPERTIES_H__ */ diff --git a/arm_compute/runtime/GLES_COMPUTE/functions/GCActivationLayer.h b/arm_compute/runtime/GLES_COMPUTE/functions/GCActivationLayer.h index b43456b2cd..5e0effe902 100644 --- a/arm_compute/runtime/GLES_COMPUTE/functions/GCActivationLayer.h +++ b/arm_compute/runtime/GLES_COMPUTE/functions/GCActivationLayer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -38,6 +38,19 @@ class IGCTensor; class GCActivationLayer : public IGCSimpleFunction { public: + /** Constructor + * + * @param[in] ctx Runtime context to be used by the function + */ + GCActivationLayer(void *ctx = nullptr); + /** Prevent instances of this class from being copied (As this class contains pointers) */ + GCActivationLayer(const GCActivationLayer &) = delete; + /** Default move constructor */ + GCActivationLayer(GCActivationLayer &&) = default; + /** Prevent instances of this class from being copied (As this class contains pointers) */ + GCActivationLayer &operator=(const GCActivationLayer &) = delete; + /** Default move assignment operator */ + GCActivationLayer &operator=(GCActivationLayer &&) = default; /** Set the input and output tensor. * * @note If the output tensor is a nullptr, the activation function will be performed in-place @@ -49,5 +62,5 @@ public: */ void configure(IGCTensor *input, IGCTensor *output, ActivationLayerInfo act_info); }; -} +} // namespace arm_compute #endif /* __ARM_COMPUTE_GCACTIVATIONLAYER_H__ */ diff --git a/arm_compute/runtime/IAssetManager.h b/arm_compute/runtime/IAssetManager.h new file mode 100644 index 0000000000..d6f501a9e0 --- /dev/null +++ b/arm_compute/runtime/IAssetManager.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 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_IASSET_MANAGER_H__ +#define __ARM_COMPUTE_IASSET_MANAGER_H__ + +namespace arm_compute +{ +/** Asset manager interface */ +class IAssetManager +{ +public: + /** Memory manager accessor + * + * @return Memory manager + */ + virtual IMemoryManager *memory_manager() = 0; +}; +} // namespace arm_compute +#endif /*__ARM_COMPUTE_IASSET_MANAGER_H__ */ diff --git a/arm_compute/runtime/IRuntimeContext.h b/arm_compute/runtime/IRuntimeContext.h new file mode 100644 index 0000000000..f928085682 --- /dev/null +++ b/arm_compute/runtime/IRuntimeContext.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2019 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_IRUNTIME_CONTEXT_H__ +#define __ARM_COMPUTE_IRUNTIME_CONTEXT_H__ + +namespace arm_compute +{ +// Forward declarations +class IScheduler; +class IAssetManager; +class DeviceProperties; + +/** Context interface */ +class IRuntimeContext +{ +public: + /** Destructor */ + virtual ~IRuntimeContext() = default; + /** Scheduler accessor + * + * @note Scheduler is used to schedule workloads + * + * @return The scheduler registered to the context + */ + virtual IScheduler *scheduler() = 0; + /** Asset manager accessor + * + * @note Asset manager is used to manage objects/tensors within functions + * + * @return The asset manager registered to the context + */ + virtual IAssetManager *asset_manager() = 0; + /** Device propertied accessor + * + * @return Device properties + */ + virtual const DeviceProperties &properties() = 0; +}; +} // namespace arm_compute +#endif /*__ARM_COMPUTE_IRUNTIME_CONTEXT_H__ */ diff --git a/arm_compute/runtime/NEON/INESimpleFunctionNoBorder.h b/arm_compute/runtime/NEON/INESimpleFunctionNoBorder.h index 6765b5f937..d0c3a9beb5 100644 --- a/arm_compute/runtime/NEON/INESimpleFunctionNoBorder.h +++ b/arm_compute/runtime/NEON/INESimpleFunctionNoBorder.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 ARM Limited. + * Copyright (c) 2018-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -26,6 +26,7 @@ #include "arm_compute/core/NEON/INEKernel.h" #include "arm_compute/runtime/IFunction.h" +#include "arm_compute/runtime/IRuntimeContext.h" #include @@ -35,14 +36,26 @@ namespace arm_compute class INESimpleFunctionNoBorder : public IFunction { public: - /** Constructor */ - INESimpleFunctionNoBorder(); + /** Constructor + * + * @param[in] ctx Runtime context to be used by the function + */ + INESimpleFunctionNoBorder(IRuntimeContext *ctx = nullptr); + /** Prevent instances of this class from being copied (As this class contains pointers) */ + INESimpleFunctionNoBorder(const INESimpleFunctionNoBorder &) = delete; + /** Default move constructor */ + INESimpleFunctionNoBorder(INESimpleFunctionNoBorder &&) = default; + /** Prevent instances of this class from being copied (As this class contains pointers) */ + INESimpleFunctionNoBorder &operator=(const INESimpleFunctionNoBorder &) = delete; + /** Default move assignment operator */ + INESimpleFunctionNoBorder &operator=(INESimpleFunctionNoBorder &&) = default; // Inherited methods overridden: void run() override final; protected: std::unique_ptr _kernel; /**< Kernel to run */ + IRuntimeContext *_ctx; /**< Context to use */ }; } // namespace arm_compute #endif /*__ARM_COMPUTE_INESIMPLEFUNCTIONNOBORDER_H__ */ diff --git a/arm_compute/runtime/NEON/functions/NEActivationLayer.h b/arm_compute/runtime/NEON/functions/NEActivationLayer.h index c0b5f7ab37..d383da4f32 100644 --- a/arm_compute/runtime/NEON/functions/NEActivationLayer.h +++ b/arm_compute/runtime/NEON/functions/NEActivationLayer.h @@ -30,6 +30,7 @@ namespace arm_compute { +// Forward declarations class ITensor; /** Basic function to run @ref NEActivationLayerKernel @@ -39,6 +40,19 @@ class ITensor; class NEActivationLayer : public INESimpleFunctionNoBorder { public: + /** Constructor + * + * @param[in] ctx Runtime context to be used by the function + */ + NEActivationLayer(IRuntimeContext *ctx = nullptr); + /** Prevent instances of this class from being copied (As this class contains pointers) */ + NEActivationLayer(const NEActivationLayer &) = delete; + /** Default move constructor */ + NEActivationLayer(NEActivationLayer &&) = default; + /** Prevent instances of this class from being copied (As this class contains pointers) */ + NEActivationLayer &operator=(const NEActivationLayer &) = delete; + /** Default move assignment operator */ + NEActivationLayer &operator=(NEActivationLayer &&) = default; /** Set the input and output tensor. * * @note If the output tensor is a nullptr or is equal to the input, the activation function will be performed in-place diff --git a/arm_compute/runtime/OMP/OMPScheduler.h b/arm_compute/runtime/OMP/OMPScheduler.h index ff9bf052fd..5934ee1c12 100644 --- a/arm_compute/runtime/OMP/OMPScheduler.h +++ b/arm_compute/runtime/OMP/OMPScheduler.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -29,9 +29,11 @@ namespace arm_compute { /** Pool of threads to automatically split a kernel's execution among several threads. */ -class OMPScheduler : public IScheduler +class OMPScheduler final : public IScheduler { public: + /** Constructor. */ + OMPScheduler(); /** Sets the number of threads the scheduler will use to run the kernels. * * @param[in] num_threads If set to 0, then the number returned by omp_get_max_threads() will be used, otherwise the number of threads specified. @@ -42,11 +44,6 @@ public: * @return Number of threads available in OMPScheduler. */ unsigned int num_threads() const override; - /** Access the scheduler singleton - * - * @return The scheduler - */ - static OMPScheduler &get(); /** Multithread the execution of the passed kernel if possible. * * The kernel will run on a single thread if any of these conditions is true: @@ -68,10 +65,7 @@ protected: void run_workloads(std::vector &workloads) override; private: - /** Constructor. */ - OMPScheduler(); - unsigned int _num_threads; }; -} +} // namespace arm_compute #endif /* __ARM_COMPUTE_OMPSCHEDULER_H__ */ diff --git a/arm_compute/runtime/RuntimeContext.h b/arm_compute/runtime/RuntimeContext.h new file mode 100644 index 0000000000..564ba78e63 --- /dev/null +++ b/arm_compute/runtime/RuntimeContext.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 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_RUNTIME_CONTEXT_H__ +#define __ARM_COMPUTE_RUNTIME_CONTEXT_H__ + +#include "arm_compute/runtime/DeviceProperties.h" +#include "arm_compute/runtime/IRuntimeContext.h" + +#include + +namespace arm_compute +{ +/** Runtime context */ +class RuntimeContext : public IRuntimeContext +{ +public: + /** Default Constructor */ + RuntimeContext(); + /** Destructor */ + ~RuntimeContext() = default; + /** Prevent instances of this class from being copied (As this class contains pointers) */ + RuntimeContext(const RuntimeContext &) = delete; + /** Default move constructor */ + RuntimeContext(RuntimeContext &&) = default; + /** Prevent instances of this class from being copied (As this class contains pointers) */ + RuntimeContext &operator=(const RuntimeContext &) = delete; + /** Default move assignment operator */ + RuntimeContext &operator=(RuntimeContext &&) = default; + /** CPU Scheduler setter */ + void set_scheduler(IScheduler *scheduler); + + // Inherited overridden methods + IScheduler *scheduler() override; + IAssetManager *asset_manager() override; + const DeviceProperties &properties() override; + +private: + std::unique_ptr _owned_scheduler{ nullptr }; + IScheduler *_scheduler{ nullptr }; + DeviceProperties _device_props{}; +}; +} // namespace arm_compute +#endif /*__ARM_COMPUTE_RUNTIME_CONTEXT_H__ */ diff --git a/arm_compute/runtime/Scheduler.h b/arm_compute/runtime/Scheduler.h index 7e10461b5a..89263fd176 100644 --- a/arm_compute/runtime/Scheduler.h +++ b/arm_compute/runtime/Scheduler.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -25,6 +25,8 @@ #define __ARM_COMPUTE_SCHEDULER_H__ #include "arm_compute/runtime/IScheduler.h" + +#include #include namespace arm_compute @@ -74,7 +76,9 @@ public: private: static Type _scheduler_type; static std::shared_ptr _custom_scheduler; + static std::map> _schedulers; + Scheduler(); }; -} +} // namespace arm_compute #endif /* __ARM_COMPUTE_SCHEDULER_H__ */ diff --git a/arm_compute/runtime/SchedulerFactory.h b/arm_compute/runtime/SchedulerFactory.h new file mode 100644 index 0000000000..3e35655a19 --- /dev/null +++ b/arm_compute/runtime/SchedulerFactory.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019 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_SCHEDULER_FACTORY_H__ +#define __ARM_COMPUTE_SCHEDULER_FACTORY_H__ + +#include "arm_compute/runtime/IScheduler.h" + +#include + +namespace arm_compute +{ +/** Scheduler Factory */ +class SchedulerFactory +{ +public: + /** Scheduler type */ + enum class Type + { + ST, /**< Single thread. */ + CPP, /**< C++11 threads. */ + OMP, /**< OpenMP. */ + }; + +public: + /** Create a scheduler depending on the scheduler type + * + * @param[in] type Type of scheduler to create + * + * @return Scheduler + */ + static std::unique_ptr create(Type type = _default_type); + +private: + static const Type _default_type; +}; +} // namespace arm_compute +#endif /* __ARM_COMPUTE_SCHEDULER_H__ */ diff --git a/arm_compute/runtime/SingleThreadScheduler.h b/arm_compute/runtime/SingleThreadScheduler.h index 7c084efeaf..9ea0f0818e 100644 --- a/arm_compute/runtime/SingleThreadScheduler.h +++ b/arm_compute/runtime/SingleThreadScheduler.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -29,9 +29,11 @@ namespace arm_compute { /** Pool of threads to automatically split a kernel's execution among several threads. */ -class SingleThreadScheduler : public IScheduler +class SingleThreadScheduler final : public IScheduler { public: + /** Constructor. */ + SingleThreadScheduler() = default; /** Sets the number of threads the scheduler will use to run the kernels. * * @param[in] num_threads This is ignored for this scheduler as the number of threads is always one. @@ -42,11 +44,6 @@ public: * @return Number of threads available in SingleThreadScheduler. */ unsigned int num_threads() const override; - /** Access the scheduler singleton - * - * @return The scheduler - */ - static SingleThreadScheduler &get(); /** Runs the kernel in the same thread as the caller synchronously. * * @param[in] kernel Kernel to execute. @@ -60,10 +57,6 @@ protected: * @param[in] workloads Workloads to run */ void run_workloads(std::vector &workloads) override; - -private: - /** Constructor. */ - SingleThreadScheduler() = default; }; -} +} // namespace arm_compute #endif /* __ARM_COMPUTE_SINGLETHREADSCHEDULER_H__ */ diff --git a/arm_compute/runtime/Utils.h b/arm_compute/runtime/Utils.h index 2f037a0621..15c0042a33 100644 --- a/arm_compute/runtime/Utils.h +++ b/arm_compute/runtime/Utils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -24,6 +24,7 @@ #ifndef __ARM_COMPUTE_RUNTIME_UTILS_H__ #define __ARM_COMPUTE_RUNTIME_UTILS_H__ +#include "arm_compute/runtime/IRuntimeContext.h" #include "arm_compute/runtime/Scheduler.h" #include @@ -37,5 +38,13 @@ namespace arm_compute * @return The string describing the scheduler type. */ const std::string &string_from_scheduler_type(Scheduler::Type t); -} + +/** Schedules a kernel using the context if not nullptr else uses the legacy scheduling flow. + * + * @param[in] ctx Context to use. + * @param[in] kernel Kernel to schedule. + * @param[in] hints Hints to use. + */ +void schedule_kernel_on_ctx(IRuntimeContext *ctx, ICPPKernel *kernel, const IScheduler::Hints &hints); +} // namespace arm_compute #endif /* __ARM_COMPUTE_RUNTIME_UTILS_H__ */ diff --git a/src/runtime/CL/functions/CLActivationLayer.cpp b/src/runtime/CL/functions/CLActivationLayer.cpp index 4aeb3a15e1..2b66795cf9 100644 --- a/src/runtime/CL/functions/CLActivationLayer.cpp +++ b/src/runtime/CL/functions/CLActivationLayer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 ARM Limited. + * Copyright (c) 2016-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -27,7 +27,12 @@ #include "arm_compute/core/Types.h" #include "support/ToolchainSupport.h" -using namespace arm_compute; +namespace arm_compute +{ +CLActivationLayer::CLActivationLayer(void *ctx) +{ + ARM_COMPUTE_UNUSED(ctx); +} void CLActivationLayer::configure(ICLTensor *input, ICLTensor *output, ActivationLayerInfo act_info) { @@ -40,3 +45,4 @@ Status CLActivationLayer::validate(const ITensorInfo *input, const ITensorInfo * { return CLActivationLayerKernel::validate(input, output, act_info); } +} // namespace arm_compute diff --git a/src/runtime/CPP/CPPScheduler.cpp b/src/runtime/CPP/CPPScheduler.cpp index 5916bb46fd..9b670d5c04 100644 --- a/src/runtime/CPP/CPPScheduler.cpp +++ b/src/runtime/CPP/CPPScheduler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 ARM Limited. + * Copyright (c) 2016-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -90,7 +91,31 @@ void process_workloads(std::vector &workloads, ThreadFeede } //namespace -class CPPScheduler::Thread +struct CPPScheduler::Impl +{ + Impl(unsigned int thread_hint) + : _num_threads(thread_hint), _threads(_num_threads - 1) + { + } + void set_num_threads(unsigned int num_threads, unsigned int thead_hint) + { + _num_threads = num_threads == 0 ? thead_hint : num_threads; + _threads.resize(_num_threads - 1); + } + unsigned int num_threads() const + { + return _num_threads; + } + + void run_workloads(std::vector &workloads); + + class Thread; + + unsigned int _num_threads; + std::list _threads; +}; + +class CPPScheduler::Impl::Thread { public: /** Start a new thread. */ @@ -132,12 +157,12 @@ private: std::exception_ptr _current_exception{ nullptr }; }; -CPPScheduler::Thread::Thread() +CPPScheduler::Impl::Thread::Thread() { _thread = std::thread(&Thread::worker_thread, this); } -CPPScheduler::Thread::~Thread() +CPPScheduler::Impl::Thread::~Thread() { // Make sure worker thread has ended if(_thread.joinable()) @@ -148,7 +173,7 @@ CPPScheduler::Thread::~Thread() } } -void CPPScheduler::Thread::start(std::vector *workloads, ThreadFeeder &feeder, const ThreadInfo &info) +void CPPScheduler::Impl::Thread::start(std::vector *workloads, ThreadFeeder &feeder, const ThreadInfo &info) { _workloads = workloads; _feeder = &feeder; @@ -161,7 +186,7 @@ void CPPScheduler::Thread::start(std::vector *workloads, T _cv.notify_one(); } -void CPPScheduler::Thread::wait() +void CPPScheduler::Impl::Thread::wait() { { std::unique_lock lock(_m); @@ -174,7 +199,7 @@ void CPPScheduler::Thread::wait() } } -void CPPScheduler::Thread::worker_thread() +void CPPScheduler::Impl::Thread::worker_thread() { while(true) { @@ -209,6 +234,9 @@ void CPPScheduler::Thread::worker_thread() } } +/* + * This singleton has been deprecated and will be removed in the next release + */ CPPScheduler &CPPScheduler::get() { static CPPScheduler scheduler; @@ -216,26 +244,26 @@ CPPScheduler &CPPScheduler::get() } CPPScheduler::CPPScheduler() - : _num_threads(num_threads_hint()), - _threads(_num_threads - 1) + : _impl(support::cpp14::make_unique(num_threads_hint())) { } +CPPScheduler::~CPPScheduler() = default; + void CPPScheduler::set_num_threads(unsigned int num_threads) { - _num_threads = num_threads == 0 ? num_threads_hint() : num_threads; - _threads.resize(_num_threads - 1); + _impl->set_num_threads(num_threads, num_threads_hint()); } unsigned int CPPScheduler::num_threads() const { - return _num_threads; + return _impl->num_threads(); } #ifndef DOXYGEN_SKIP_THIS void CPPScheduler::run_workloads(std::vector &workloads) { - const unsigned int num_threads = std::min(_num_threads, static_cast(workloads.size())); + const unsigned int num_threads = std::min(_impl->num_threads(), static_cast(workloads.size())); if(num_threads < 1) { return; @@ -245,7 +273,7 @@ void CPPScheduler::run_workloads(std::vector &workloads) info.cpu_info = &_cpu_info; info.num_threads = num_threads; unsigned int t = 0; - auto thread_it = _threads.begin(); + auto thread_it = _impl->_threads.begin(); for(; t < num_threads - 1; ++t, ++thread_it) { info.thread_id = t; @@ -258,7 +286,7 @@ void CPPScheduler::run_workloads(std::vector &workloads) try { #endif /* ARM_COMPUTE_EXCEPTIONS_DISABLED */ - for(auto &thread : _threads) + for(auto &thread : _impl->_threads) { thread.wait(); } @@ -278,7 +306,7 @@ void CPPScheduler::schedule(ICPPKernel *kernel, const Hints &hints) const Window &max_window = kernel->window(); const unsigned int num_iterations = max_window.num_iterations(hints.split_dimension()); - const unsigned int num_threads = std::min(num_iterations, _num_threads); + const unsigned int num_threads = std::min(num_iterations, _impl->_num_threads); if(num_iterations == 0) { @@ -302,7 +330,7 @@ void CPPScheduler::schedule(ICPPKernel *kernel, const Hints &hints) case StrategyHint::DYNAMIC: { // Make sure we don't use some windows which are too small as this might create some contention on the ThreadFeeder - const unsigned int max_iterations = static_cast(_num_threads) * 3; + const unsigned int max_iterations = static_cast(_impl->_num_threads) * 3; num_windows = num_iterations > max_iterations ? max_iterations : num_iterations; break; } diff --git a/src/runtime/CPP/SingleThreadScheduler.cpp b/src/runtime/CPP/SingleThreadScheduler.cpp index 37011595fd..152569fb67 100644 --- a/src/runtime/CPP/SingleThreadScheduler.cpp +++ b/src/runtime/CPP/SingleThreadScheduler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -29,12 +29,6 @@ namespace arm_compute { -SingleThreadScheduler &SingleThreadScheduler::get() -{ - static SingleThreadScheduler scheduler; - return scheduler; -} - void SingleThreadScheduler::set_num_threads(unsigned int num_threads) { ARM_COMPUTE_UNUSED(num_threads); diff --git a/src/runtime/DeviceProperties.cpp b/src/runtime/DeviceProperties.cpp new file mode 100644 index 0000000000..e88aa7124c --- /dev/null +++ b/src/runtime/DeviceProperties.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 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 "arm_compute/runtime/DeviceProperties.h" + +#include "arm_compute/runtime/CPUUtils.h" + +namespace arm_compute +{ +DeviceProperties::DeviceProperties() +{ + get_cpu_configuration(cpu_info); +} +} // namespace arm_compute diff --git a/src/runtime/GLES_COMPUTE/functions/GCActivationLayer.cpp b/src/runtime/GLES_COMPUTE/functions/GCActivationLayer.cpp index 8686416616..207e8cef56 100644 --- a/src/runtime/GLES_COMPUTE/functions/GCActivationLayer.cpp +++ b/src/runtime/GLES_COMPUTE/functions/GCActivationLayer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -27,7 +27,12 @@ #include "arm_compute/core/Helpers.h" #include "support/ToolchainSupport.h" -using namespace arm_compute; +namespace arm_compute +{ +GCActivationLayer::GCActivationLayer(void *ctx) +{ + ARM_COMPUTE_UNUSED(ctx); +} void GCActivationLayer::configure(IGCTensor *input, IGCTensor *output, ActivationLayerInfo act_info) { @@ -35,3 +40,4 @@ void GCActivationLayer::configure(IGCTensor *input, IGCTensor *output, Activatio k->configure(input, output, act_info); _kernel = std::move(k); } +} // namespace arm_compute diff --git a/src/runtime/NEON/INESimpleFunctionNoBorder.cpp b/src/runtime/NEON/INESimpleFunctionNoBorder.cpp index 12872048c7..2cabee4c46 100644 --- a/src/runtime/NEON/INESimpleFunctionNoBorder.cpp +++ b/src/runtime/NEON/INESimpleFunctionNoBorder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 ARM Limited. + * Copyright (c) 2018-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -24,16 +24,18 @@ #include "arm_compute/runtime/NEON/INESimpleFunctionNoBorder.h" #include "arm_compute/runtime/NEON/NEScheduler.h" +#include "arm_compute/runtime/Utils.h" namespace arm_compute { -INESimpleFunctionNoBorder::INESimpleFunctionNoBorder() // NOLINT - : _kernel() +INESimpleFunctionNoBorder::INESimpleFunctionNoBorder(IRuntimeContext *ctx) + : _kernel(), + _ctx(ctx) { } void INESimpleFunctionNoBorder::run() { - NEScheduler::get().schedule(_kernel.get(), Window::DimY); + schedule_kernel_on_ctx(_ctx, _kernel.get(), Window::DimY); } } // namespace arm_compute diff --git a/src/runtime/NEON/functions/NEActivationLayer.cpp b/src/runtime/NEON/functions/NEActivationLayer.cpp index 6af71a3580..1b8651487d 100644 --- a/src/runtime/NEON/functions/NEActivationLayer.cpp +++ b/src/runtime/NEON/functions/NEActivationLayer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -24,10 +24,15 @@ #include "arm_compute/runtime/NEON/functions/NEActivationLayer.h" #include "arm_compute/core/NEON/kernels/NEActivationLayerKernel.h" +#include "arm_compute/runtime/IRuntimeContext.h" #include "support/ToolchainSupport.h" -using namespace arm_compute; - +namespace arm_compute +{ +NEActivationLayer::NEActivationLayer(IRuntimeContext *ctx) // NOLINT + : INESimpleFunctionNoBorder(ctx) +{ +} void NEActivationLayer::configure(ITensor *input, ITensor *output, ActivationLayerInfo activation_info) { auto k = arm_compute::support::cpp14::make_unique(); @@ -39,3 +44,4 @@ Status NEActivationLayer::validate(const ITensorInfo *input, const ITensorInfo * { return NEActivationLayerKernel::validate(input, output, act_info); } +} // namespace arm_compute diff --git a/src/runtime/OMP/OMPScheduler.cpp b/src/runtime/OMP/OMPScheduler.cpp index 2355389dbd..f67f06fc94 100644 --- a/src/runtime/OMP/OMPScheduler.cpp +++ b/src/runtime/OMP/OMPScheduler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -31,14 +31,8 @@ #include -using namespace arm_compute; - -OMPScheduler &OMPScheduler::get() +namespace arm_compute { - static OMPScheduler scheduler; - return scheduler; -} - OMPScheduler::OMPScheduler() // NOLINT : _num_threads(omp_get_max_threads()) { @@ -109,3 +103,4 @@ void OMPScheduler::run_workloads(std::vector } } #endif /* DOXYGEN_SKIP_THIS */ +} // namespace arm_compute diff --git a/src/runtime/RuntimeContext.cpp b/src/runtime/RuntimeContext.cpp new file mode 100644 index 0000000000..308e2788a9 --- /dev/null +++ b/src/runtime/RuntimeContext.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019 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 "arm_compute/runtime/RuntimeContext.h" + +#include "arm_compute/core/Validate.h" +#include "arm_compute/runtime/SchedulerFactory.h" + +namespace arm_compute +{ +RuntimeContext::RuntimeContext() + : _owned_scheduler(SchedulerFactory::create()), _scheduler(_owned_scheduler.get()), _device_props() +{ +} + +void RuntimeContext::set_scheduler(IScheduler *scheduler) +{ + ARM_COMPUTE_ERROR_ON_NULLPTR(scheduler); + _scheduler = scheduler; +} + +IScheduler *RuntimeContext::scheduler() +{ + return _scheduler; +} + +IAssetManager *RuntimeContext::asset_manager() +{ + return nullptr; +} + +const DeviceProperties &RuntimeContext::properties() +{ + return _device_props; +} +} // namespace arm_compute diff --git a/src/runtime/Scheduler.cpp b/src/runtime/Scheduler.cpp index 8925acfa47..1af39d8122 100644 --- a/src/runtime/Scheduler.cpp +++ b/src/runtime/Scheduler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -24,6 +24,8 @@ #include "arm_compute/runtime/Scheduler.h" #include "arm_compute/core/Error.h" +#include "support/ToolchainSupport.h" + #if ARM_COMPUTE_CPP_SCHEDULER #include "arm_compute/runtime/CPP/CPPScheduler.h" #endif /* ARM_COMPUTE_CPP_SCHEDULER */ @@ -46,6 +48,27 @@ Scheduler::Type Scheduler::_scheduler_type = Scheduler::Type::CPP; Scheduler::Type Scheduler::_scheduler_type = Scheduler::Type::ST; #endif /* ARM_COMPUTE_*_SCHEDULER */ +std::shared_ptr Scheduler::_custom_scheduler = nullptr; + +namespace +{ +std::map> init() +{ + std::map> m; + m[Scheduler::Type::ST] = support::cpp14::make_unique(); +#if defined(ARM_COMPUTE_CPP_SCHEDULER) + m[Scheduler::Type::CPP] = support::cpp14::make_unique(); +#endif // defined(ARM_COMPUTE_CPP_SCHEDULER) +#if defined(ARM_COMPUTE_OPENMP_SCHEDULER) + m[Scheduler::Type::OMP] = support::cpp14::make_unique(); +#endif // defined(ARM_COMPUTE_OPENMP_SCHEDULER) + + return m; +} +} // namespace + +std::map> Scheduler::_schedulers = init(); + void Scheduler::set(Type t) { ARM_COMPUTE_ERROR_ON(!Scheduler::is_available(t)); @@ -54,37 +77,13 @@ void Scheduler::set(Type t) bool Scheduler::is_available(Type t) { - switch(t) + if(t == Type::CUSTOM) { - case Type::ST: - { - return true; - } - case Type::CPP: - { -#if ARM_COMPUTE_CPP_SCHEDULER - return true; -#else /* ARM_COMPUTE_CPP_SCHEDULER */ - return false; -#endif /* ARM_COMPUTE_CPP_SCHEDULER */ - } - case Type::OMP: - { -#if ARM_COMPUTE_OPENMP_SCHEDULER - return true; -#else /* ARM_COMPUTE_OPENMP_SCHEDULER */ - return false; -#endif /* ARM_COMPUTE_OPENMP_SCHEDULER */ - } - case Type::CUSTOM: - { - return _custom_scheduler != nullptr; - } - default: - { - ARM_COMPUTE_ERROR("Invalid Scheduler type"); - return false; - } + return _custom_scheduler != nullptr; + } + else + { + return _schedulers.find(t) != _schedulers.end(); } } @@ -95,53 +94,31 @@ Scheduler::Type Scheduler::get_type() IScheduler &Scheduler::get() { - switch(_scheduler_type) + if(_scheduler_type == Type::CUSTOM) { - case Type::ST: - { - return SingleThreadScheduler::get(); - } - case Type::CPP: + if(_custom_scheduler == nullptr) { -#if ARM_COMPUTE_CPP_SCHEDULER - return CPPScheduler::get(); -#else /* ARM_COMPUTE_CPP_SCHEDULER */ - ARM_COMPUTE_ERROR("Recompile with cppthreads=1 to use C++11 scheduler."); -#endif /* ARM_COMPUTE_CPP_SCHEDULER */ - break; + ARM_COMPUTE_ERROR("No custom scheduler has been setup. Call set(std::shared_ptr &scheduler) before Scheduler::get()"); } - case Type::OMP: + else { -#if ARM_COMPUTE_OPENMP_SCHEDULER - return OMPScheduler::get(); -#else /* ARM_COMPUTE_OPENMP_SCHEDULER */ - ARM_COMPUTE_ERROR("Recompile with openmp=1 to use openmp scheduler."); -#endif /* ARM_COMPUTE_OPENMP_SCHEDULER */ - break; + return *_custom_scheduler; } - case Type::CUSTOM: + } + else + { + auto it = _schedulers.find(_scheduler_type); + if(it != _schedulers.end()) { - if(_custom_scheduler == nullptr) - { - ARM_COMPUTE_ERROR("No custom scheduler has been setup. Call set(std::shared_ptr &scheduler) before Scheduler::get()"); - } - else - { - return *_custom_scheduler; - } - break; + return *it->second; } - default: + else { ARM_COMPUTE_ERROR("Invalid Scheduler type"); - break; } } - return SingleThreadScheduler::get(); } -std::shared_ptr Scheduler::_custom_scheduler = nullptr; - void Scheduler::set(std::shared_ptr scheduler) { _custom_scheduler = std::move(scheduler); diff --git a/src/runtime/SchedulerFactory.cpp b/src/runtime/SchedulerFactory.cpp new file mode 100644 index 0000000000..8bdd510367 --- /dev/null +++ b/src/runtime/SchedulerFactory.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019 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 "arm_compute/runtime/SchedulerFactory.h" + +#include "support/ToolchainSupport.h" + +#include "arm_compute/core/Error.h" +#if ARM_COMPUTE_CPP_SCHEDULER +#include "arm_compute/runtime/CPP/CPPScheduler.h" +#endif /* ARM_COMPUTE_CPP_SCHEDULER */ + +#include "arm_compute/runtime/SingleThreadScheduler.h" + +#if ARM_COMPUTE_OPENMP_SCHEDULER +#include "arm_compute/runtime/OMP/OMPScheduler.h" +#endif /* ARM_COMPUTE_OPENMP_SCHEDULER */ + +namespace arm_compute +{ +#if !ARM_COMPUTE_CPP_SCHEDULER && ARM_COMPUTE_OPENMP_SCHEDULER +const SchedulerFactory::Type SchedulerFactory::_default_type = SchedulerFactory::Type::OMP; +#elif ARM_COMPUTE_CPP_SCHEDULER && !ARM_COMPUTE_OPENMP_SCHEDULER +const SchedulerFactory::Type SchedulerFactory::_default_type = SchedulerFactory::Type::CPP; +#elif ARM_COMPUTE_CPP_SCHEDULER && ARM_COMPUTE_OPENMP_SCHEDULER +const SchedulerFactory::Type SchedulerFactory::_default_type = SchedulerFactory::Type::CPP; +#else /* ARM_COMPUTE_*_SCHEDULER */ +const SchedulerFactory::Type SchedulerFactory::_default_type = SchedulerFactory::Type::ST; +#endif /* ARM_COMPUTE_*_SCHEDULER */ + +std::unique_ptr SchedulerFactory::create(Type type) +{ + switch(type) + { + case Type::ST: + { + return support::cpp14::make_unique(); + } + case Type::CPP: + { +#if ARM_COMPUTE_CPP_SCHEDULER + return support::cpp14::make_unique(); +#else /* ARM_COMPUTE_CPP_SCHEDULER */ + ARM_COMPUTE_ERROR("Recompile with cppthreads=1 to use C++11 scheduler."); +#endif /* ARM_COMPUTE_CPP_SCHEDULER */ + } + case Type::OMP: + { +#if ARM_COMPUTE_OPENMP_SCHEDULER + return support::cpp14::make_unique(); +#else /* ARM_COMPUTE_OPENMP_SCHEDULER */ + ARM_COMPUTE_ERROR("Recompile with openmp=1 to use openmp scheduler."); +#endif /* ARM_COMPUTE_OPENMP_SCHEDULER */ + } + default: + { + ARM_COMPUTE_ERROR("Invalid Scheduler type"); + break; + } + } +} +} // namespace arm_compute diff --git a/src/runtime/Utils.cpp b/src/runtime/Utils.cpp index 81de782399..70494be05c 100644 --- a/src/runtime/Utils.cpp +++ b/src/runtime/Utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -23,16 +23,20 @@ */ #include "arm_compute/runtime/Utils.h" +#include "arm_compute/runtime/NEON/NEScheduler.h" + #include #include -using namespace arm_compute; - +namespace arm_compute +{ +#ifndef DOXYGEN_SKIP_THIS static const std::string information = #include "arm_compute_version.embed" ; +#endif /* DOXYGEN_SKIP_THIS */ -const std::string &arm_compute::string_from_scheduler_type(Scheduler::Type t) +const std::string &string_from_scheduler_type(Scheduler::Type t) { static std::map scheduler_type_map = { @@ -44,3 +48,17 @@ const std::string &arm_compute::string_from_scheduler_type(Scheduler::Type t) return scheduler_type_map[t]; } + +void schedule_kernel_on_ctx(IRuntimeContext *ctx, ICPPKernel *kernel, const IScheduler::Hints &hints) +{ + if(ctx) + { + ARM_COMPUTE_ERROR_ON(ctx->scheduler() == nullptr); + ctx->scheduler()->schedule(kernel, hints); + } + else + { + NEScheduler::get().schedule(kernel, hints); + } +} +} // namespace arm_compute diff --git a/tests/Globals.h b/tests/Globals.h index c4c450c5fe..569b1a31c6 100644 --- a/tests/Globals.h +++ b/tests/Globals.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -25,6 +25,7 @@ #define __ARM_COMPUTE_TEST_GLOBALS_H__ #include "tests/AssetsLibrary.h" +#include "tests/ParametersLibrary.h" #include @@ -32,7 +33,8 @@ namespace arm_compute { namespace test { -extern std::unique_ptr library; +extern std::unique_ptr library; +extern std::unique_ptr parameters; } // namespace test } // namespace arm_compute #endif /* __ARM_COMPUTE_TEST_GLOBALS_H__ */ diff --git a/tests/ParametersLibrary.cpp b/tests/ParametersLibrary.cpp new file mode 100644 index 0000000000..16152c8482 --- /dev/null +++ b/tests/ParametersLibrary.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019 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 "tests/ParametersLibrary.h" + +namespace arm_compute +{ +namespace test +{ +void ParametersLibrary::set_cpu_ctx(std::unique_ptr cpu_ctx) +{ + _cpu_ctx = std::move(cpu_ctx); +} + +template <> +typename ContextType::type *ParametersLibrary::get_ctx() +{ + return _cpu_ctx.get(); +} +} // namespace test +} // namespace arm_compute diff --git a/tests/ParametersLibrary.h b/tests/ParametersLibrary.h new file mode 100644 index 0000000000..a99be46d3f --- /dev/null +++ b/tests/ParametersLibrary.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019 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_PARAMETERS_LIBRARY_H__ +#define __ARM_COMPUTE_TEST_PARAMETERS_LIBRARY_H__ + +#include "arm_compute/runtime/IRuntimeContext.h" +#include "arm_compute/runtime/Tensor.h" + +#include + +namespace arm_compute +{ +namespace test +{ +// Return type trait helper +template +struct ContextType +{ + using type = void; +}; +template <> +struct ContextType +{ + using type = IRuntimeContext; +}; + +/** Class that contains all the global parameters used by the tests */ +class ParametersLibrary final +{ +public: + /** Default constructor */ + ParametersLibrary() = default; + /** Set cpu context to be used by the tests + * + * @param[in] cpu_ctx CPU context to use + */ + void set_cpu_ctx(std::unique_ptr cpu_ctx); + /** Get context given a tensor type + * + * @tparam TensorType + * + * @return Pointer to the context + */ + template + typename ContextType::type *get_ctx() + { + return nullptr; + } + +private: + std::unique_ptr _cpu_ctx{ nullptr }; +}; +} // namespace test +} // namespace arm_compute +#endif //__ARM_COMPUTE_TEST_PARAMETERS_LIBRARY_H__ diff --git a/tests/Utils.h b/tests/Utils.h index f88b01dc40..f26507d1a0 100644 --- a/tests/Utils.h +++ b/tests/Utils.h @@ -54,6 +54,9 @@ #include #include +#include "arm_compute/runtime/CPP/CPPScheduler.h" +#include "arm_compute/runtime/RuntimeContext.h" + namespace arm_compute { #ifdef ARM_COMPUTE_CL diff --git a/tests/benchmark/fixtures/ActivationLayerFixture.h b/tests/benchmark/fixtures/ActivationLayerFixture.h index a82861f624..2ac10b2746 100644 --- a/tests/benchmark/fixtures/ActivationLayerFixture.h +++ b/tests/benchmark/fixtures/ActivationLayerFixture.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -41,6 +41,11 @@ template class ActivationLayerFixture : public framework::Fixture { public: + ActivationLayerFixture() + : src(), dst(), act_layer(parameters->get_ctx()) + { + } + template void setup(TensorShape shape, ActivationLayerInfo info, DataType data_type, int batches) { @@ -78,9 +83,9 @@ public: } private: - TensorType src{}; - TensorType dst{}; - Function act_layer{}; + TensorType src; + TensorType dst; + Function act_layer; }; } // namespace benchmark } // namespace test diff --git a/tests/framework/Framework.cpp b/tests/framework/Framework.cpp index cc7852906c..fbc2456047 100644 --- a/tests/framework/Framework.cpp +++ b/tests/framework/Framework.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -40,6 +40,8 @@ namespace test { namespace framework { +std::unique_ptr instruments_info; + Framework::Framework() { _available_instruments.emplace(std::pair(InstrumentType::WALL_CLOCK_TIMESTAMPS, ScaleFactor::NONE), Instrument::make_instrument); @@ -83,6 +85,8 @@ Framework::Framework() _available_instruments.emplace(std::pair(InstrumentType::OPENCL_MEMORY_USAGE, ScaleFactor::SCALE_1M), Instrument::make_instrument); #endif /* ARM_COMPUTE_CL */ + + instruments_info = support::cpp14::make_unique(); } std::set Framework::available_instruments() const @@ -679,6 +683,12 @@ LogLevel Framework::log_level() const { return _log_level; } + +void Framework::set_instruments_info(InstrumentsInfo instr_info) +{ + ARM_COMPUTE_ERROR_ON(instruments_info == nullptr); + *instruments_info = instr_info; +} } // namespace framework } // namespace test } // namespace arm_compute diff --git a/tests/framework/Framework.h b/tests/framework/Framework.h index 65ffc0a818..c02416f9b5 100644 --- a/tests/framework/Framework.h +++ b/tests/framework/Framework.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -293,6 +293,13 @@ public: * @return The current logging level. */ LogLevel log_level() const; + /** Sets instruments info + * + * @note TODO(COMPMID-2638) : Remove once instruments are transferred outside the framework. + * + * @param[in] instr_info Instruments info to set + */ + void set_instruments_info(InstrumentsInfo instr_info); private: Framework(); diff --git a/tests/framework/instruments/Instruments.h b/tests/framework/instruments/Instruments.h index 370db8d4dc..8adf501c18 100644 --- a/tests/framework/instruments/Instruments.h +++ b/tests/framework/instruments/Instruments.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -33,6 +33,7 @@ #include "SchedulerTimer.h" #include "WallClockTimer.h" +#include #include #include @@ -59,6 +60,12 @@ enum class InstrumentType : unsigned int SCHEDULER_TIMESTAMPS = 0x0900, }; +struct InstrumentsInfo +{ + std::vector _scheduler_users{}; +}; +extern std::unique_ptr instruments_info; + using InstrumentsDescription = std::pair; InstrumentsDescription instrument_type_from_name(const std::string &name); diff --git a/tests/framework/instruments/SchedulerTimer.cpp b/tests/framework/instruments/SchedulerTimer.cpp index c114dfbd9d..98c9b878d9 100644 --- a/tests/framework/instruments/SchedulerTimer.cpp +++ b/tests/framework/instruments/SchedulerTimer.cpp @@ -23,6 +23,7 @@ */ #include "SchedulerTimer.h" +#include "Instruments.h" #include "WallClockTimer.h" #include "arm_compute/core/CPP/ICPPKernel.h" #include "arm_compute/core/utils/misc/Cast.h" @@ -114,8 +115,12 @@ private: template SchedulerClock::SchedulerClock(ScaleFactor scale_factor) - : _kernels(), _real_scheduler(nullptr), _real_scheduler_type(), _real_graph_function(nullptr), _scale_factor(scale_factor), _interceptor(nullptr) + : _kernels(), _real_scheduler(nullptr), _real_scheduler_type(), _real_graph_function(nullptr), _scale_factor(scale_factor), _interceptor(nullptr), _scheduler_users() { + if(instruments_info != nullptr) + { + _scheduler_users = instruments_info->_scheduler_users; + } } template @@ -157,6 +162,17 @@ void SchedulerClock::test_start() _interceptor = std::make_shared>(_kernels, *_real_scheduler, _scale_factor); Scheduler::set(std::static_pointer_cast(_interceptor)); graph::TaskExecutor::get().execute_function = task_interceptor; + + // Create an interceptor for each scheduler + // TODO(COMPID-2638) : Allow multiple schedulers, now it assumes the same scheduler is used. + std::for_each(std::begin(_scheduler_users), std::end(_scheduler_users), + [&](ISchedulerUser * user) + { + if(user != nullptr && user->scheduler() != nullptr) + { + user->intercept_scheduler(support::cpp14::make_unique>(_kernels, *user->scheduler(), _scale_factor)); + } + }); } } @@ -175,6 +191,16 @@ void SchedulerClock::test_stop() _interceptor = nullptr; graph::TaskExecutor::get().execute_function = _real_graph_function; _real_graph_function = nullptr; + + // Restore schedulers + std::for_each(std::begin(_scheduler_users), std::end(_scheduler_users), + [&](ISchedulerUser * user) + { + if(user != nullptr) + { + user->restore_scheduler(); + } + }); } template diff --git a/tests/framework/instruments/SchedulerTimer.h b/tests/framework/instruments/SchedulerTimer.h index 64adb488ae..ea64b227eb 100644 --- a/tests/framework/instruments/SchedulerTimer.h +++ b/tests/framework/instruments/SchedulerTimer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -29,6 +29,8 @@ #include "arm_compute/runtime/Scheduler.h" #include +#include +#include namespace arm_compute { @@ -36,6 +38,26 @@ namespace test { namespace framework { +/** Scheduler user interface */ +class ISchedulerUser +{ +public: + /** Default Destructor */ + virtual ~ISchedulerUser() = default; + /** Intercept the scheduler used by + * + * @param interceptor Intercept the scheduler used by the scheduler user. + */ + virtual void intercept_scheduler(std::unique_ptr interceptor) = 0; + /** Restore the original scheduler */ + virtual void restore_scheduler() = 0; + /** Real scheduler accessor + * + * @return The real scheduler + */ + virtual IScheduler *scheduler() = 0; +}; + /** Instrument creating measurements based on the information returned by clGetEventProfilingInfo for each OpenCL kernel executed*/ template class SchedulerClock : public Instrument @@ -46,7 +68,6 @@ public: * @param[in] scale_factor Measurement scale factor. */ SchedulerClock(ScaleFactor scale_factor); - /** Prevent instances of this class from being copy constructed */ SchedulerClock(const SchedulerClock &) = delete; /** Prevent instances of this class from being copied */ @@ -58,6 +79,7 @@ public: /** Use the default destructor */ ~SchedulerClock() = default; + // Inherited overridden methods std::string id() const override; void test_start() override; void start() override; @@ -79,6 +101,7 @@ private: std::function _real_graph_function; ScaleFactor _scale_factor; std::shared_ptr _interceptor; + std::vector _scheduler_users; }; using SchedulerTimer = SchedulerClock; diff --git a/tests/instruments/Helpers.h b/tests/instruments/Helpers.h new file mode 100644 index 0000000000..07387f10f8 --- /dev/null +++ b/tests/instruments/Helpers.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2019 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_INSTRUMENTS_UTILS_H__ +#define __ARM_COMPUTE_TEST_INSTRUMENTS_UTILS_H__ + +#include "arm_compute/runtime/RuntimeContext.h" +#include "tests/framework/instruments/Instruments.h" + +namespace arm_compute +{ +namespace test +{ +class ContextSchedulerUser : public framework::ISchedulerUser +{ +public: + /** Default Constructor + * + * @param[in] ctx Runtime context to track + */ + ContextSchedulerUser(RuntimeContext *ctx) + : _ctx(ctx), _scheduler_to_use(nullptr), _real_scheduler(nullptr), _interceptor(nullptr) + { + ARM_COMPUTE_ERROR_ON(ctx == nullptr); + _real_scheduler = _ctx->scheduler(); + _scheduler_to_use = _real_scheduler; + } + /** Prevent instances of this class from being copied (As this class contains pointers) */ + ContextSchedulerUser(const ContextSchedulerUser &) = delete; + /** Default move constructor */ + ContextSchedulerUser(ContextSchedulerUser &&) = default; + /** Prevent instances of this class from being copied (As this class contains pointers) */ + ContextSchedulerUser &operator=(const ContextSchedulerUser &) = delete; + /** Default move assignment operator */ + ContextSchedulerUser &operator=(ContextSchedulerUser &&) = default; + + // Overridden inherited methods + void intercept_scheduler(std::unique_ptr interceptor) + { + if(interceptor != nullptr) + { + _interceptor = std::move(interceptor); + _scheduler_to_use = _interceptor.get(); + _ctx->set_scheduler(_scheduler_to_use); + } + } + void restore_scheduler() + { + _interceptor = nullptr; + _scheduler_to_use = _real_scheduler; + _ctx->set_scheduler(_scheduler_to_use); + } + IScheduler *scheduler() + { + return _real_scheduler; + } + +private: + RuntimeContext *_ctx; + IScheduler *_scheduler_to_use; + IScheduler *_real_scheduler; + std::unique_ptr _interceptor; +}; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_INSTRUMENTS_UTILS_H__ */ diff --git a/tests/main.cpp b/tests/main.cpp index 9690eb9a00..01741939a0 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -23,6 +23,7 @@ */ #include "support/ToolchainSupport.h" #include "tests/AssetsLibrary.h" +#include "tests/ParametersLibrary.h" #include "tests/framework/DatasetModes.h" #include "tests/framework/Exceptions.h" #include "tests/framework/Framework.h" @@ -31,6 +32,7 @@ #include "tests/framework/command_line/CommonOptions.h" #include "tests/framework/instruments/Instruments.h" #include "tests/framework/printers/Printers.h" +#include "tests/instruments/Helpers.h" #include "utils/command_line/CommandLineOptions.h" #include "utils/command_line/CommandLineParser.h" @@ -72,7 +74,8 @@ namespace arm_compute { namespace test { -std::unique_ptr library; +std::unique_ptr library; +std::unique_ptr parameters; } // namespace test } // namespace arm_compute @@ -167,7 +170,20 @@ int main(int argc, char **argv) std::vector> printers = options.create_printers(); + // Setup CPU Scheduler Scheduler::get().set_num_threads(threads->value()); + + // Create CPU context + auto cpu_ctx = support::cpp14::make_unique(); + cpu_ctx->set_scheduler(&Scheduler::get()); + + // Track CPU context + auto cpu_ctx_track = support::cpp14::make_unique(cpu_ctx.get()); + + // Create parameters + parameters = support::cpp14::make_unique(); + parameters->set_cpu_ctx(std::move(cpu_ctx)); + #ifdef ARM_COMPUTE_CL if(enable_tuner->is_set()) { @@ -232,7 +248,19 @@ int main(int argc, char **argv) } } - framework.init(options.instruments->value(), options.iterations->value(), dataset_mode->value(), filter->value(), filter_id->value(), options.log_level->value()); + // Setup instruments meta-data + framework::InstrumentsInfo instruments_info; + instruments_info._scheduler_users.push_back(cpu_ctx_track.get()); + framework.set_instruments_info(instruments_info); + + // Initialize framework + framework.init(options.instruments->value(), + options.iterations->value(), + dataset_mode->value(), + filter->value(), + filter_id->value(), + options.log_level->value()); + for(auto &p : printers) { framework.add_printer(p.get()); diff --git a/tests/validation/CL/ActivationLayer.cpp b/tests/validation/CL/ActivationLayer.cpp index e97f12f5a3..250777d541 100644 --- a/tests/validation/CL/ActivationLayer.cpp +++ b/tests/validation/CL/ActivationLayer.cpp @@ -25,6 +25,7 @@ #include "arm_compute/runtime/CL/CLTensor.h" #include "arm_compute/runtime/CL/CLTensorAllocator.h" #include "arm_compute/runtime/CL/functions/CLActivationLayer.h" +#include "arm_compute/runtime/RuntimeContext.h" #include "tests/CL/CLAccessor.h" #include "tests/PaddingCalculator.h" #include "tests/datasets/ActivationFunctionsDataset.h" diff --git a/tests/validation/NEON/ActivationLayer.cpp b/tests/validation/NEON/ActivationLayer.cpp index eb3a37fba7..8c18d47da9 100644 --- a/tests/validation/NEON/ActivationLayer.cpp +++ b/tests/validation/NEON/ActivationLayer.cpp @@ -23,6 +23,7 @@ */ #include "arm_compute/core/Types.h" #include "arm_compute/runtime/NEON/functions/NEActivationLayer.h" +#include "arm_compute/runtime/RuntimeContext.h" #include "arm_compute/runtime/Tensor.h" #include "arm_compute/runtime/TensorAllocator.h" #include "tests/NEON/Accessor.h" @@ -133,8 +134,11 @@ DATA_TEST_CASE(Configuration, framework::DatasetMode::ALL, combine(combine(datas ARM_COMPUTE_EXPECT(src.info()->is_resizable(), framework::LogLevel::ERRORS); ARM_COMPUTE_EXPECT(dst.info()->is_resizable(), framework::LogLevel::ERRORS); + // Create context + RuntimeContext ctx; + // Create and configure function - NEActivationLayer act_layer; + NEActivationLayer act_layer(&ctx); if(in_place) { diff --git a/tests/validation/NEON/UNIT/RuntimeContext.cpp b/tests/validation/NEON/UNIT/RuntimeContext.cpp new file mode 100644 index 0000000000..05670a94e8 --- /dev/null +++ b/tests/validation/NEON/UNIT/RuntimeContext.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2019 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 "arm_compute/runtime/RuntimeContext.h" + +#include "arm_compute/runtime/CPP/CPPScheduler.h" +#include "arm_compute/runtime/NEON/functions/NEActivationLayer.h" +#include "arm_compute/runtime/Tensor.h" +#include "support/ToolchainSupport.h" +#include "tests/Globals.h" +#include "tests/NEON/Accessor.h" +#include "tests/Utils.h" +#include "tests/framework/Asserts.h" +#include "tests/framework/Macros.h" +#include "tests/validation/Validation.h" +#include "tests/validation/reference/ActivationLayer.h" + +#include +#include +#if !defined(BARE_METAL) +#include +#endif // !defined(BARE_METAL) + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +TEST_SUITE(NEON) +TEST_SUITE(UNIT) +TEST_SUITE(RuntimeContext) + +TEST_CASE(Scheduler, framework::DatasetMode::ALL) +{ + using namespace arm_compute; + // Create a runtime context object + RuntimeContext ctx; + + // Check if it's been initialised properly + ARM_COMPUTE_EXPECT(ctx.scheduler() != nullptr, framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(ctx.asset_manager() == nullptr, framework::LogLevel::ERRORS); + + // Create a CPPScheduler + CPPScheduler scheduler; + ctx.set_scheduler(&scheduler); + // Check if the scheduler has been properly setup + ARM_COMPUTE_EXPECT(ctx.scheduler() != nullptr, framework::LogLevel::ERRORS); + + // Create a new activation function + NEActivationLayer act_layer(&ctx); + + Tensor src = create_tensor(TensorShape(32, 32), DataType::F32, 1); + Tensor dst = create_tensor(TensorShape(32, 32), DataType::F32, 1); + + act_layer.configure(&src, &dst, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LINEAR)); + + ARM_COMPUTE_EXPECT(src.info()->is_resizable(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(dst.info()->is_resizable(), framework::LogLevel::ERRORS); + + // Allocate tensors + src.allocator()->allocate(); + dst.allocator()->allocate(); + + ARM_COMPUTE_EXPECT(!src.info()->is_resizable(), framework::LogLevel::ERRORS); + + float min_bound = 0; + float max_bound = 0; + std::tie(min_bound, max_bound) = get_activation_layer_test_bounds(ActivationLayerInfo::ActivationFunction::LINEAR, DataType::F32); + std::uniform_real_distribution<> distribution(min_bound, max_bound); + library->fill(Accessor(src), distribution, 0); + + // Compute function + act_layer.run(); +} + +#if !defined(BARE_METAL) +// This test tries scheduling work concurrently from two independent threads +TEST_CASE(MultipleThreadedScheduller, framework::DatasetMode::ALL) +{ + // Create a runtime context object for thread 1 + RuntimeContext ctx1; + + // Create a runtime context object for thread 2 + RuntimeContext ctx2; + + // Create a new activation function + NEActivationLayer act_layer_thread0(&ctx1); + NEActivationLayer act_layer_thread1(&ctx2); + + const TensorShape tensor_shape(128, 128); + Tensor src_t0 = create_tensor(tensor_shape, DataType::F32, 1); + Tensor dst_t0 = create_tensor(tensor_shape, DataType::F32, 1); + Tensor src_t1 = create_tensor(tensor_shape, DataType::F32, 1); + Tensor dst_t1 = create_tensor(tensor_shape, DataType::F32, 1); + ActivationLayerInfo activation_info(ActivationLayerInfo::ActivationFunction::LINEAR); + + act_layer_thread0.configure(&src_t0, &dst_t0, activation_info); + act_layer_thread1.configure(&src_t1, &dst_t1, activation_info); + + ARM_COMPUTE_EXPECT(src_t0.info()->is_resizable(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(dst_t0.info()->is_resizable(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(src_t1.info()->is_resizable(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(dst_t1.info()->is_resizable(), framework::LogLevel::ERRORS); + + // Allocate tensors + src_t0.allocator()->allocate(); + dst_t0.allocator()->allocate(); + src_t1.allocator()->allocate(); + dst_t1.allocator()->allocate(); + + ARM_COMPUTE_EXPECT(!src_t0.info()->is_resizable(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(!src_t1.info()->is_resizable(), framework::LogLevel::ERRORS); + + float min_bound = 0; + float max_bound = 0; + std::tie(min_bound, max_bound) = get_activation_layer_test_bounds(ActivationLayerInfo::ActivationFunction::LINEAR, DataType::F32); + std::uniform_real_distribution<> distribution(min_bound, max_bound); + library->fill(Accessor(src_t0), distribution, 0); + library->fill(Accessor(src_t1), distribution, 0); + + std::thread neon_thread1([&] { act_layer_thread0.run(); }); + std::thread neon_thread2([&] { act_layer_thread1.run(); }); + + neon_thread1.join(); + neon_thread2.join(); + + Window window; + window.use_tensor_dimensions(dst_t0.info()->tensor_shape()); + Iterator t0_it(&dst_t0, window); + Iterator t1_it(&dst_t1, window); + execute_window_loop(window, [&](const Coordinates &) + { + const bool match = (*reinterpret_cast(t0_it.ptr()) == *reinterpret_cast(t1_it.ptr())); + ARM_COMPUTE_EXPECT(match, framework::LogLevel::ERRORS); + }, + t0_it, t1_it); +} +#endif // !defined(BARE_METAL) + +TEST_SUITE_END() // RuntimeContext +TEST_SUITE_END() // UNIT +TEST_SUITE_END() // NEON +} // namespace validation +} // namespace test +} // namespace arm_compute diff --git a/tests/validation/fixtures/ActivationLayerFixture.h b/tests/validation/fixtures/ActivationLayerFixture.h index d9f26b7368..8fa74979a8 100644 --- a/tests/validation/fixtures/ActivationLayerFixture.h +++ b/tests/validation/fixtures/ActivationLayerFixture.h @@ -29,6 +29,7 @@ #include "tests/AssetsLibrary.h" #include "tests/Globals.h" #include "tests/IAccessor.h" +#include "tests/ParametersLibrary.h" #include "tests/framework/Asserts.h" #include "tests/framework/Fixture.h" #include "tests/validation/Helpers.h" @@ -94,7 +95,7 @@ protected: TensorType dst = create_tensor(shape, _data_type, 1, _output_quantization_info); // Create and configure function - FunctionType act_layer; + FunctionType act_layer(parameters->get_ctx()); TensorType *dst_ptr = _in_place ? nullptr : &dst; -- cgit v1.2.1