diff options
42 files changed, 1179 insertions, 171 deletions
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 <list> +#include <memory> 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<Workload> &workloads) override; private: - class Thread; - /** Constructor: create a pool of threads. */ - CPPScheduler(); - - unsigned int _num_threads; - std::list<Thread> _threads; + struct Impl; + std::unique_ptr<Impl> _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 <memory> @@ -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<INEKernel> _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<Workload> &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 <memory> + +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<IScheduler> _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 <map> #include <memory> namespace arm_compute @@ -74,7 +76,9 @@ public: private: static Type _scheduler_type; static std::shared_ptr<IScheduler> _custom_scheduler; + static std::map<Type, std::unique_ptr<IScheduler>> _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 <memory> + +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<IScheduler> 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<Workload> &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 <string> @@ -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 <atomic> #include <condition_variable> #include <iostream> +#include <list> #include <mutex> #include <system_error> #include <thread> @@ -90,7 +91,31 @@ void process_workloads(std::vector<IScheduler::Workload> &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<IScheduler::Workload> &workloads); + + class Thread; + + unsigned int _num_threads; + std::list<Thread> _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<IScheduler::Workload> *workloads, ThreadFeeder &feeder, const ThreadInfo &info) +void CPPScheduler::Impl::Thread::start(std::vector<IScheduler::Workload> *workloads, ThreadFeeder &feeder, const ThreadInfo &info) { _workloads = workloads; _feeder = &feeder; @@ -161,7 +186,7 @@ void CPPScheduler::Thread::start(std::vector<IScheduler::Workload> *workloads, T _cv.notify_one(); } -void CPPScheduler::Thread::wait() +void CPPScheduler::Impl::Thread::wait() { { std::unique_lock<std::mutex> 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<Impl>(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<IScheduler::Workload> &workloads) { - const unsigned int num_threads = std::min(_num_threads, static_cast<unsigned int>(workloads.size())); + const unsigned int num_threads = std::min(_impl->num_threads(), static_cast<unsigned int>(workloads.size())); if(num_threads < 1) { return; @@ -245,7 +273,7 @@ void CPPScheduler::run_workloads(std::vector<IScheduler::Workload> &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<IScheduler::Workload> &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<unsigned int>(_num_threads) * 3; + const unsigned int max_iterations = static_cast<unsigned int>(_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<NEActivationLayerKernel>(); @@ -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 <omp.h> -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<arm_compute::IScheduler::Workload> } } #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<IScheduler> Scheduler::_custom_scheduler = nullptr; + +namespace +{ +std::map<Scheduler::Type, std::unique_ptr<IScheduler>> init() +{ + std::map<Scheduler::Type, std::unique_ptr<IScheduler>> m; + m[Scheduler::Type::ST] = support::cpp14::make_unique<SingleThreadScheduler>(); +#if defined(ARM_COMPUTE_CPP_SCHEDULER) + m[Scheduler::Type::CPP] = support::cpp14::make_unique<CPPScheduler>(); +#endif // defined(ARM_COMPUTE_CPP_SCHEDULER) +#if defined(ARM_COMPUTE_OPENMP_SCHEDULER) + m[Scheduler::Type::OMP] = support::cpp14::make_unique<OMPScheduler>(); +#endif // defined(ARM_COMPUTE_OPENMP_SCHEDULER) + + return m; +} +} // namespace + +std::map<Scheduler::Type, std::unique_ptr<IScheduler>> 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<IScheduler> &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<IScheduler> &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<IScheduler> Scheduler::_custom_scheduler = nullptr; - void Scheduler::set(std::shared_ptr<IScheduler> 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<IScheduler> SchedulerFactory::create(Type type) +{ + switch(type) + { + case Type::ST: + { + return support::cpp14::make_unique<SingleThreadScheduler>(); + } + case Type::CPP: + { +#if ARM_COMPUTE_CPP_SCHEDULER + return support::cpp14::make_unique<CPPScheduler>(); +#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<OMPScheduler>(); +#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 <map> #include <string> -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, const std::string> 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 <memory> @@ -32,7 +33,8 @@ namespace arm_compute { namespace test { -extern std::unique_ptr<AssetsLibrary> library; +extern std::unique_ptr<AssetsLibrary> library; +extern std::unique_ptr<ParametersLibrary> 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<IRuntimeContext> cpu_ctx) +{ + _cpu_ctx = std::move(cpu_ctx); +} + +template <> +typename ContextType<Tensor>::type *ParametersLibrary::get_ctx<Tensor>() +{ + 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 <memory> + +namespace arm_compute +{ +namespace test +{ +// Return type trait helper +template <class T> +struct ContextType +{ + using type = void; +}; +template <> +struct ContextType<Tensor> +{ + 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<IRuntimeContext> cpu_ctx); + /** Get context given a tensor type + * + * @tparam TensorType + * + * @return Pointer to the context + */ + template <typename TensorType> + typename ContextType<TensorType>::type *get_ctx() + { + return nullptr; + } + +private: + std::unique_ptr<IRuntimeContext> _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 <type_traits> #include <vector> +#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 <typename TensorType, typename Function, typename Accessor> class ActivationLayerFixture : public framework::Fixture { public: + ActivationLayerFixture() + : src(), dst(), act_layer(parameters->get_ctx<TensorType>()) + { + } + template <typename...> 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<InstrumentsInfo> instruments_info; + Framework::Framework() { _available_instruments.emplace(std::pair<InstrumentType, ScaleFactor>(InstrumentType::WALL_CLOCK_TIMESTAMPS, ScaleFactor::NONE), Instrument::make_instrument<WallClockTimestamps, ScaleFactor::NONE>); @@ -83,6 +85,8 @@ Framework::Framework() _available_instruments.emplace(std::pair<InstrumentType, ScaleFactor>(InstrumentType::OPENCL_MEMORY_USAGE, ScaleFactor::SCALE_1M), Instrument::make_instrument<OpenCLMemoryUsage, ScaleFactor::SCALE_1M>); #endif /* ARM_COMPUTE_CL */ + + instruments_info = support::cpp14::make_unique<InstrumentsInfo>(); } std::set<InstrumentsDescription> 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 <memory> #include <sstream> #include <string> @@ -59,6 +60,12 @@ enum class InstrumentType : unsigned int SCHEDULER_TIMESTAMPS = 0x0900, }; +struct InstrumentsInfo +{ + std::vector<ISchedulerUser *> _scheduler_users{}; +}; +extern std::unique_ptr<InstrumentsInfo> instruments_info; + using InstrumentsDescription = std::pair<InstrumentType, ScaleFactor>; 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 <bool output_timestamps> SchedulerClock<output_timestamps>::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 <bool output_timestamps> @@ -157,6 +162,17 @@ void SchedulerClock<output_timestamps>::test_start() _interceptor = std::make_shared<Interceptor<output_timestamps>>(_kernels, *_real_scheduler, _scale_factor); Scheduler::set(std::static_pointer_cast<IScheduler>(_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<Interceptor<output_timestamps>>(_kernels, *user->scheduler(), _scale_factor)); + } + }); } } @@ -175,6 +191,16 @@ void SchedulerClock<output_timestamps>::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 <bool output_timestamps> 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 <list> +#include <memory> +#include <vector> 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<IScheduler> 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 <bool output_timestamps> 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<decltype(graph::execute_task)> _real_graph_function; ScaleFactor _scale_factor; std::shared_ptr<IScheduler> _interceptor; + std::vector<ISchedulerUser *> _scheduler_users; }; using SchedulerTimer = SchedulerClock<false>; 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<IScheduler> 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<IScheduler> _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<AssetsLibrary> library; +std::unique_ptr<AssetsLibrary> library; +std::unique_ptr<ParametersLibrary> parameters; } // namespace test } // namespace arm_compute @@ -167,7 +170,20 @@ int main(int argc, char **argv) std::vector<std::unique_ptr<framework::Printer>> printers = options.create_printers(); + // Setup CPU Scheduler Scheduler::get().set_num_threads(threads->value()); + + // Create CPU context + auto cpu_ctx = support::cpp14::make_unique<RuntimeContext>(); + cpu_ctx->set_scheduler(&Scheduler::get()); + + // Track CPU context + auto cpu_ctx_track = support::cpp14::make_unique<ContextSchedulerUser>(cpu_ctx.get()); + + // Create parameters + parameters = support::cpp14::make_unique<ParametersLibrary>(); + 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 <memory> +#include <random> +#if !defined(BARE_METAL) +#include <thread> +#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<Tensor>(TensorShape(32, 32), DataType::F32, 1); + Tensor dst = create_tensor<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<float>(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>(tensor_shape, DataType::F32, 1); + Tensor dst_t0 = create_tensor<Tensor>(tensor_shape, DataType::F32, 1); + Tensor src_t1 = create_tensor<Tensor>(tensor_shape, DataType::F32, 1); + Tensor dst_t1 = create_tensor<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<float>(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<float *>(t0_it.ptr()) == *reinterpret_cast<float *>(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<TensorType>(shape, _data_type, 1, _output_quantization_info); // Create and configure function - FunctionType act_layer; + FunctionType act_layer(parameters->get_ctx<TensorType>()); TensorType *dst_ptr = _in_place ? nullptr : &dst; |