• 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_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