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