• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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