• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 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_RUNTIME_MEM_GC_GC_WORKERS_THREAD_POOL_H
17 #define PANDA_RUNTIME_MEM_GC_GC_WORKERS_THREAD_POOL_H
18 
19 #include "runtime/include/thread.h"
20 #include "runtime/thread_pool.h"
21 #include "runtime/mem/gc/workers/gc_workers_task_pool.h"
22 
23 namespace ark::mem {
24 // Forward declaration for GCWorkersProcessor
25 class GCWorkersThreadPool;
26 
27 class GCWorkersProcessor : public ProcessorInterface<GCWorkersTask, GCWorkersThreadPool *> {
28 public:
GCWorkersProcessor(GCWorkersThreadPool * gcThreadsPools)29     explicit GCWorkersProcessor(GCWorkersThreadPool *gcThreadsPools) : gcThreadsPools_(gcThreadsPools) {}
30 
31     ~GCWorkersProcessor() override = default;
32     NO_COPY_SEMANTIC(GCWorkersProcessor);
33     NO_MOVE_SEMANTIC(GCWorkersProcessor);
34 
35     bool Process(GCWorkersTask &&task) override;
36     bool Init() override;
37     bool Destroy() override;
38 
39 private:
40     GCWorkersThreadPool *gcThreadsPools_;
41     void *workerData_ {nullptr};
42 };
43 
44 class GCWorkersQueueSimple : public TaskQueueInterface<GCWorkersTask> {
45 public:
GCWorkersQueueSimple(mem::InternalAllocatorPtr allocator,size_t queueLimit)46     explicit GCWorkersQueueSimple(mem::InternalAllocatorPtr allocator, size_t queueLimit)
47         : TaskQueueInterface<GCWorkersTask>(queueLimit), queue_(allocator->Adapter())
48     {
49     }
50 
51     ~GCWorkersQueueSimple() override = default;
52     NO_COPY_SEMANTIC(GCWorkersQueueSimple);
53     NO_MOVE_SEMANTIC(GCWorkersQueueSimple);
54 
GetTask()55     GCWorkersTask GetTask() override
56     {
57         if (queue_.empty()) {
58             LOG(DEBUG, GC) << "Empty " << queueName_ << ", return nothing";
59             return GCWorkersTask();
60         }
61         auto task = queue_.front();
62         queue_.pop_front();
63         LOG(DEBUG, GC) << "Extract a task from a " << queueName_ << ": " << GetTaskDescription(task);
64         return task;
65     }
66 
67     // NOLINTNEXTLINE(google-default-arguments)
68     void AddTask(GCWorkersTask &&ctx, [[maybe_unused]] size_t priority = 0) override
69     {
70         LOG(DEBUG, GC) << "Add task to a " << queueName_ << ": " << GetTaskDescription(ctx);
71         queue_.push_front(ctx);
72     }
73 
Finalize()74     void Finalize() override
75     {
76         // Nothing to deallocate
77         LOG(DEBUG, GC) << "Clear a " << queueName_;
78         queue_.clear();
79     }
80 
81 protected:
GetTaskDescription(const GCWorkersTask & ctx)82     PandaString GetTaskDescription(const GCWorkersTask &ctx)
83     {
84         PandaOStringStream stream;
85         stream << GCWorkersTaskTypesToString(ctx.GetType());
86         return stream.str();
87     }
88 
GetQueueSize()89     size_t GetQueueSize() override
90     {
91         return queue_.size();
92     }
93 
94 private:
95     PandaList<GCWorkersTask> queue_;
96     const char *queueName_ = "simple gc workers task queue";
97 };
98 
99 class GCWorkersCreationInterface : public WorkerCreationInterface {
100 public:
GCWorkersCreationInterface(PandaVM * vm)101     explicit GCWorkersCreationInterface(PandaVM *vm) : gcThread_(vm, Thread::ThreadType::THREAD_TYPE_GC)
102     {
103         ASSERT(vm != nullptr);
104     }
105 
106     ~GCWorkersCreationInterface() override = default;
107     NO_COPY_SEMANTIC(GCWorkersCreationInterface);
108     NO_MOVE_SEMANTIC(GCWorkersCreationInterface);
109 
AttachWorker(bool helperThread)110     void AttachWorker(bool helperThread) override
111     {
112         if (!helperThread) {
113             Thread::SetCurrent(&gcThread_);
114         }
115     }
DetachWorker(bool helperThread)116     void DetachWorker(bool helperThread) override
117     {
118         if (!helperThread) {
119             Thread::SetCurrent(nullptr);
120         }
121     }
122 
123 private:
124     Thread gcThread_;
125 };
126 
127 /// @brief GC workers task pool based on internal thread pool
128 class GCWorkersThreadPool final : public GCWorkersTaskPool {
129 public:
130     NO_COPY_SEMANTIC(GCWorkersThreadPool);
131     NO_MOVE_SEMANTIC(GCWorkersThreadPool);
132     explicit GCWorkersThreadPool(GC *gc, size_t threadsCount = 0);
133     ~GCWorkersThreadPool() final;
134 
135     void SetAffinityForGCWorkers();
136 
137     void UnsetAffinityForGCWorkers();
138 
139 private:
140     /**
141      * @brief Try to add new gc workers task to thread pool
142      * @param task gc workers task
143      * @return true if task successfully added to thread pool, false - otherwise
144      */
145     bool TryAddTask(GCWorkersTask &&task) final;
146 
147     /**
148      * @brief Try to get gc task from gc workers task queue and
149      * run it in the current thread to help gc workers from thread pool.
150      * Do nothing if couldn't get task
151      * @see GCWorkersQueueSimple
152      */
153     void RunInCurrentThread() final;
154 
155     /* GC thread pool specific variables */
156     ThreadPool<GCWorkersTask, GCWorkersProcessor, GCWorkersThreadPool *> *threadPool_;
157     GCWorkersQueueSimple *queue_;
158     GCWorkersCreationInterface *workerIface_;
159     mem::InternalAllocatorPtr internalAllocator_;
160     const size_t threadsCount_;
161 
162     friend class GCWorkersProcessor;
163 };
164 
165 }  // namespace ark::mem
166 
167 #endif  // PANDA_RUNTIME_MEM_GC_GC_WORKERS_THREAD_POOL_H
168