1 /** 2 * Copyright (c) 2023-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_G1_UPDATE_REMSET_WORKER_H 17 #define PANDA_RUNTIME_MEM_GC_G1_UPDATE_REMSET_WORKER_H 18 19 #include "libpandabase/os/mutex.h" 20 #include "runtime/mem/gc/card_table.h" 21 #include "runtime/mem/gc/gc_barrier_set.h" 22 #include "runtime/mem/gc/g1/hot_cards.h" 23 24 namespace ark::mem { 25 // Forward declarations for UpdateRemsetWorker: 26 template <class LanguageConfig> 27 class G1GC; 28 class Region; 29 30 template <class LanguageConfig> 31 class UpdateRemsetWorker { 32 public: 33 UpdateRemsetWorker(G1GC<LanguageConfig> *gc, GCG1BarrierSet::ThreadLocalCardQueues *queue, 34 os::memory::Mutex *queueLock, size_t regionSize, bool updateConcurrent, 35 size_t minConcurrentCardsToProcess, size_t hotCardsProcessingFrequency); 36 NO_COPY_SEMANTIC(UpdateRemsetWorker); 37 NO_MOVE_SEMANTIC(UpdateRemsetWorker); 38 39 virtual ~UpdateRemsetWorker(); 40 41 /// @brief Create necessary worker structures and start UpdateRemsetWorker 42 void CreateWorker(); 43 44 /// @brief Stop UpdateRemsetWorker and destroy according worker structures 45 void DestroyWorker(); 46 SetUpdateConcurrent(bool value)47 ALWAYS_INLINE void SetUpdateConcurrent(bool value) 48 { 49 os::memory::LockHolder holder(updateRemsetLock_); 50 updateConcurrent_ = value; 51 } 52 53 /** 54 * @brief add post-barrier buffer to process according cards in UpdateRemsetWorker 55 * @param buffer post-barrier buffer 56 */ 57 void AddPostBarrierBuffer(PandaVector<mem::CardTable::CardPtr> *buffer); 58 59 /** 60 * @brief Drain all cards to GC. Can be called only if UpdateRemsetWorker is suspended 61 * @param cards pointer for saving all unprocessed cards 62 */ 63 void DrainAllCards(PandaUnorderedSet<CardTable::CardPtr> *cards); 64 65 /** 66 * @brief Suspend UpdateRemsetWorker to reduce CPU usage during GC puase. 67 * Pause cards processing in UpdateRemsetWorker 68 */ 69 void SuspendWorkerForGCPause(); 70 71 /** 72 * @brief Resume UpdateRemsetWorker execution loop. 73 * Continue cards processing in UpdateRemsetWorker 74 */ 75 virtual void ResumeWorkerAfterGCPause(); 76 77 /** 78 * @brief Process all cards in the GC thread. 79 * Can be called only if UpdateRemsetWorker is suspended 80 */ 81 void GCProcessCards(); 82 83 using RegionVector = PandaVector<Region *>; 84 85 /** 86 * @brief Invalidate regions during non-pause GC phase. 87 * Pause cards processing in UpdateRemsetWorker during regions invalidation 88 * @param regions regions for invalidation 89 */ 90 void InvalidateRegions(RegionVector *regions); 91 92 /** 93 * @brief Invalidate regions in the GC thread 94 * Can be called only if UpdateRemsetWorker is suspended 95 * @param regions regions for invalidation 96 */ 97 void GCInvalidateRegions(RegionVector *regions); 98 99 #ifndef NDEBUG 100 // only debug purpose GetQueueSize()101 ALWAYS_INLINE size_t GetQueueSize() const 102 { 103 os::memory::LockHolder holder(*queueLock_); 104 return queue_->size(); 105 } 106 #endif // NDEBUG 107 108 protected: 109 /// @brief Create implementation specific structures and start UpdateRemsetWorker in according with these 110 virtual void CreateWorkerImpl() = 0; 111 112 /// @brief Stop implementation specific UpdateRemsetWorker and destroy according structures 113 virtual void DestroyWorkerImpl() = 0; 114 115 /// @brief Try to process all unprocessed cards in one thread 116 size_t ProcessAllCards() REQUIRES(updateRemsetLock_); 117 118 /// @brief Try to process hot cards in one thread 119 size_t ProcessHotCards() REQUIRES(updateRemsetLock_); 120 121 /// @brief Try to process cards from barriers in one thread 122 size_t ProcessCommonCards() REQUIRES(updateRemsetLock_); 123 124 /** 125 * @brief Notify UpdateRemsetWorker to continue process cards 126 * @see SuspendWorkerForGCPause 127 * @see ResumeWorkerAfterGCPause 128 * @see InvalidateRegions 129 */ 130 virtual void ContinueProcessCards() REQUIRES(updateRemsetLock_) = 0; 131 GetGC()132 ALWAYS_INLINE G1GC<LanguageConfig> *GetGC() const 133 { 134 return gc_; 135 } 136 137 /// @enum UpdateRemsetWorkerFlags is special flags for indicating of process kind in UpdateRemsetWorker 138 enum class UpdateRemsetWorkerFlags : uint32_t { 139 IS_PROCESS_CARD = 0U, ///< Special value for main work (process cards) in update remset worker 140 IS_STOP_WORKER = 1U, ///< Update remset worker is in destroying process 141 IS_PAUSED_BY_GC_THREAD = 1U << 1U, ///< Update remset worker is paused by GCThread 142 IS_INVALIDATE_REGIONS = 1U << 2U, ///< Update remset worker is invalidating regions 143 }; 144 IsFlag(UpdateRemsetWorkerFlags value)145 ALWAYS_INLINE bool IsFlag(UpdateRemsetWorkerFlags value) const 146 { 147 return iterationFlag_ == value; 148 } 149 SetFlag(UpdateRemsetWorkerFlags value)150 ALWAYS_INLINE void SetFlag(UpdateRemsetWorkerFlags value) 151 { 152 iterationFlag_ = value; 153 } 154 RemoveFlag(UpdateRemsetWorkerFlags value)155 ALWAYS_INLINE void RemoveFlag([[maybe_unused]] UpdateRemsetWorkerFlags value) 156 { 157 ASSERT(iterationFlag_ == value); 158 iterationFlag_ = UpdateRemsetWorkerFlags::IS_PROCESS_CARD; 159 } 160 GetFlag()161 ALWAYS_INLINE UpdateRemsetWorkerFlags GetFlag() const 162 { 163 return iterationFlag_; 164 } 165 GetMinConcurrentCardsToProcess()166 ALWAYS_INLINE size_t GetMinConcurrentCardsToProcess() const 167 { 168 return minConcurrentCardsToProcess_; 169 } 170 171 /** 172 * We use this lock to synchronize UpdateRemsetWorker and external operations with it 173 * (as SuspendWorkerForGCPause/ResumeWorkerAfterGCPause/DestroyWorker/etc), wait and notify this worker. 174 */ 175 os::memory::Mutex updateRemsetLock_; // NOLINT(misc-non-private-member-variables-in-classes) 176 177 #ifndef NDEBUG 178 // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes) GUARDED_BY(updateRemsetLock_)179 std::atomic<bool> pausedByGcThread_ GUARDED_BY(updateRemsetLock_) {false}; 180 #endif 181 182 private: 183 void FillFromDefered(PandaUnorderedSet<CardTable::CardPtr> *cards) REQUIRES(updateRemsetLock_); 184 void FillFromQueue(PandaUnorderedSet<CardTable::CardPtr> *cards) REQUIRES(updateRemsetLock_); 185 void FillFromThreads(PandaUnorderedSet<CardTable::CardPtr> *cards) REQUIRES(updateRemsetLock_); 186 void FillFromHotCards(PandaUnorderedSet<CardTable::CardPtr> *cards) REQUIRES(updateRemsetLock_); 187 188 void FillFromPostBarrierBuffers(PandaUnorderedSet<CardTable::CardPtr> *cards); 189 void FillFromPostBarrierBuffer(GCG1BarrierSet::G1PostBarrierRingBufferType *postWrb, 190 PandaUnorderedSet<CardTable::CardPtr> *cards); 191 void FillFromPostBarrierBuffer(GCG1BarrierSet::ThreadLocalCardQueues *postWrb, 192 PandaUnorderedSet<CardTable::CardPtr> *cards); 193 194 void DoInvalidateRegions(RegionVector *regions) REQUIRES(updateRemsetLock_); 195 196 void UpdateCardStatus(CardTable::CardPtr card); 197 198 bool NeedProcessHotCards(); 199 200 G1GC<LanguageConfig> *gc_ {nullptr}; 201 size_t regionSizeBits_; 202 size_t minConcurrentCardsToProcess_; 203 size_t hotCardsProcessingFrequency_; GUARDED_BY(queueLock_)204 GCG1BarrierSet::ThreadLocalCardQueues *queue_ GUARDED_BY(queueLock_) {nullptr}; 205 os::memory::Mutex *queueLock_ {nullptr}; 206 bool updateConcurrent_; // used to process references in gc-thread between zygote phases 207 208 HotCards hotCards_; 209 PandaUnorderedSet<CardTable::CardPtr> cards_; 210 PandaVector<GCG1BarrierSet::ThreadLocalCardQueues *> postBarrierBuffers_ GUARDED_BY(postBarrierBuffersLock_); 211 os::memory::Mutex postBarrierBuffersLock_; 212 213 std::atomic<UpdateRemsetWorkerFlags> iterationFlag_ {UpdateRemsetWorkerFlags::IS_STOP_WORKER}; 214 215 // We do not fully update remset during collection pause 216 std::atomic<bool> deferCards_ {false}; 217 }; 218 219 template <class LanguageConfig> 220 class SuspendUpdateRemsetWorkerScope { 221 public: SuspendUpdateRemsetWorkerScope(UpdateRemsetWorker<LanguageConfig> * worker)222 explicit SuspendUpdateRemsetWorkerScope(UpdateRemsetWorker<LanguageConfig> *worker) : worker_(worker) 223 { 224 worker_->SuspendWorkerForGCPause(); 225 } ~SuspendUpdateRemsetWorkerScope()226 ~SuspendUpdateRemsetWorkerScope() 227 { 228 worker_->ResumeWorkerAfterGCPause(); 229 } 230 NO_COPY_SEMANTIC(SuspendUpdateRemsetWorkerScope); 231 NO_MOVE_SEMANTIC(SuspendUpdateRemsetWorkerScope); 232 233 private: 234 UpdateRemsetWorker<LanguageConfig> *worker_ {nullptr}; 235 }; 236 237 } // namespace ark::mem 238 239 #endif // PANDA_RUNTIME_MEM_GC_G1_UPDATE_REMSET_WORKER_H 240