blob: b7534853518ec858f18d5012d0415e8c91c3b70c [file] [log] [blame]
Anthony Barbiere8a49832018-01-18 10:04:05 +00001/*
Sang-Hoon Park0094c022021-01-20 18:16:47 +00002 * Copyright (c) 2017-2021 Arm Limited.
Anthony Barbiere8a49832018-01-18 10:04:05 +00003 *
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#include "SchedulerTimer.h"
25
Georgios Pinitas12833d02019-07-25 13:31:10 +010026#include "Instruments.h"
Anthony Barbiere8a49832018-01-18 10:04:05 +000027#include "WallClockTimer.h"
28#include "arm_compute/core/CPP/ICPPKernel.h"
Freddie Liardet59fd7a72021-06-17 13:30:11 +010029#include "arm_compute/graph/DataLayerVisitor.h"
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +010030#include "arm_compute/graph/INode.h"
Sang-Hoon Park68dd25f2020-10-19 16:00:11 +010031#include "support/Cast.h"
Anthony Barbiere8a49832018-01-18 10:04:05 +000032
33namespace arm_compute
34{
35namespace test
36{
37namespace framework
38{
Anthony Barbier72f4ae52018-11-07 17:33:54 +000039template <bool output_timestamps>
40std::string SchedulerClock<output_timestamps>::id() const
Anthony Barbiere8a49832018-01-18 10:04:05 +000041{
Anthony Barbier72f4ae52018-11-07 17:33:54 +000042 if(output_timestamps)
43 {
44 return "SchedulerTimestamps";
45 }
46 else
47 {
48 return "SchedulerTimer";
49 }
Anthony Barbiere8a49832018-01-18 10:04:05 +000050}
51
Anthony Barbier72f4ae52018-11-07 17:33:54 +000052template <bool output_timestamps>
Anthony Barbiere8a49832018-01-18 10:04:05 +000053class Interceptor final : public IScheduler
54{
55public:
56 /** Default constructor. */
Freddie Liardet59fd7a72021-06-17 13:30:11 +010057 Interceptor(std::list<struct SchedulerClock<output_timestamps>::kernel_info> &kernels,
58 std::map<std::string, SchedulerTimer::LayerData> &layers, IScheduler &real_scheduler,
59 ScaleFactor scale_factor)
60 : _kernels(kernels), _layer_data_map(layers), _real_scheduler(real_scheduler), _timer(scale_factor), _prefix()
Anthony Barbiere8a49832018-01-18 10:04:05 +000061 {
62 }
63
64 void set_num_threads(unsigned int num_threads) override
65 {
66 _real_scheduler.set_num_threads(num_threads);
67 }
68
Georgios Pinitas06e890b2020-07-09 18:38:34 +010069 void set_num_threads_with_affinity(unsigned int num_threads, BindFunc func) override
70 {
71 _real_scheduler.set_num_threads_with_affinity(num_threads, func);
72 }
73
Anthony Barbiere8a49832018-01-18 10:04:05 +000074 unsigned int num_threads() const override
75 {
76 return _real_scheduler.num_threads();
77 }
78
Michalis Spyroubcfd09a2019-05-01 13:03:59 +010079 void set_prefix(const std::string &prefix)
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +010080 {
Michalis Spyroubcfd09a2019-05-01 13:03:59 +010081 _prefix = prefix;
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +010082 }
83
Anthony Barbier376c85f2018-05-25 14:17:21 +010084 void schedule(ICPPKernel *kernel, const Hints &hints) override
Anthony Barbiere8a49832018-01-18 10:04:05 +000085 {
86 _timer.start();
Georgios Pinitas77d42522019-11-05 13:35:47 +000087 _real_scheduler.schedule(kernel, hints);
Anthony Barbiere8a49832018-01-18 10:04:05 +000088 _timer.stop();
89
Anthony Barbier72f4ae52018-11-07 17:33:54 +000090 typename SchedulerClock<output_timestamps>::kernel_info info;
Anthony Barbiere8a49832018-01-18 10:04:05 +000091 info.name = kernel->name();
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +010092 info.prefix = _prefix;
Anthony Barbiere8a49832018-01-18 10:04:05 +000093 info.measurements = _timer.measurements();
94 _kernels.push_back(std::move(info));
95 }
96
Sang-Hoon Park0094c022021-01-20 18:16:47 +000097 void schedule_op(ICPPKernel *kernel, const Hints &hints, const Window &window, ITensorPack &tensors) override
Michalis Spyroubcd23522020-05-21 15:02:36 +010098 {
99 _timer.start();
Sang-Hoon Park0094c022021-01-20 18:16:47 +0000100 _real_scheduler.schedule_op(kernel, hints, window, tensors);
Michalis Spyroubcd23522020-05-21 15:02:36 +0100101 _timer.stop();
102
103 typename SchedulerClock<output_timestamps>::kernel_info info;
104 info.name = kernel->name();
105 info.prefix = _prefix;
106 info.measurements = _timer.measurements();
107 _kernels.push_back(std::move(info));
108 }
109
Anthony Barbier148b0752018-09-11 14:19:39 +0100110 void run_tagged_workloads(std::vector<Workload> &workloads, const char *tag) override
Anthony Barbier52ecb062018-05-25 13:32:10 +0100111 {
112 _timer.start();
Anthony Barbier148b0752018-09-11 14:19:39 +0100113 _real_scheduler.run_tagged_workloads(workloads, tag);
Anthony Barbier52ecb062018-05-25 13:32:10 +0100114 _timer.stop();
115
Anthony Barbier72f4ae52018-11-07 17:33:54 +0000116 typename SchedulerClock<output_timestamps>::kernel_info info;
Anthony Barbier148b0752018-09-11 14:19:39 +0100117 info.name = tag != nullptr ? tag : "Unknown";
Anthony Barbier52ecb062018-05-25 13:32:10 +0100118 info.prefix = _prefix;
119 info.measurements = _timer.measurements();
120 _kernels.push_back(std::move(info));
121 }
122
Anthony Barbier148b0752018-09-11 14:19:39 +0100123protected:
124 void run_workloads(std::vector<Workload> &workloads) override
125 {
126 ARM_COMPUTE_UNUSED(workloads);
127 ARM_COMPUTE_ERROR("Can't be reached");
128 }
129
Anthony Barbiere8a49832018-01-18 10:04:05 +0000130private:
Anthony Barbier72f4ae52018-11-07 17:33:54 +0000131 std::list<struct SchedulerClock<output_timestamps>::kernel_info> &_kernels;
Georgios Pinitasb6af4822021-09-14 12:33:34 +0100132 std::map<std::string, SchedulerTimer::LayerData> &_layer_data_map;
133 IScheduler &_real_scheduler;
134 WallClock<output_timestamps> _timer;
135 std::string _prefix;
Anthony Barbiere8a49832018-01-18 10:04:05 +0000136};
137
Anthony Barbier72f4ae52018-11-07 17:33:54 +0000138template <bool output_timestamps>
139SchedulerClock<output_timestamps>::SchedulerClock(ScaleFactor scale_factor)
Georgios Pinitasb6af4822021-09-14 12:33:34 +0100140 : _kernels(),
141 _layer_data_map(),
142 _real_scheduler(nullptr),
143 _real_scheduler_type(),
144#ifdef ARM_COMPUTE_GRAPH_ENABLED
145 _real_graph_function(nullptr),
146#endif /* ARM_COMPUTE_GRAPH_ENABLED */
147 _scale_factor(scale_factor),
148 _interceptor(nullptr),
149 _scheduler_users()
Anthony Barbiere8a49832018-01-18 10:04:05 +0000150{
Georgios Pinitas12833d02019-07-25 13:31:10 +0100151 if(instruments_info != nullptr)
152 {
153 _scheduler_users = instruments_info->_scheduler_users;
154 }
Anthony Barbiere8a49832018-01-18 10:04:05 +0000155}
156
Anthony Barbier72f4ae52018-11-07 17:33:54 +0000157template <bool output_timestamps>
158void SchedulerClock<output_timestamps>::test_start()
Anthony Barbiere8a49832018-01-18 10:04:05 +0000159{
Georgios Pinitasb6af4822021-09-14 12:33:34 +0100160#ifdef ARM_COMPUTE_GRAPH_ENABLED
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100161 // Start intercepting tasks:
162 ARM_COMPUTE_ERROR_ON(_real_graph_function != nullptr);
163 _real_graph_function = graph::TaskExecutor::get().execute_function;
164 auto task_interceptor = [this](graph::ExecutionTask & task)
165 {
Anthony Barbier72f4ae52018-11-07 17:33:54 +0000166 Interceptor<output_timestamps> *scheduler = nullptr;
167 if(dynamic_cast<Interceptor<output_timestamps> *>(this->_interceptor.get()) != nullptr)
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100168 {
Anthony Barbier72f4ae52018-11-07 17:33:54 +0000169 scheduler = arm_compute::utils::cast::polymorphic_downcast<Interceptor<output_timestamps> *>(_interceptor.get());
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100170 if(task.node != nullptr && !task.node->name().empty())
171 {
172 scheduler->set_prefix(task.node->name() + "/");
Freddie Liardet59fd7a72021-06-17 13:30:11 +0100173
174 if(_layer_data_map.find(task.node->name()) == _layer_data_map.end())
175 {
176 arm_compute::graph::DataLayerVisitor dlv = {};
177 task.node->accept(dlv);
178 _layer_data_map[task.node->name()] = dlv.layer_data();
179 }
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100180 }
181 else
182 {
183 scheduler->set_prefix("");
184 }
185 }
186
187 this->_real_graph_function(task);
188
189 if(scheduler != nullptr)
190 {
191 scheduler->set_prefix("");
192 }
193 };
Georgios Pinitasb6af4822021-09-14 12:33:34 +0100194#endif /* ARM_COMPUTE_GRAPH_ENABLED */
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100195
Anthony Barbiere8a49832018-01-18 10:04:05 +0000196 ARM_COMPUTE_ERROR_ON(_real_scheduler != nullptr);
197 _real_scheduler_type = Scheduler::get_type();
198 //Note: We can't currently replace a custom scheduler
199 if(_real_scheduler_type != Scheduler::Type::CUSTOM)
200 {
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100201 _real_scheduler = &Scheduler::get();
Freddie Liardet59fd7a72021-06-17 13:30:11 +0100202 _interceptor = std::make_shared<Interceptor<output_timestamps>>(_kernels, _layer_data_map, *_real_scheduler, _scale_factor);
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100203 Scheduler::set(std::static_pointer_cast<IScheduler>(_interceptor));
Georgios Pinitasb6af4822021-09-14 12:33:34 +0100204#ifdef ARM_COMPUTE_GRAPH_ENABLED
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100205 graph::TaskExecutor::get().execute_function = task_interceptor;
Georgios Pinitasb6af4822021-09-14 12:33:34 +0100206#endif /* ARM_COMPUTE_GRAPH_ENABLED */
Georgios Pinitas12833d02019-07-25 13:31:10 +0100207
208 // Create an interceptor for each scheduler
209 // TODO(COMPID-2638) : Allow multiple schedulers, now it assumes the same scheduler is used.
210 std::for_each(std::begin(_scheduler_users), std::end(_scheduler_users),
211 [&](ISchedulerUser * user)
212 {
213 if(user != nullptr && user->scheduler() != nullptr)
214 {
Freddie Liardet59fd7a72021-06-17 13:30:11 +0100215 user->intercept_scheduler(std::make_unique<Interceptor<output_timestamps>>(_kernels, _layer_data_map, *user->scheduler(), _scale_factor));
Georgios Pinitas12833d02019-07-25 13:31:10 +0100216 }
217 });
Anthony Barbiere8a49832018-01-18 10:04:05 +0000218 }
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100219}
220
Anthony Barbier72f4ae52018-11-07 17:33:54 +0000221template <bool output_timestamps>
222void SchedulerClock<output_timestamps>::start()
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100223{
Anthony Barbiere8a49832018-01-18 10:04:05 +0000224 _kernels.clear();
225}
226
Anthony Barbier72f4ae52018-11-07 17:33:54 +0000227template <bool output_timestamps>
228void SchedulerClock<output_timestamps>::test_stop()
Anthony Barbiere8a49832018-01-18 10:04:05 +0000229{
230 // Restore real scheduler
231 Scheduler::set(_real_scheduler_type);
Georgios Pinitasb6af4822021-09-14 12:33:34 +0100232 _real_scheduler = nullptr;
233 _interceptor = nullptr;
234#ifdef ARM_COMPUTE_GRAPH_ENABLED
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100235 graph::TaskExecutor::get().execute_function = _real_graph_function;
236 _real_graph_function = nullptr;
Georgios Pinitasb6af4822021-09-14 12:33:34 +0100237#endif /* ARM_COMPUTE_GRAPH_ENABLED */
Georgios Pinitas12833d02019-07-25 13:31:10 +0100238
239 // Restore schedulers
240 std::for_each(std::begin(_scheduler_users), std::end(_scheduler_users),
241 [&](ISchedulerUser * user)
242 {
243 if(user != nullptr)
244 {
245 user->restore_scheduler();
246 }
247 });
Anthony Barbiere8a49832018-01-18 10:04:05 +0000248}
249
Anthony Barbier72f4ae52018-11-07 17:33:54 +0000250template <bool output_timestamps>
251Instrument::MeasurementsMap SchedulerClock<output_timestamps>::measurements() const
Anthony Barbiere8a49832018-01-18 10:04:05 +0000252{
253 MeasurementsMap measurements;
254 unsigned int kernel_number = 0;
255 for(auto kernel : _kernels)
256 {
Anthony Barbier72f4ae52018-11-07 17:33:54 +0000257 std::string name = kernel.prefix + kernel.name + " #" + support::cpp11::to_string(kernel_number++);
258 if(output_timestamps)
259 {
260 ARM_COMPUTE_ERROR_ON(kernel.measurements.size() != 2);
Michalis Spyroubcfd09a2019-05-01 13:03:59 +0100261 for(auto const &m : kernel.measurements)
Anthony Barbier72f4ae52018-11-07 17:33:54 +0000262 {
263 if(m.first.find("[start]") != std::string::npos)
264 {
265 measurements.emplace("[start]" + name, m.second);
266 }
267 else if(m.first.find("[end]") != std::string::npos)
268 {
269 measurements.emplace("[end]" + name, m.second);
270 }
271 else
272 {
273 ARM_COMPUTE_ERROR("Measurement not handled");
274 }
275 }
276 }
277 else
278 {
279 measurements.emplace(name, kernel.measurements.begin()->second);
280 }
Anthony Barbiere8a49832018-01-18 10:04:05 +0000281 }
282
283 return measurements;
284}
Anthony Barbiercc225be2018-11-09 15:35:20 +0000285
Freddie Liardet59fd7a72021-06-17 13:30:11 +0100286template <bool output_timestamps>
Georgios Pinitasb6af4822021-09-14 12:33:34 +0100287std::string SchedulerClock<output_timestamps>::instrument_header() const
Freddie Liardet59fd7a72021-06-17 13:30:11 +0100288{
Georgios Pinitasb6af4822021-09-14 12:33:34 +0100289 std::string output{ "" };
Freddie Liardet59fd7a72021-06-17 13:30:11 +0100290 output += R"("layer_data" : {)";
291 for(auto i_it = _layer_data_map.cbegin(), i_end = _layer_data_map.cend(); i_it != i_end; ++i_it)
292 {
293 output += "\"" + i_it->first + "\" : {";
294 if(i_it->second.size() != 0)
295 {
296 // Print for each entry in layer
297 for(auto entry_it = i_it->second.cbegin(), entry_end = i_it->second.cend(); entry_it != entry_end; ++entry_it)
298 {
299 output += "\"" + entry_it->first + "\" : \"" + entry_it->second + "\"";
300 if(std::next(entry_it) != entry_end)
301 {
302 output += ",";
303 }
304 }
305 }
306 output += "}";
307 if(std::next(i_it) != i_end)
308 {
309 output += ",";
310 }
311 }
312 output += "}";
313 return output;
314}
315
Anthony Barbiere8a49832018-01-18 10:04:05 +0000316} // namespace framework
317} // namespace test
318} // namespace arm_compute
Anthony Barbiercc225be2018-11-09 15:35:20 +0000319
320template class arm_compute::test::framework::SchedulerClock<true>;
321template class arm_compute::test::framework::SchedulerClock<false>;