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