• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 #include "runtime/mem/gc/generational-gc-base.h"
17 #include "runtime/include/runtime.h"
18 #include "runtime/include/runtime_notification.h"
19 #include "runtime/include/panda_vm.h"
20 
21 namespace panda::mem {
22 
23 template <class LanguageConfig>
ShouldRunTenuredGC(const GCTask & task)24 bool GenerationalGC<LanguageConfig>::ShouldRunTenuredGC(const GCTask &task)
25 {
26     return this->IsOnPygoteFork() || task.reason_ == GCTaskCause::OOM_CAUSE ||
27            task.reason_ == GCTaskCause::EXPLICIT_CAUSE || task.reason_ == GCTaskCause::HEAP_USAGE_THRESHOLD_CAUSE ||
28            task.reason_ == GCTaskCause::STARTUP_COMPLETE_CAUSE;
29 }
30 
31 template <class LanguageConfig>
WaitForGC(GCTask task)32 void GenerationalGC<LanguageConfig>::WaitForGC(GCTask task)
33 {
34     // TODO(maksenov): Notify only about pauses (#4681)
35     Runtime::GetCurrent()->GetNotificationManager()->GarbageCollectorStartEvent();
36     // Atomic with acquire order reason: data race with gc_counter_ with dependecies on reads after the load which
37     // should become visible
38     auto old_counter = this->gc_counter_.load(std::memory_order_acquire);
39     Timing suspend_threads_timing;
40     {
41         ScopedTiming t("SuspendThreads", suspend_threads_timing);
42         this->GetPandaVm()->GetRendezvous()->SafepointBegin();
43     }
44 
45     // Atomic with acquire order reason: data race with gc_counter_ with dependecies on reads after the load which
46     // should become visible
47     auto new_counter = this->gc_counter_.load(std::memory_order_acquire);
48     // Atomic with acquire order reason: data race with last_cause_ with dependecies on reads after the load which
49     // should become visible
50     if (new_counter > old_counter && this->last_cause_.load(std::memory_order_acquire) >= task.reason_) {
51         this->GetPandaVm()->GetRendezvous()->SafepointEnd();
52         return;
53     }
54 
55     // Create a copy of the constant GCTask to be able to change its value
56     this->RunPhases(task);
57 
58     if (UNLIKELY(this->IsLogDetailedGcInfoEnabled())) {
59         LOG(INFO, GC) << mem_stats_.Dump();
60         for (auto &footprint : this->footprint_list_) {
61             LOG(INFO, GC) << footprint.first << " : " << footprint.second;
62         }
63         LOG(INFO, GC) << suspend_threads_timing.Dump();
64         LOG(INFO, GC) << this->GetTiming()->Dump();
65     }
66     this->GetTiming()->Reset();  // Clear records.
67 
68     this->GetPandaVm()->GetRendezvous()->SafepointEnd();
69     Runtime::GetCurrent()->GetNotificationManager()->GarbageCollectorFinishEvent();
70     this->GetPandaVm()->HandleGCFinished();
71     this->GetPandaVm()->HandleEnqueueReferences();
72 }
73 
74 template <class LanguageConfig>
Dump()75 PandaString GenerationalGC<LanguageConfig>::MemStats::Dump()
76 {
77     PandaStringStream statistic;
78     statistic << "Young freed " << young_free_object_count_ << " objects ("
79               << helpers::MemoryConverter(young_free_object_size_) << ") Young moved " << young_move_object_count_
80               << " objects, " << young_move_object_size_ << " bytes ("
81               << helpers::MemoryConverter(young_move_object_size_) << ")";
82     if (tenured_free_object_size_ > 0U) {
83         statistic << " Tenured freed " << tenured_free_object_size_ << "("
84                   << helpers::MemoryConverter(tenured_free_object_size_) << ")";
85     }
86     return statistic.str();
87 }
88 
89 template <class LanguageConfig>
UpdateMemStats(size_t bytes_in_heap_before,bool update_tenured_stats,bool record_allocation_for_moved_objects)90 void GenerationalGC<LanguageConfig>::UpdateMemStats(size_t bytes_in_heap_before, bool update_tenured_stats,
91                                                     bool record_allocation_for_moved_objects)
92 {
93     size_t young_move_size = this->mem_stats_.GetSizeMovedYoung();
94     size_t young_move_count = this->mem_stats_.GetCountMovedYoung();
95     size_t young_delete_size = this->mem_stats_.GetSizeFreedYoung();
96     size_t young_delete_count = this->mem_stats_.GetCountFreedYoung();
97     size_t tenured_move_size = update_tenured_stats ? this->mem_stats_.GetSizeMovedTenured() : 0;
98     size_t tenured_move_count = update_tenured_stats ? this->mem_stats_.GetCountMovedTenured() : 0;
99     size_t tenured_delete_size = update_tenured_stats ? this->mem_stats_.GetSizeFreedTenured() : 0;
100     size_t tenured_delete_count = update_tenured_stats ? this->mem_stats_.GetCountFreedTenured() : 0;
101 
102     auto *vm_mem_stats = this->GetPandaVm()->GetMemStats();
103     GCInstanceStats *gc_stats = this->GetStats();
104 
105     if (record_allocation_for_moved_objects) {
106         vm_mem_stats->RecordAllocateObjects(young_move_count + tenured_move_count, young_move_size + tenured_move_size,
107                                             SpaceType::SPACE_TYPE_OBJECT);
108     }
109     if (young_move_size > 0) {
110         gc_stats->AddMemoryValue(young_move_size, MemoryTypeStats::MOVED_BYTES);
111         gc_stats->AddObjectsValue(young_move_count, ObjectTypeStats::MOVED_OBJECTS);
112         vm_mem_stats->RecordYoungMovedObjects(young_move_count, young_move_size, SpaceType::SPACE_TYPE_OBJECT);
113     }
114     if (young_delete_size > 0) {
115         gc_stats->AddMemoryValue(young_delete_size, MemoryTypeStats::YOUNG_FREED_BYTES);
116         gc_stats->AddObjectsValue(young_delete_count, ObjectTypeStats::YOUNG_FREED_OBJECTS);
117     }
118 
119     if (bytes_in_heap_before > 0) {
120         gc_stats->AddCopiedRatioValue(static_cast<double>(young_move_size + tenured_move_size) / bytes_in_heap_before);
121     }
122 
123     if (tenured_move_size > 0) {
124         gc_stats->AddMemoryValue(tenured_move_size, MemoryTypeStats::MOVED_BYTES);
125         gc_stats->AddObjectsValue(tenured_move_count, ObjectTypeStats::MOVED_OBJECTS);
126         vm_mem_stats->RecordTenuredMovedObjects(tenured_move_count, tenured_move_size, SpaceType::SPACE_TYPE_OBJECT);
127     }
128     if (tenured_delete_size > 0) {
129         gc_stats->AddMemoryValue(tenured_delete_size, MemoryTypeStats::ALL_FREED_BYTES);
130         gc_stats->AddObjectsValue(tenured_delete_count, ObjectTypeStats::ALL_FREED_OBJECTS);
131     }
132     vm_mem_stats->RecordFreeObjects(young_delete_count + tenured_delete_count, young_delete_size + tenured_delete_size,
133                                     SpaceType::SPACE_TYPE_OBJECT);
134 }
135 
136 template <class LanguageConfig>
SweepStringTableYoung(const std::function<bool (ObjectHeader *)> & young_checker)137 void GenerationalGC<LanguageConfig>::SweepStringTableYoung(const std::function<bool(ObjectHeader *)> &young_checker)
138 {
139     GCScope<TRACE_TIMING_PHASE> scoped_trace(__FUNCTION__, this, GCPhase::GC_PHASE_SWEEP_STRING_TABLE_YOUNG);
140 
141     this->GetPandaVm()->SweepStringTable(static_cast<GCObjectVisitor>([&young_checker](ObjectHeader *object_header) {
142         if (young_checker(object_header)) {
143             return ObjectStatus::DEAD_OBJECT;
144         }
145         return ObjectStatus::ALIVE_OBJECT;
146     }));
147 }
148 
149 template <class LanguageConfig>
CreateCardTable(InternalAllocatorPtr internal_allocator_ptr,uintptr_t min_address,size_t size)150 void GenerationalGC<LanguageConfig>::CreateCardTable(InternalAllocatorPtr internal_allocator_ptr, uintptr_t min_address,
151                                                      size_t size)
152 {
153     card_table_ = MakePandaUnique<CardTable>(internal_allocator_ptr, min_address, size);
154     card_table_->Initialize();
155 }
156 
157 TEMPLATE_CLASS_LANGUAGE_CONFIG(GenerationalGC);
158 }  // namespace panda::mem
159