1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <stdio.h> 18 19#include "garbage_collector.h" 20 21#include "android-base/stringprintf.h" 22 23#include "base/dumpable.h" 24#include "base/histogram-inl.h" 25#include "base/logging.h" 26#include "base/mutex-inl.h" 27#include "base/systrace.h" 28#include "base/time_utils.h" 29#include "gc/accounting/heap_bitmap.h" 30#include "gc/gc_pause_listener.h" 31#include "gc/heap.h" 32#include "gc/space/large_object_space.h" 33#include "gc/space/space-inl.h" 34#include "thread-inl.h" 35#include "thread_list.h" 36#include "utils.h" 37 38namespace art { 39namespace gc { 40namespace collector { 41 42Iteration::Iteration() 43 : duration_ns_(0), timings_("GC iteration timing logger", true, VLOG_IS_ON(heap)) { 44 Reset(kGcCauseBackground, false); // Reset to some place holder values. 45} 46 47void Iteration::Reset(GcCause gc_cause, bool clear_soft_references) { 48 timings_.Reset(); 49 pause_times_.clear(); 50 duration_ns_ = 0; 51 clear_soft_references_ = clear_soft_references; 52 gc_cause_ = gc_cause; 53 freed_ = ObjectBytePair(); 54 freed_los_ = ObjectBytePair(); 55 freed_bytes_revoke_ = 0; 56} 57 58uint64_t Iteration::GetEstimatedThroughput() const { 59 // Add 1ms to prevent possible division by 0. 60 return (static_cast<uint64_t>(freed_.bytes) * 1000) / (NsToMs(GetDurationNs()) + 1); 61} 62 63GarbageCollector::GarbageCollector(Heap* heap, const std::string& name) 64 : heap_(heap), 65 name_(name), 66 pause_histogram_((name_ + " paused").c_str(), kPauseBucketSize, kPauseBucketCount), 67 cumulative_timings_(name), 68 pause_histogram_lock_("pause histogram lock", kDefaultMutexLevel, true), 69 is_transaction_active_(false) { 70 ResetCumulativeStatistics(); 71} 72 73void GarbageCollector::RegisterPause(uint64_t nano_length) { 74 GetCurrentIteration()->pause_times_.push_back(nano_length); 75} 76 77void GarbageCollector::ResetCumulativeStatistics() { 78 cumulative_timings_.Reset(); 79 total_time_ns_ = 0; 80 total_freed_objects_ = 0; 81 total_freed_bytes_ = 0; 82 MutexLock mu(Thread::Current(), pause_histogram_lock_); 83 pause_histogram_.Reset(); 84} 85 86void GarbageCollector::Run(GcCause gc_cause, bool clear_soft_references) { 87 ScopedTrace trace(android::base::StringPrintf("%s %s GC", PrettyCause(gc_cause), GetName())); 88 Thread* self = Thread::Current(); 89 uint64_t start_time = NanoTime(); 90 Iteration* current_iteration = GetCurrentIteration(); 91 current_iteration->Reset(gc_cause, clear_soft_references); 92 // Note transaction mode is single-threaded and there's no asynchronous GC and this flag doesn't 93 // change in the middle of a GC. 94 is_transaction_active_ = Runtime::Current()->IsActiveTransaction(); 95 RunPhases(); // Run all the GC phases. 96 // Add the current timings to the cumulative timings. 97 cumulative_timings_.AddLogger(*GetTimings()); 98 // Update cumulative statistics with how many bytes the GC iteration freed. 99 total_freed_objects_ += current_iteration->GetFreedObjects() + 100 current_iteration->GetFreedLargeObjects(); 101 total_freed_bytes_ += current_iteration->GetFreedBytes() + 102 current_iteration->GetFreedLargeObjectBytes(); 103 uint64_t end_time = NanoTime(); 104 current_iteration->SetDurationNs(end_time - start_time); 105 if (Locks::mutator_lock_->IsExclusiveHeld(self)) { 106 // The entire GC was paused, clear the fake pauses which might be in the pause times and add 107 // the whole GC duration. 108 current_iteration->pause_times_.clear(); 109 RegisterPause(current_iteration->GetDurationNs()); 110 } 111 total_time_ns_ += current_iteration->GetDurationNs(); 112 for (uint64_t pause_time : current_iteration->GetPauseTimes()) { 113 MutexLock mu(self, pause_histogram_lock_); 114 pause_histogram_.AdjustAndAddValue(pause_time); 115 } 116 is_transaction_active_ = false; 117} 118 119void GarbageCollector::SwapBitmaps() { 120 TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings()); 121 // Swap the live and mark bitmaps for each alloc space. This is needed since sweep re-swaps 122 // these bitmaps. The bitmap swapping is an optimization so that we do not need to clear the live 123 // bits of dead objects in the live bitmap. 124 const GcType gc_type = GetGcType(); 125 for (const auto& space : GetHeap()->GetContinuousSpaces()) { 126 // We never allocate into zygote spaces. 127 if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect || 128 (gc_type == kGcTypeFull && 129 space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect)) { 130 accounting::ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap(); 131 accounting::ContinuousSpaceBitmap* mark_bitmap = space->GetMarkBitmap(); 132 if (live_bitmap != nullptr && live_bitmap != mark_bitmap) { 133 heap_->GetLiveBitmap()->ReplaceBitmap(live_bitmap, mark_bitmap); 134 heap_->GetMarkBitmap()->ReplaceBitmap(mark_bitmap, live_bitmap); 135 CHECK(space->IsContinuousMemMapAllocSpace()); 136 space->AsContinuousMemMapAllocSpace()->SwapBitmaps(); 137 } 138 } 139 } 140 for (const auto& disc_space : GetHeap()->GetDiscontinuousSpaces()) { 141 space::LargeObjectSpace* space = disc_space->AsLargeObjectSpace(); 142 accounting::LargeObjectBitmap* live_set = space->GetLiveBitmap(); 143 accounting::LargeObjectBitmap* mark_set = space->GetMarkBitmap(); 144 heap_->GetLiveBitmap()->ReplaceLargeObjectBitmap(live_set, mark_set); 145 heap_->GetMarkBitmap()->ReplaceLargeObjectBitmap(mark_set, live_set); 146 space->SwapBitmaps(); 147 } 148} 149 150uint64_t GarbageCollector::GetEstimatedMeanThroughput() const { 151 // Add 1ms to prevent possible division by 0. 152 return (total_freed_bytes_ * 1000) / (NsToMs(GetCumulativeTimings().GetTotalNs()) + 1); 153} 154 155void GarbageCollector::ResetMeasurements() { 156 { 157 MutexLock mu(Thread::Current(), pause_histogram_lock_); 158 pause_histogram_.Reset(); 159 } 160 cumulative_timings_.Reset(); 161 total_time_ns_ = 0; 162 total_freed_objects_ = 0; 163 total_freed_bytes_ = 0; 164} 165 166GarbageCollector::ScopedPause::ScopedPause(GarbageCollector* collector, bool with_reporting) 167 : start_time_(NanoTime()), collector_(collector), with_reporting_(with_reporting) { 168 Runtime* runtime = Runtime::Current(); 169 runtime->GetThreadList()->SuspendAll(__FUNCTION__); 170 if (with_reporting) { 171 GcPauseListener* pause_listener = runtime->GetHeap()->GetGcPauseListener(); 172 if (pause_listener != nullptr) { 173 pause_listener->StartPause(); 174 } 175 } 176} 177 178GarbageCollector::ScopedPause::~ScopedPause() { 179 collector_->RegisterPause(NanoTime() - start_time_); 180 Runtime* runtime = Runtime::Current(); 181 if (with_reporting_) { 182 GcPauseListener* pause_listener = runtime->GetHeap()->GetGcPauseListener(); 183 if (pause_listener != nullptr) { 184 pause_listener->EndPause(); 185 } 186 } 187 runtime->GetThreadList()->ResumeAll(); 188} 189 190// Returns the current GC iteration and assocated info. 191Iteration* GarbageCollector::GetCurrentIteration() { 192 return heap_->GetCurrentGcIteration(); 193} 194const Iteration* GarbageCollector::GetCurrentIteration() const { 195 return heap_->GetCurrentGcIteration(); 196} 197 198void GarbageCollector::RecordFree(const ObjectBytePair& freed) { 199 GetCurrentIteration()->freed_.Add(freed); 200 heap_->RecordFree(freed.objects, freed.bytes); 201} 202void GarbageCollector::RecordFreeLOS(const ObjectBytePair& freed) { 203 GetCurrentIteration()->freed_los_.Add(freed); 204 heap_->RecordFree(freed.objects, freed.bytes); 205} 206 207uint64_t GarbageCollector::GetTotalPausedTimeNs() { 208 MutexLock mu(Thread::Current(), pause_histogram_lock_); 209 return pause_histogram_.AdjustedSum(); 210} 211 212void GarbageCollector::DumpPerformanceInfo(std::ostream& os) { 213 const CumulativeLogger& logger = GetCumulativeTimings(); 214 const size_t iterations = logger.GetIterations(); 215 if (iterations == 0) { 216 return; 217 } 218 os << Dumpable<CumulativeLogger>(logger); 219 const uint64_t total_ns = logger.GetTotalNs(); 220 double seconds = NsToMs(logger.GetTotalNs()) / 1000.0; 221 const uint64_t freed_bytes = GetTotalFreedBytes(); 222 const uint64_t freed_objects = GetTotalFreedObjects(); 223 { 224 MutexLock mu(Thread::Current(), pause_histogram_lock_); 225 if (pause_histogram_.SampleSize() > 0) { 226 Histogram<uint64_t>::CumulativeData cumulative_data; 227 pause_histogram_.CreateHistogram(&cumulative_data); 228 pause_histogram_.PrintConfidenceIntervals(os, 0.99, cumulative_data); 229 } 230 } 231 os << GetName() << " total time: " << PrettyDuration(total_ns) 232 << " mean time: " << PrettyDuration(total_ns / iterations) << "\n" 233 << GetName() << " freed: " << freed_objects 234 << " objects with total size " << PrettySize(freed_bytes) << "\n" 235 << GetName() << " throughput: " << freed_objects / seconds << "/s / " 236 << PrettySize(freed_bytes / seconds) << "/s\n"; 237} 238 239} // namespace collector 240} // namespace gc 241} // namespace art 242