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