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