diff --git a/runtime/mem/gc/g1/g1-gc.cpp b/runtime/mem/gc/g1/g1-gc.cpp index 35c05f27486b6fa30d90d251313e6f282851b186..8cea94628a9db3f97e5c4878c7be2fe153db323c 100644 --- a/runtime/mem/gc/g1/g1-gc.cpp +++ b/runtime/mem/gc/g1/g1-gc.cpp @@ -617,6 +617,8 @@ bool G1GC::NeedFullGC(const panda::GCTask &task) template void G1GC::RunPhasesImpl(panda::GCTask &task) { + this->GetPandaVm()->GetMemStats()->RecordGCPauseStart(); + GCScopedPauseStats scoped_pause_stats(this->GetPandaVm()->GetGCStats()); interrupt_concurrent_flag_ = false; LOG_DEBUG_GC << "G1GC start, reason: " << task.reason; LOG_DEBUG_GC << "Footprint before GC: " << this->GetPandaVm()->GetMemStats()->GetFootprintHeap(); @@ -626,10 +628,8 @@ void G1GC::RunPhasesImpl(panda::GCTask &task) { ScopedTiming t("G1 GC", *this->GetTiming()); { - GCScopedPauseStats scoped_pause_stats(this->GetPandaVm()->GetGCStats()); this->mem_stats_.Reset(); if (NeedToRunGC(task)) { - this->GetPandaVm()->GetMemStats()->RecordGCPauseStart(); // Check there is no concurrent mark running by another thread. // Atomic with relaxed order reason: concurrent access with another thread which can running GC now ASSERT(pre_wrb_entrypoint_.load(std::memory_order_relaxed) == nullptr); @@ -664,16 +664,15 @@ void G1GC::RunPhasesImpl(panda::GCTask &task) : "not enough free regions to move"); } } - this->GetPandaVm()->GetMemStats()->RecordGCPauseEnd(); } + if (task.reason == GCTaskCause::MIXED) { + // There was forced a mixed GC. This GC type sets specific settings. + // So we need to restore them. + region_garbage_rate_threshold_ = this->GetSettings()->G1RegionGarbageRateThreshold(); + } + ScheduleMixedGCAndConcurrentMark(task); + RunConcurrentMarkIfNeeded(task); } - if (task.reason == GCTaskCause::MIXED) { - // There was forced a mixed GC. This GC type sets specific settings. - // So we need to restore them. - region_garbage_rate_threshold_ = this->GetSettings()->G1RegionGarbageRateThreshold(); - } - ScheduleMixedGCAndConcurrentMark(task); - RunConcurrentMarkIfNeeded(task); } // Update global and GC memstats based on generational memstats information // We will update tenured stats and record allocations, so set 'true' values @@ -681,6 +680,8 @@ void G1GC::RunPhasesImpl(panda::GCTask &task) LOG_DEBUG_GC << "Footprint after GC: " << this->GetPandaVm()->GetMemStats()->GetFootprintHeap(); this->SetFullGC(false); + + this->GetPandaVm()->GetMemStats()->RecordGCPauseEnd(); } template @@ -1280,7 +1281,6 @@ void G1GC::StartMarking(panda::GCTask &task) } // Concurrent/on-pause marking { - this->GetPandaVm()->GetMemStats()->RecordGCPauseEnd(); // NOLINTNEXTLINE(readability-braces-around-statements) if constexpr (IS_CONCURRENT) { const ReferenceCheckPredicateT &disable_ref_pred = []([[maybe_unused]] const ObjectHeader *obj) { @@ -1342,7 +1342,6 @@ void G1GC::StartMarking(panda::GCTask &task) concurrent_marking_stack_.Clear(); } ASSERT(concurrent_marking_stack_.Empty()); - this->GetPandaVm()->GetMemStats()->RecordGCPauseStart(); } ASSERT(concurrent_marking_stack_.Empty()); } @@ -1390,10 +1389,6 @@ void G1GC::Remark(panda::GCTask const &task) if (use_gc_workers) { this->GetWorkersPool()->WaitUntilTasksEnd(); } - { - ScopedTiming remset_thread_timing("RemsetThread WaitUntilTasksEnd", *this->GetTiming()); - WaitForUpdateRemsetThread(); - } // ConcurrentMark doesn't visit young objects - so we can't clear references which are in young-space because we // don't know which objects are marked. We will process them on young/mixed GC separately later, here we process diff --git a/runtime/mem/gc/g1/update_remset_thread.cpp b/runtime/mem/gc/g1/update_remset_thread.cpp index 4f236ae923d569c5c86332b071c1a38bd52e3f31..e8343e83aac542df05d7b845bf685b0c5f6d4235 100644 --- a/runtime/mem/gc/g1/update_remset_thread.cpp +++ b/runtime/mem/gc/g1/update_remset_thread.cpp @@ -157,10 +157,27 @@ void UpdateRemsetThread::ThreadLoop() continue; } if (invalidate_regions_ != nullptr) { + FillFromDefered(&cards_); + FillFromQueue(&cards_); + FillFromThreads(&cards_); + + PandaSet region_set; for (const auto ®ion : *invalidate_regions_) { // don't need lock because only update_remset_thread changes remsets RemSet<>::template InvalidateRegion(region); + region_set.insert(region); + } + + for (auto it = cards_.begin(); it != cards_.end();) { + auto start_address = ToVoidPtr(card_table_->GetCardStartAddress(*it)); + auto region = AddrToRegion(start_address); + if (region_set.count(region) == 0) { + ++it; + continue; + } + it = cards_.erase(it); } + invalidate_regions_ = nullptr; thread_cond_var_.Signal(); Sleep(); diff --git a/runtime/mem/gc/g1/update_remset_thread.h b/runtime/mem/gc/g1/update_remset_thread.h index dfb150d4cc1298cea4ab47ecc474072a9e21f447..5681026561de31b4a1d21b9bd527a257224ae139 100644 --- a/runtime/mem/gc/g1/update_remset_thread.h +++ b/runtime/mem/gc/g1/update_remset_thread.h @@ -121,6 +121,8 @@ public: void InvalidateRegions(PandaVector *regions) { + // Atomic with relaxed order reason: memory order is not required + defer_cards_.store(true, std::memory_order_relaxed); need_invalidate_region_ = true; { os::memory::LockHolder holder(loop_lock_); @@ -132,6 +134,8 @@ public: while (invalidate_regions_ != nullptr) { Sleep(); } + // Atomic with relaxed order reason: memory order is not required + defer_cards_.store(false, std::memory_order_relaxed); } need_invalidate_region_ = false; thread_cond_var_.Signal(); diff --git a/runtime/mem/gc/gc_stats.cpp b/runtime/mem/gc/gc_stats.cpp index 6306ee9b136e85a57a850cc940640853d91ba667..c8aef1f555f5057dd95854a91ffa96852bb583ce 100644 --- a/runtime/mem/gc/gc_stats.cpp +++ b/runtime/mem/gc/gc_stats.cpp @@ -233,13 +233,13 @@ GCScopedStats::~GCScopedStats() } GCScopedPauseStats::GCScopedPauseStats(GCStats *stats, GCInstanceStats *instance_stats) - : start_time_(time::GetCurrentTimeInNanos()), instance_stats_(instance_stats), stats_(stats) + : start_time_(stats->mem_stats_->GetTotalGCPauseInNanos()), instance_stats_(instance_stats), stats_(stats) { } GCScopedPauseStats::~GCScopedPauseStats() { - stats_->RecordPause(time::GetCurrentTimeInNanos() - start_time_, instance_stats_); + stats_->RecordPause(stats_->mem_stats_->GetTotalGCPauseInNanos() - start_time_, instance_stats_); } PandaString GCInstanceStats::GetDump(GCType gc_type) diff --git a/runtime/mem/mem_stats.cpp b/runtime/mem/mem_stats.cpp index d654620dffe431e3d207c5d043dcaea44f621cbc..d0a33409bdaca46ea7aa3b9145d2f7dea630477e 100644 --- a/runtime/mem/mem_stats.cpp +++ b/runtime/mem/mem_stats.cpp @@ -233,6 +233,12 @@ uint64_t MemStats::GetTotalGCPause() const return std::chrono::duration_cast(sum_pause_).count(); } +template +uint64_t MemStats::GetTotalGCPauseInNanos() const +{ + return std::chrono::duration_cast(sum_pause_).count(); +} + template class MemStats; template class MemStats; } // namespace panda::mem diff --git a/runtime/mem/mem_stats.h b/runtime/mem/mem_stats.h index 4fc37115d0df783457d9b0aae7a747ef4c8e9397..7d52fdb17f8906fe7cd76774bb30b758f161c071 100644 --- a/runtime/mem/mem_stats.h +++ b/runtime/mem/mem_stats.h @@ -123,6 +123,7 @@ public: uint64_t GetMaxGCPause() const; uint64_t GetAverageGCPause() const; uint64_t GetTotalGCPause() const; + uint64_t GetTotalGCPauseInNanos() const; protected: using Clock = std::chrono::high_resolution_clock;