1 /*
2 * Copyright (c) 2023-2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef PANDA_COMPILER_BACKGROUND_TASK_RUNNER_H
17 #define PANDA_COMPILER_BACKGROUND_TASK_RUNNER_H
18
19 #include <memory>
20
21 #include "libpandabase/task_runner.h"
22 #include "libpandabase/taskmanager/task.h"
23 #include "libpandabase/taskmanager/task_queue.h"
24 #include "libpandabase/mem/arena_allocator.h"
25 #include "compiler/optimizer/pipeline.h"
26 #include "compiler/optimizer/ir/runtime_interface.h"
27 #include "runtime/include/compiler_interface.h"
28 #include "runtime/include/thread.h"
29
30 namespace ark {
31
32 class CompilerTask;
33 class Thread;
34 class Method;
35 class PandaVM;
36
37 } // namespace ark
38
39 namespace ark::compiler {
40
41 class Graph;
42
43 class BackgroundCompilerContext {
44 public:
45 using CompilerTask = std::unique_ptr<ark::CompilerTask, std::function<void(ark::CompilerTask *)>>;
46 using CompilerThread = std::unique_ptr<ark::Thread, std::function<void(ark::Thread *)>>;
47
SetCompilerTask(CompilerTask compilerTask)48 void SetCompilerTask(CompilerTask compilerTask)
49 {
50 compilerTask_ = std::move(compilerTask);
51 }
52
SetCompilerThread(CompilerThread compilerThread)53 void SetCompilerThread(CompilerThread compilerThread)
54 {
55 compilerThread_ = std::move(compilerThread);
56 }
57
SetAllocator(std::unique_ptr<ArenaAllocator> allocator)58 void SetAllocator(std::unique_ptr<ArenaAllocator> allocator)
59 {
60 allocator_ = std::move(allocator);
61 }
62
SetLocalAllocator(std::unique_ptr<ArenaAllocator> localAllocator)63 void SetLocalAllocator(std::unique_ptr<ArenaAllocator> localAllocator)
64 {
65 localAllocator_ = std::move(localAllocator);
66 }
67
SetMethodName(std::string methodName)68 void SetMethodName(std::string methodName)
69 {
70 methodName_ = std::move(methodName);
71 }
72
SetGraph(Graph * graph)73 void SetGraph(Graph *graph)
74 {
75 graph_ = graph;
76 }
77
SetPipeline(std::unique_ptr<Pipeline> pipeline)78 void SetPipeline(std::unique_ptr<Pipeline> pipeline)
79 {
80 pipeline_ = std::move(pipeline);
81 }
82
SetCompilationStatus(bool compilationStatus)83 void SetCompilationStatus(bool compilationStatus)
84 {
85 compilationStatus_ = compilationStatus;
86 }
87
GetMethod()88 Method *GetMethod() const
89 {
90 return compilerTask_->GetMethod();
91 }
92
IsOsr()93 bool IsOsr() const
94 {
95 return compilerTask_->IsOsr();
96 }
97
GetVM()98 PandaVM *GetVM() const
99 {
100 return compilerTask_->GetVM();
101 }
102
GetAllocator()103 ArenaAllocator *GetAllocator() const
104 {
105 return allocator_.get();
106 }
107
GetLocalAllocator()108 ArenaAllocator *GetLocalAllocator() const
109 {
110 return localAllocator_.get();
111 }
112
GetMethodName()113 const std::string &GetMethodName() const
114 {
115 return methodName_;
116 }
117
GetGraph()118 Graph *GetGraph() const
119 {
120 return graph_;
121 }
122
GetPipeline()123 Pipeline *GetPipeline() const
124 {
125 return pipeline_.get();
126 }
127
GetCompilationStatus()128 bool GetCompilationStatus() const
129 {
130 return compilationStatus_;
131 }
132
133 private:
134 CompilerTask compilerTask_;
135 CompilerThread compilerThread_;
136 std::unique_ptr<ArenaAllocator> allocator_;
137 std::unique_ptr<ArenaAllocator> localAllocator_;
138 std::string methodName_;
139 Graph *graph_ {nullptr};
140 std::unique_ptr<Pipeline> pipeline_;
141 // Used only in JIT Compilation
142 bool compilationStatus_ {false};
143 };
144
145 namespace copy_hooks {
146 class FailOnCopy {
147 public:
148 FailOnCopy() = default;
FailOnCopy(const FailOnCopy & other)149 FailOnCopy(const FailOnCopy &other)
150 {
151 UNUSED_VAR(other);
152 UNREACHABLE();
153 }
154 FailOnCopy &operator=(const FailOnCopy &other)
155 {
156 UNUSED_VAR(other);
157 UNREACHABLE();
158 }
159 DEFAULT_MOVE_SEMANTIC(FailOnCopy);
160 ~FailOnCopy() = default;
161 };
162
163 template <typename T>
164 class FakeCopyable : public FailOnCopy {
165 public:
FakeCopyable(T && t)166 explicit FakeCopyable(T &&t) : target_(std::forward<T>(t)) {}
FakeCopyable(const FakeCopyable & other)167 FakeCopyable(const FakeCopyable &other)
168 : FailOnCopy(other), // this will fail
169 target_(std::move(const_cast<T &>(other.target_))) // never reached
170 {
171 }
172 FakeCopyable &operator=(const FakeCopyable &other) = default;
173 DEFAULT_MOVE_SEMANTIC(FakeCopyable);
174 ~FakeCopyable() = default;
175
176 template <typename... Args>
operator()177 auto operator()(Args &&...args)
178 {
179 return target_(std::forward<Args>(args)...);
180 }
181
182 private:
183 T target_;
184 };
185
186 template <typename T>
MakeFakeCopyable(T && t)187 FakeCopyable<T> MakeFakeCopyable(T &&t)
188 {
189 return FakeCopyable<T>(std::forward<T>(t));
190 }
191
192 } // namespace copy_hooks
193
194 class BackgroundCompilerTaskRunner : public ark::TaskRunner<BackgroundCompilerTaskRunner, BackgroundCompilerContext> {
195 public:
BackgroundCompilerTaskRunner(taskmanager::TaskQueueInterface * compilerQueue,Thread * compilerThread,RuntimeInterface * runtimeIface)196 BackgroundCompilerTaskRunner(taskmanager::TaskQueueInterface *compilerQueue, Thread *compilerThread,
197 RuntimeInterface *runtimeIface)
198 : compilerQueue_(compilerQueue), compilerThread_(compilerThread), runtimeIface_(runtimeIface)
199 {
200 }
201
GetContext()202 BackgroundCompilerContext &GetContext() override
203 {
204 return taskCtx_;
205 }
206
207 /**
208 * @brief Adds a task to the TaskManager queue. This task will run in the background
209 * @param task_runner - Current TaskRunner containing context and callbacks
210 * @param task_func - task which will be executed with @param task_runner
211 */
StartTask(BackgroundCompilerTaskRunner taskRunner,TaskRunner::TaskFunc taskFunc)212 static void StartTask(BackgroundCompilerTaskRunner taskRunner, TaskRunner::TaskFunc taskFunc)
213 {
214 auto *compilerQueue = taskRunner.compilerQueue_;
215 auto callback = [nextTask = std::move(taskFunc), nextRunner = std::move(taskRunner)]() mutable {
216 auto *runtimeIface = nextRunner.runtimeIface_;
217 runtimeIface->SetCurrentThread(nextRunner.compilerThread_);
218 nextTask(std::move(nextRunner));
219 runtimeIface->SetCurrentThread(nullptr);
220 };
221 compilerQueue->AddBackgroundTask(copy_hooks::MakeFakeCopyable(std::move(callback)));
222 }
223
224 private:
225 taskmanager::TaskQueueInterface *compilerQueue_ {nullptr};
226 Thread *compilerThread_ {nullptr};
227 RuntimeInterface *runtimeIface_;
228 BackgroundCompilerContext taskCtx_;
229 };
230
231 } // namespace ark::compiler
232
233 #endif // PANDA_COMPILER_BACKGROUND_TASK_RUNNER_H
234