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 #ifndef PANDA_RUNTIME_MEM_GC_G1_UPDATE_REMSET_THREAD_H 17 #define PANDA_RUNTIME_MEM_GC_G1_UPDATE_REMSET_THREAD_H 18 19 #include "libpandabase/macros.h" 20 #include "libpandabase/os/mutex.h" 21 #include "runtime/include/panda_vm.h" 22 #include "runtime/include/mem/panda_containers.h" 23 #include "runtime/mem/gc/card_table-inl.h" 24 25 namespace panda::mem { 26 27 // template <typename T> 28 class GC; 29 30 constexpr bool REMSET_THREAD_USE_STATS = false; 31 32 class RemsetThreadStats { 33 public: 34 void IncAddedCardToQueue(size_t value = 1) 35 { 36 if (REMSET_THREAD_USE_STATS) { 37 added_cards_to_queue += value; 38 } 39 } 40 IncProcessedConcurrentCards(const PandaUnorderedSet<CardTable::CardPtr> & cards)41 void IncProcessedConcurrentCards(const PandaUnorderedSet<CardTable::CardPtr> &cards) 42 { 43 if (REMSET_THREAD_USE_STATS) { 44 processed_concurrent_cards += cards.size(); 45 for (const auto &card : cards) { 46 unique_cards.insert(card); 47 } 48 } 49 } 50 IncProcessedAtSTWCards(const PandaUnorderedSet<CardTable::CardPtr> & cards)51 void IncProcessedAtSTWCards(const PandaUnorderedSet<CardTable::CardPtr> &cards) 52 { 53 if (REMSET_THREAD_USE_STATS) { 54 processed_at_stw_cards += cards.size(); 55 for (const auto &card : cards) { 56 unique_cards.insert(card); 57 } 58 } 59 } 60 Reset()61 void Reset() 62 { 63 added_cards_to_queue = processed_concurrent_cards = processed_at_stw_cards = 0; 64 unique_cards.clear(); 65 } 66 PrintStats()67 void PrintStats() const 68 { 69 if (REMSET_THREAD_USE_STATS) { 70 LOG(DEBUG, GC) << "remset thread stats: " 71 << "added_cards_to_queue: " << added_cards_to_queue 72 << " processed_concurrent_cards: " << processed_concurrent_cards 73 << " processed_at_stw_cards: " << processed_at_stw_cards 74 << " uniq_cards_processed: " << unique_cards.size(); 75 } 76 } 77 78 private: 79 std::atomic<size_t> added_cards_to_queue {0}; 80 std::atomic<size_t> processed_concurrent_cards {0}; 81 std::atomic<size_t> processed_at_stw_cards {0}; 82 PandaUnorderedSet<CardTable::CardPtr> unique_cards; 83 }; 84 85 template <class LanguageConfig> 86 class UpdateRemsetThread { 87 public: 88 explicit UpdateRemsetThread(GC *gc, PandaVM *vm, GCG1BarrierSet::ThreadLocalCardQueues *queue, 89 os::memory::Mutex *queue_lock, size_t region_size, bool update_concurrent, 90 size_t min_concurrent_cards_to_process, CardTable *card_table); 91 ~UpdateRemsetThread() = default; 92 NO_COPY_SEMANTIC(UpdateRemsetThread); 93 NO_MOVE_SEMANTIC(UpdateRemsetThread); 94 95 void CreateThread(InternalAllocatorPtr internal_allocator); 96 97 void DestroyThread(); 98 99 void StartThread(); 100 101 /** 102 * Blocking call until all tasks are not processed 103 */ 104 void WaitUntilTasksEnd(); 105 106 void ThreadLoop(); 107 108 // only debug purpose GetQueueSize()109 size_t GetQueueSize() const 110 { 111 os::memory::LockHolder holder(*queue_lock_); 112 return queue_->size(); 113 } 114 SetUpdateConcurrent(bool value)115 void SetUpdateConcurrent(bool value) 116 { 117 os::memory::LockHolder holder(loop_lock); 118 update_concurrent_ = value; 119 } 120 InvalidateRegions(PandaVector<Region * > * regions)121 void InvalidateRegions(PandaVector<Region *> *regions) 122 { 123 need_invalidate_region_ = true; 124 { 125 os::memory::LockHolder holder(loop_lock); 126 invalidate_regions_ = regions; 127 } 128 thread_cond_var_.Signal(); 129 { 130 os::memory::LockHolder holder(loop_lock); 131 while (invalidate_regions_ != nullptr) { 132 Sleep(); 133 } 134 } 135 need_invalidate_region_ = false; 136 thread_cond_var_.Signal(); 137 } 138 139 private: 140 void HandleCard(CardTable::CardPtr card_ptr) REQUIRES(loop_lock); 141 142 void BuildSetFromQueue() REQUIRES(loop_lock); 143 144 void DrainThreads() REQUIRES(loop_lock); 145 void DrainThread(ManagedThread *thread); 146 147 size_t ProcessAllCards() REQUIRES(loop_lock); 148 Sleep()149 void Sleep() 150 { 151 static constexpr uint64_t SLEEP_MS = 1; 152 thread_cond_var_.TimedWait(&loop_lock, SLEEP_MS); 153 } 154 155 GC *gc_ {nullptr}; 156 PandaVM *vm_ {nullptr}; 157 CardTable *card_table_ {nullptr}; GUARDED_BY(queue_lock_)158 GCG1BarrierSet::ThreadLocalCardQueues *queue_ GUARDED_BY(queue_lock_) {nullptr}; 159 os::memory::Mutex *queue_lock_ {nullptr}; 160 PandaUnorderedSet<CardTable::CardPtr> cards_; GUARDED_BY(loop_lock)161 PandaVector<Region *> *invalidate_regions_ GUARDED_BY(loop_lock) {nullptr}; 162 /* 163 * We use this lock to synchronize UpdateRemSet and external operations with it (as 164 * WaitUntilTasksEnd/DestroyThread/etc), wait and notify this thread. 165 */ 166 os::memory::Mutex loop_lock; 167 bool update_concurrent_; // used to process reference in gc-thread between zygote phases 168 size_t region_size_bits_; 169 size_t min_concurrent_cards_to_process_; 170 std::thread *update_thread_ {nullptr}; 171 os::memory::ConditionVariable thread_cond_var_; 172 std::atomic<bool> stop_thread_ {false}; 173 std::atomic<bool> pause_thread_ {false}; 174 std::atomic<bool> need_invalidate_region_ {false}; 175 176 RemsetThreadStats stats_; 177 }; 178 } // namespace panda::mem 179 #endif // PANDA_RUNTIME_MEM_GC_G1_UPDATE_REMSET_THREAD_H 180