1 /**
2 * Copyright (c) 2021-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_RUNTIME_MEM_GC_GC_ADAPTIVE_STACK_INL_H
17 #define PANDA_RUNTIME_MEM_GC_GC_ADAPTIVE_STACK_INL_H
18
19 #include "runtime/mem/gc/gc_adaptive_stack.h"
20 #include "runtime/mem/gc/gc.h"
21 #include "runtime/mem/gc/workers/gc_workers_task_pool.h"
22
23 namespace ark::mem {
24
25 template <typename Ref>
GCAdaptiveStack(GC * gc,size_t stackSizeLimit,size_t newTaskStackSizeLimit,GCWorkersTaskTypes task,uint64_t timeLimitForNewTaskCreation,PandaDeque<Ref> * stackSrc)26 GCAdaptiveStack<Ref>::GCAdaptiveStack(GC *gc, size_t stackSizeLimit, size_t newTaskStackSizeLimit,
27 GCWorkersTaskTypes task, uint64_t timeLimitForNewTaskCreation,
28 PandaDeque<Ref> *stackSrc)
29 : stackSizeLimit_(stackSizeLimit),
30 newTaskStackSizeLimit_(newTaskStackSizeLimit),
31 timeLimitForNewTaskCreation_(timeLimitForNewTaskCreation),
32 taskType_(task),
33 gc_(gc)
34 {
35 initialStackSizeLimit_ = stackSizeLimit_;
36 auto allocator = gc_->GetInternalAllocator();
37 ASSERT((stackSizeLimit == 0) || (gc->GetWorkersTaskPool() != nullptr));
38 if (stackSrc != nullptr) {
39 stackSrc_ = stackSrc;
40 } else {
41 stackSrc_ = allocator->template New<PandaDeque<Ref>>(allocator->Adapter());
42 }
43 stackDst_ = allocator->template New<PandaDeque<Ref>>(allocator->Adapter());
44 }
45
46 template <typename Ref>
~GCAdaptiveStack()47 GCAdaptiveStack<Ref>::~GCAdaptiveStack()
48 {
49 gc_->GetInternalAllocator()->Delete(stackSrc_);
50 gc_->GetInternalAllocator()->Delete(stackDst_);
51 }
52
53 template <typename Ref>
Empty()54 bool GCAdaptiveStack<Ref>::Empty() const
55 {
56 return stackSrc_->empty() && stackDst_->empty();
57 }
58
59 template <typename Ref>
Size()60 size_t GCAdaptiveStack<Ref>::Size() const
61 {
62 return stackSrc_->size() + stackDst_->size();
63 }
64
65 template <typename Ref>
MoveStacksPointers()66 PandaDeque<Ref> *GCAdaptiveStack<Ref>::MoveStacksPointers()
67 {
68 ASSERT(stackSrc_ != nullptr);
69 auto *returnValue = stackSrc_;
70 stackSrc_ = nullptr;
71 return returnValue;
72 }
73
74 template <typename Ref>
PushToStack(Ref element)75 void GCAdaptiveStack<Ref>::PushToStack(Ref element)
76 {
77 ASSERT_PRINT(IsAddressInObjectsHeap(element), element);
78 if ((stackSizeLimit_ > 0) && ((stackDst_->size() + 1) == stackSizeLimit_)) {
79 // Try to create a new task only once
80 // Create a new stack and send a new task to GC
81 LOG(DEBUG, GC) << "GCAdaptiveStack: Try to add new task " << GCWorkersTaskTypesToString(taskType_)
82 << " for worker";
83 ASSERT(gc_->GetWorkersTaskPool() != nullptr);
84 ASSERT(taskType_ != GCWorkersTaskTypes::TASK_EMPTY);
85 auto allocator = gc_->GetInternalAllocator();
86 auto *newStack = CreateStack();
87 ASSERT(newStack != nullptr);
88 if (gc_->GetWorkersTaskPool()->AddTask(CreateTask(newStack))) {
89 LOG(DEBUG, GC) << "GCAdaptiveStack: Successfully add new task " << GCWorkersTaskTypesToString(taskType_)
90 << " for worker";
91 stackDst_ = allocator->template New<PandaDeque<Ref>>(allocator->Adapter());
92 } else {
93 // We will try to create a new task later
94 stackSizeLimit_ += stackSizeLimit_;
95 LOG(DEBUG, GC) << "GCAdaptiveStack: Failed to add new task " << GCWorkersTaskTypesToString(taskType_)
96 << " for worker";
97 [[maybe_unused]] auto srcStack = newStack->MoveStacksPointers();
98 ASSERT(srcStack == stackDst_);
99 allocator->Delete(newStack);
100 }
101 if (IsHighTaskCreationRate()) {
102 stackSizeLimit_ += stackSizeLimit_;
103 }
104 }
105 stackDst_->push_back(element);
106 }
107
108 template <typename Ref>
IsHighTaskCreationRate()109 bool GCAdaptiveStack<Ref>::IsHighTaskCreationRate()
110 {
111 if (createdTasks_ == 0) {
112 startTime_ = ark::os::time::GetClockTimeInThreadCpuTime();
113 }
114 createdTasks_++;
115 if (tasksForTimeCheck_ == createdTasks_) {
116 uint64_t curTime = ark::os::time::GetClockTimeInThreadCpuTime();
117 ASSERT(curTime >= startTime_);
118 uint64_t totalTimeConsumed = curTime - startTime_;
119 uint64_t oneTaskConsumed = totalTimeConsumed / createdTasks_;
120 LOG(DEBUG, GC) << "Created " << createdTasks_ << " tasks in " << Timing::PrettyTimeNs(totalTimeConsumed);
121 if (oneTaskConsumed < timeLimitForNewTaskCreation_) {
122 createdTasks_ = 0;
123 startTime_ = 0;
124 return true;
125 }
126 }
127 return false;
128 }
129
130 template <typename Ref>
PopFromStack()131 Ref GCAdaptiveStack<Ref>::PopFromStack()
132 {
133 if (stackSrc_->empty()) {
134 ASSERT(!stackDst_->empty());
135 auto temp = stackSrc_;
136 stackSrc_ = stackDst_;
137 stackDst_ = temp;
138 if (stackSizeLimit_ != 0) {
139 // We may increase the current limit, so return it to the default value
140 stackSizeLimit_ = initialStackSizeLimit_;
141 }
142 }
143 ASSERT(!stackSrc_->empty());
144 auto *element = stackSrc_->back();
145 stackSrc_->pop_back();
146 return element;
147 }
148
149 template <typename Ref>
150 template <typename Handler>
TraverseObjects(Handler & handler)151 void GCAdaptiveStack<Ref>::TraverseObjects(Handler &handler)
152 {
153 if (stackSrc_->empty()) {
154 std::swap(stackSrc_, stackDst_);
155 }
156 while (!Empty()) {
157 [[maybe_unused]] auto stackSrcSize = stackSrc_->size();
158 for (auto ref : *stackSrc_) {
159 handler.ProcessRef(ref);
160 // visitor mustn't pop from stack
161 ASSERT(stackSrcSize == stackSrc_->size());
162 }
163 stackSrc_->clear();
164 std::swap(stackSrc_, stackDst_);
165 }
166 }
167
168 template <typename Ref>
IsWorkersTaskSupported()169 bool GCAdaptiveStack<Ref>::IsWorkersTaskSupported() const
170 {
171 return taskType_ != GCWorkersTaskTypes::TASK_EMPTY;
172 }
173
174 template <typename Ref>
Clear()175 void GCAdaptiveStack<Ref>::Clear()
176 {
177 *stackSrc_ = PandaDeque<Ref>();
178 *stackDst_ = PandaDeque<Ref>();
179 }
180 } // namespace ark::mem
181 #endif // PANDA_RUNTIME_MEM_GC_GC_ADAPTIVE_STACK_INL_H
182