• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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