• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2017-2020 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 #ifndef ARM_COMPUTE_ISCHEDULER_H
25 #define ARM_COMPUTE_ISCHEDULER_H
26 
27 #include "arm_compute/core/CPP/CPPTypes.h"
28 #include "arm_compute/core/Types.h"
29 #include "arm_compute/core/experimental/Types.h"
30 
31 #include <functional>
32 #include <limits>
33 
34 namespace arm_compute
35 {
36 class ICPPKernel;
37 class ITensor;
38 
39 /** Scheduler interface to run kernels */
40 class IScheduler
41 {
42 public:
43     /** Strategies available to split a workload */
44     enum class StrategyHint
45     {
46         STATIC,  /**< Split the workload evenly among the threads */
47         DYNAMIC, /**< Split the workload dynamically using a bucket system */
48     };
49 
50     /** Function to be used and map a given thread id to a logical core id
51      *
52      * Mapping function expects the thread index and total number of cores as input,
53      * and returns the logical core index to bind against
54      */
55     using BindFunc = std::function<int(int, int)>;
56 
57     /** When arm_compute::ISchedular::Hints::_split_dimension is initialized with this value
58      * then the schedular is free to break down the problem space over as many dimensions
59      * as it wishes
60      */
61     static constexpr unsigned int split_dimensions_all = std::numeric_limits<unsigned>::max();
62 
63     /** Scheduler hints
64      *
65      * Collection of preferences set by the function regarding how to split a given workload
66      */
67     class Hints
68     {
69     public:
70         /** Constructor
71          *
72          * @param[in] split_dimension Dimension along which to split the kernel's execution window.
73          * @param[in] strategy        (Optional) Split strategy.
74          * @param[in] threshold       (Optional) Dynamic scheduling capping threshold.
75          */
76         Hints(unsigned int split_dimension, StrategyHint strategy = StrategyHint::STATIC, int threshold = 0)
_split_dimension(split_dimension)77             : _split_dimension(split_dimension), _strategy(strategy), _threshold(threshold)
78         {
79         }
80         /** Set the split_dimension hint
81          *
82          * @param[in] split_dimension Dimension along which to split the kernel's execution window.
83          *
84          * @return the Hints object
85          */
set_split_dimension(unsigned int split_dimension)86         Hints &set_split_dimension(unsigned int split_dimension)
87         {
88             _split_dimension = split_dimension;
89             return *this;
90         }
91         /** Return the prefered split dimension
92          *
93          * @return The split dimension
94          */
split_dimension()95         unsigned int split_dimension() const
96         {
97             return _split_dimension;
98         }
99 
100         /** Set the strategy hint
101          *
102          * @param[in] strategy Prefered strategy to use to split the workload
103          *
104          * @return the Hints object
105          */
set_strategy(StrategyHint strategy)106         Hints &set_strategy(StrategyHint strategy)
107         {
108             _strategy = strategy;
109             return *this;
110         }
111         /** Return the prefered strategy to use to split workload.
112          *
113          * @return The strategy
114          */
strategy()115         StrategyHint strategy() const
116         {
117             return _strategy;
118         }
119         /** Return the granule capping threshold to be used by dynamic scheduling.
120          *
121          * @return The capping threshold
122          */
threshold()123         int threshold() const
124         {
125             return _threshold;
126         }
127 
128     private:
129         unsigned int _split_dimension;
130         StrategyHint _strategy;
131         int          _threshold;
132     };
133     /** Signature for the workloads to execute */
134     using Workload = std::function<void(const ThreadInfo &)>;
135     /** Default constructor. */
136     IScheduler();
137 
138     /** Destructor. */
139     virtual ~IScheduler() = default;
140 
141     /** Sets the number of threads the scheduler will use to run the kernels.
142      *
143      * @param[in] num_threads If set to 0, then one thread per CPU core available on the system will be used, otherwise the number of threads specified.
144      */
145     virtual void set_num_threads(unsigned int num_threads) = 0;
146 
147     /** Sets the number of threads the scheduler will use to run the kernels but also using a binding function to pin the threads to given logical cores
148      *
149      * @param[in] num_threads If set to 0, then one thread per CPU core available on the system will be used, otherwise the number of threads specified.
150      * @param[in] func        Binding function to use.
151      */
152     virtual void set_num_threads_with_affinity(unsigned int num_threads, BindFunc func);
153 
154     /** Returns the number of threads that the SingleThreadScheduler has in his pool.
155      *
156      * @return Number of threads available in SingleThreadScheduler.
157      */
158     virtual unsigned int num_threads() const = 0;
159 
160     /** Runs the kernel in the same thread as the caller synchronously.
161      *
162      * @param[in] kernel Kernel to execute.
163      * @param[in] hints  Hints for the scheduler.
164      */
165     virtual void schedule(ICPPKernel *kernel, const Hints &hints) = 0;
166 
167     /** Runs the kernel in the same thread as the caller synchronously.
168      *
169      * @param[in] kernel  Kernel to execute.
170      * @param[in] hints   Hints for the scheduler.
171      * @param[in] tensors Vector containing the tensors to operate on.
172      */
173     virtual void schedule_op(ICPPKernel *kernel, const Hints &hints, ITensorPack &tensors) = 0;
174 
175     /** Execute all the passed workloads
176      *
177      * @note there is no guarantee regarding the order in which the workloads will be executed or whether or not they will be executed in parallel.
178      *
179      * @param[in] workloads Array of workloads to run
180      * @param[in] tag       String that can be used by profiling tools to identify the workloads run by the scheduler (Can be null).
181      */
182     virtual void run_tagged_workloads(std::vector<Workload> &workloads, const char *tag);
183 
184     /** Get CPU info.
185      *
186      * @return CPU info.
187      */
188     CPUInfo &cpu_info();
189     /** Get a hint for the best possible number of execution threads
190      *
191      * @warning In case we can't work out the best number of threads,
192      *          std::thread::hardware_concurrency() is returned else 1 in case of bare metal builds
193      *
194      * @return Best possible number of execution threads to use
195      */
196     unsigned int num_threads_hint() const;
197 
198 protected:
199     /** Execute all the passed workloads
200      *
201      * @note there is no guarantee regarding the order in which the workloads will be executed or whether or not they will be executed in parallel.
202      *
203      * @param[in] workloads Array of workloads to run
204      */
205     virtual void run_workloads(std::vector<Workload> &workloads) = 0;
206     CPUInfo _cpu_info;
207 
208     void schedule_common(ICPPKernel *kernel, const Hints &hints, ITensorPack &tensors);
209 
210 private:
211     unsigned int _num_threads_hint = {};
212 };
213 } // namespace arm_compute
214 #endif /* ARM_COMPUTE_ISCHEDULER_H */
215