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_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 if (gc_->GetWorkersTaskPool()->AddTask(CreateTask(newStack))) {
88 LOG(DEBUG, GC) << "GCAdaptiveStack: Successfully add new task " << GCWorkersTaskTypesToString(taskType_)
89 << " for worker";
90 stackDst_ = allocator->template New<PandaDeque<Ref>>(allocator->Adapter());
91 } else {
92 // We will try to create a new task later
93 stackSizeLimit_ += stackSizeLimit_;
94 LOG(DEBUG, GC) << "GCAdaptiveStack: Failed to add new task " << GCWorkersTaskTypesToString(taskType_)
95 << " for worker";
96 [[maybe_unused]] auto srcStack = newStack->MoveStacksPointers();
97 ASSERT(srcStack == stackDst_);
98 allocator->Delete(newStack);
99 }
100 if (IsHighTaskCreationRate()) {
101 stackSizeLimit_ += stackSizeLimit_;
102 }
103 }
104 stackDst_->push_back(element);
105 }
106
107 template <typename Ref>
IsHighTaskCreationRate()108 bool GCAdaptiveStack<Ref>::IsHighTaskCreationRate()
109 {
110 if (createdTasks_ == 0) {
111 startTime_ = ark::os::time::GetClockTimeInThreadCpuTime();
112 }
113 createdTasks_++;
114 if (tasksForTimeCheck_ == createdTasks_) {
115 uint64_t curTime = ark::os::time::GetClockTimeInThreadCpuTime();
116 ASSERT(curTime >= startTime_);
117 uint64_t totalTimeConsumed = curTime - startTime_;
118 uint64_t oneTaskConsumed = totalTimeConsumed / createdTasks_;
119 LOG(DEBUG, GC) << "Created " << createdTasks_ << " tasks in " << Timing::PrettyTimeNs(totalTimeConsumed);
120 if (oneTaskConsumed < timeLimitForNewTaskCreation_) {
121 createdTasks_ = 0;
122 startTime_ = 0;
123 return true;
124 }
125 }
126 return false;
127 }
128
129 template <typename Ref>
PopFromStack()130 Ref GCAdaptiveStack<Ref>::PopFromStack()
131 {
132 if (stackSrc_->empty()) {
133 ASSERT(!stackDst_->empty());
134 auto temp = stackSrc_;
135 stackSrc_ = stackDst_;
136 stackDst_ = temp;
137 if (stackSizeLimit_ != 0) {
138 // We may increase the current limit, so return it to the default value
139 stackSizeLimit_ = initialStackSizeLimit_;
140 }
141 }
142 ASSERT(!stackSrc_->empty());
143 auto *element = stackSrc_->back();
144 stackSrc_->pop_back();
145 return element;
146 }
147
148 template <typename Ref>
149 template <typename Handler>
TraverseObjects(Handler & handler)150 void GCAdaptiveStack<Ref>::TraverseObjects(Handler &handler)
151 {
152 if (stackSrc_->empty()) {
153 std::swap(stackSrc_, stackDst_);
154 }
155 while (!Empty()) {
156 [[maybe_unused]] auto stackSrcSize = stackSrc_->size();
157 for (auto ref : *stackSrc_) {
158 handler.ProcessRef(ref);
159 // visitor mustn't pop from stack
160 ASSERT(stackSrcSize == stackSrc_->size());
161 }
162 stackSrc_->clear();
163 std::swap(stackSrc_, stackDst_);
164 }
165 }
166
167 template <typename Ref>
IsWorkersTaskSupported()168 bool GCAdaptiveStack<Ref>::IsWorkersTaskSupported() const
169 {
170 return taskType_ != GCWorkersTaskTypes::TASK_EMPTY;
171 }
172
173 template <typename Ref>
Clear()174 void GCAdaptiveStack<Ref>::Clear()
175 {
176 *stackSrc_ = PandaDeque<Ref>();
177 *stackDst_ = PandaDeque<Ref>();
178 }
179 } // namespace ark::mem
180 #endif // PANDA_RUNTIME_MEM_GC_GC_ADAPTIVE_STACK_INL_H
181