blob: ae204c85609ce34ee76155fd10251b308fe65546 [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
SiCong Lidba672c2023-04-06 16:30:18 +01002 * Copyright (c) 2017-2021, 2023 Arm Limited.
Anthony Barbier6ff3b192017-09-04 18:44:23 +01003 *
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 */
Michalis Spyrouf4643372019-11-29 16:17:13 +000024#ifndef ARM_COMPUTE_ISCHEDULER_H
25#define ARM_COMPUTE_ISCHEDULER_H
Anthony Barbier6ff3b192017-09-04 18:44:23 +010026
Moritz Pflanzerc186b572017-09-07 09:48:04 +010027#include "arm_compute/core/CPP/CPPTypes.h"
Michalis Spyroubcd23522020-05-21 15:02:36 +010028#include "arm_compute/core/experimental/Types.h"
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010029#include "arm_compute/core/Types.h"
Moritz Pflanzerc186b572017-09-07 09:48:04 +010030
Anthony Barbier52ecb062018-05-25 13:32:10 +010031#include <functional>
Joseph Dobson6f8b17d2020-02-11 19:32:11 +000032#include <limits>
Anthony Barbier52ecb062018-05-25 13:32:10 +010033
Anthony Barbier6ff3b192017-09-04 18:44:23 +010034namespace arm_compute
35{
36class ICPPKernel;
Michalis Spyroubcd23522020-05-21 15:02:36 +010037class ITensor;
Sang-Hoon Park0094c022021-01-20 18:16:47 +000038class Window;
Anthony Barbier6ff3b192017-09-04 18:44:23 +010039
40/** Scheduler interface to run kernels */
41class IScheduler
42{
43public:
Anthony Barbier376c85f2018-05-25 14:17:21 +010044 /** Strategies available to split a workload */
45 enum class StrategyHint
46 {
47 STATIC, /**< Split the workload evenly among the threads */
48 DYNAMIC, /**< Split the workload dynamically using a bucket system */
49 };
Joseph Dobson6f8b17d2020-02-11 19:32:11 +000050
Georgios Pinitas06e890b2020-07-09 18:38:34 +010051 /** Function to be used and map a given thread id to a logical core id
52 *
53 * Mapping function expects the thread index and total number of cores as input,
54 * and returns the logical core index to bind against
55 */
56 using BindFunc = std::function<int(int, int)>;
57
Joseph Dobson6f8b17d2020-02-11 19:32:11 +000058 /** When arm_compute::ISchedular::Hints::_split_dimension is initialized with this value
59 * then the schedular is free to break down the problem space over as many dimensions
60 * as it wishes
61 */
62 static constexpr unsigned int split_dimensions_all = std::numeric_limits<unsigned>::max();
63
Anthony Barbier376c85f2018-05-25 14:17:21 +010064 /** Scheduler hints
65 *
66 * Collection of preferences set by the function regarding how to split a given workload
67 */
68 class Hints
69 {
70 public:
71 /** Constructor
72 *
73 * @param[in] split_dimension Dimension along which to split the kernel's execution window.
74 * @param[in] strategy (Optional) Split strategy.
Georgios Pinitas77d42522019-11-05 13:35:47 +000075 * @param[in] threshold (Optional) Dynamic scheduling capping threshold.
Anthony Barbier376c85f2018-05-25 14:17:21 +010076 */
Georgios Pinitas77d42522019-11-05 13:35:47 +000077 Hints(unsigned int split_dimension, StrategyHint strategy = StrategyHint::STATIC, int threshold = 0)
78 : _split_dimension(split_dimension), _strategy(strategy), _threshold(threshold)
Anthony Barbier376c85f2018-05-25 14:17:21 +010079 {
80 }
81 /** Set the split_dimension hint
82 *
83 * @param[in] split_dimension Dimension along which to split the kernel's execution window.
84 *
85 * @return the Hints object
86 */
87 Hints &set_split_dimension(unsigned int split_dimension)
88 {
89 _split_dimension = split_dimension;
90 return *this;
91 }
92 /** Return the prefered split dimension
93 *
94 * @return The split dimension
95 */
96 unsigned int split_dimension() const
97 {
98 return _split_dimension;
99 }
100
101 /** Set the strategy hint
102 *
103 * @param[in] strategy Prefered strategy to use to split the workload
104 *
105 * @return the Hints object
106 */
107 Hints &set_strategy(StrategyHint strategy)
108 {
109 _strategy = strategy;
110 return *this;
111 }
112 /** Return the prefered strategy to use to split workload.
113 *
114 * @return The strategy
115 */
116 StrategyHint strategy() const
117 {
118 return _strategy;
119 }
Georgios Pinitas77d42522019-11-05 13:35:47 +0000120 /** Return the granule capping threshold to be used by dynamic scheduling.
121 *
122 * @return The capping threshold
123 */
124 int threshold() const
125 {
126 return _threshold;
127 }
Anthony Barbier376c85f2018-05-25 14:17:21 +0100128
129 private:
Georgios Pinitas08302c12021-06-09 10:08:27 +0100130 unsigned int _split_dimension{};
131 StrategyHint _strategy{};
132 int _threshold{};
Anthony Barbier376c85f2018-05-25 14:17:21 +0100133 };
Anthony Barbier52ecb062018-05-25 13:32:10 +0100134 /** Signature for the workloads to execute */
135 using Workload = std::function<void(const ThreadInfo &)>;
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100136 /** Default constructor. */
Moritz Pflanzerbeabe3b2017-08-31 14:56:32 +0100137 IScheduler();
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100138
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100139 /** Destructor. */
140 virtual ~IScheduler() = default;
Moritz Pflanzerbeabe3b2017-08-31 14:56:32 +0100141
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100142 /** Sets the number of threads the scheduler will use to run the kernels.
143 *
144 * @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.
145 */
146 virtual void set_num_threads(unsigned int num_threads) = 0;
Moritz Pflanzerbeabe3b2017-08-31 14:56:32 +0100147
Georgios Pinitas06e890b2020-07-09 18:38:34 +0100148 /** 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
149 *
150 * @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.
151 * @param[in] func Binding function to use.
152 */
153 virtual void set_num_threads_with_affinity(unsigned int num_threads, BindFunc func);
154
ramelg01b2eba7f2021-12-23 08:32:08 +0000155 /** Returns the number of threads that the SingleThreadScheduler has in its pool.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100156 *
157 * @return Number of threads available in SingleThreadScheduler.
158 */
159 virtual unsigned int num_threads() const = 0;
Moritz Pflanzerbeabe3b2017-08-31 14:56:32 +0100160
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100161 /** Runs the kernel in the same thread as the caller synchronously.
162 *
Anthony Barbier376c85f2018-05-25 14:17:21 +0100163 * @param[in] kernel Kernel to execute.
164 * @param[in] hints Hints for the scheduler.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100165 */
Anthony Barbier376c85f2018-05-25 14:17:21 +0100166 virtual void schedule(ICPPKernel *kernel, const Hints &hints) = 0;
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100167
Michalis Spyroubcd23522020-05-21 15:02:36 +0100168 /** Runs the kernel in the same thread as the caller synchronously.
169 *
170 * @param[in] kernel Kernel to execute.
171 * @param[in] hints Hints for the scheduler.
Sang-Hoon Park0094c022021-01-20 18:16:47 +0000172 * @param[in] window Window to use for kernel execution.
Georgios Pinitas0499dff2020-07-31 22:21:38 +0100173 * @param[in] tensors Vector containing the tensors to operate on.
Michalis Spyroubcd23522020-05-21 15:02:36 +0100174 */
Sang-Hoon Park0094c022021-01-20 18:16:47 +0000175 virtual void schedule_op(ICPPKernel *kernel, const Hints &hints, const Window &window, ITensorPack &tensors) = 0;
Michalis Spyroubcd23522020-05-21 15:02:36 +0100176
Anthony Barbier52ecb062018-05-25 13:32:10 +0100177 /** Execute all the passed workloads
178 *
SiCong Lidba672c2023-04-06 16:30:18 +0100179 * @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.
Anthony Barbier52ecb062018-05-25 13:32:10 +0100180 *
SiCong Lidba672c2023-04-06 16:30:18 +0100181 * @param[in] workloads List of workloads to run
Anthony Barbier148b0752018-09-11 14:19:39 +0100182 * @param[in] tag String that can be used by profiling tools to identify the workloads run by the scheduler (Can be null).
Anthony Barbier52ecb062018-05-25 13:32:10 +0100183 */
Anthony Barbier148b0752018-09-11 14:19:39 +0100184 virtual void run_tagged_workloads(std::vector<Workload> &workloads, const char *tag);
Anthony Barbier52ecb062018-05-25 13:32:10 +0100185
Moritz Pflanzerbeabe3b2017-08-31 14:56:32 +0100186 /** Get CPU info.
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100187 *
Moritz Pflanzerbeabe3b2017-08-31 14:56:32 +0100188 * @return CPU info.
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100189 */
Pablo Tello7fad9b12018-03-14 17:55:27 +0000190 CPUInfo &cpu_info();
Georgios Pinitas53d12272018-02-01 20:23:25 +0000191 /** Get a hint for the best possible number of execution threads
192 *
193 * @warning In case we can't work out the best number of threads,
194 * std::thread::hardware_concurrency() is returned else 1 in case of bare metal builds
195 *
196 * @return Best possible number of execution threads to use
197 */
198 unsigned int num_threads_hint() const;
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100199
200protected:
Anthony Barbier148b0752018-09-11 14:19:39 +0100201 /** Execute all the passed workloads
202 *
203 * @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.
204 *
205 * @param[in] workloads Array of workloads to run
206 */
207 virtual void run_workloads(std::vector<Workload> &workloads) = 0;
Georgios Pinitas53d12272018-02-01 20:23:25 +0000208
Sang-Hoon Park0094c022021-01-20 18:16:47 +0000209 /** Common scheduler logic to execute the given kernel
210 *
211 * @param[in] kernel Kernel to execute.
212 * @param[in] hints Hints for the scheduler.
213 * @param[in] window Window to use for kernel execution.
214 * @param[in] tensors Vector containing the tensors to operate on.
215 */
216 void schedule_common(ICPPKernel *kernel, const Hints &hints, const Window &window, ITensorPack &tensors);
morgolock51112642020-08-20 14:51:39 +0100217
Dana Zlotnikd7154db2021-11-10 11:50:58 +0200218 /** Adjust the number of windows to the optimize performance
219 * (used for small workloads where smaller number of threads might improve the performance)
220 *
221 * @param[in] window Window to use for kernel execution
222 * @param[in] split_dimension Axis of dimension to split
223 * @param[in] init_num_windows Initial number of sub-windows to split
224 * @param[in] kernel Kernel to execute
225 * @param[in] cpu_info The CPU platform used to create the context.
226 *
227 * @return Adjusted number of windows
228 */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100229 std::size_t adjust_num_of_windows(const Window &window,
230 std::size_t split_dimension,
231 std::size_t init_num_windows,
232 const ICPPKernel &kernel,
233 const CPUInfo &cpu_info);
Dana Zlotnikd7154db2021-11-10 11:50:58 +0200234
Georgios Pinitas53d12272018-02-01 20:23:25 +0000235private:
236 unsigned int _num_threads_hint = {};
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100237};
Georgios Pinitas77d42522019-11-05 13:35:47 +0000238} // namespace arm_compute
Michalis Spyrouf4643372019-11-29 16:17:13 +0000239#endif /* ARM_COMPUTE_ISCHEDULER_H */