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 "base/dumpable.h" 22 #include "base/histogram-inl.h" 23 #include "base/logging.h" 24 #include "base/mutex-inl.h" 25 #include "base/systrace.h" 26 #include "base/time_utils.h" 27 #include "gc/accounting/heap_bitmap.h" 28 #include "gc/space/large_object_space.h" 29 #include "gc/space/space-inl.h" 30 #include "thread-inl.h" 31 #include "thread_list.h" 32 #include "utils.h" 33 34 namespace art { 35 namespace gc { 36 namespace collector { 37 38 Iteration::Iteration() 39 : duration_ns_(0), timings_("GC iteration timing logger", true, VLOG_IS_ON(heap)) { 40 Reset(kGcCauseBackground, false); // Reset to some place holder values. 41 } 42 43 void Iteration::Reset(GcCause gc_cause, bool clear_soft_references) { 44 timings_.Reset(); 45 pause_times_.clear(); 46 duration_ns_ = 0; 47 clear_soft_references_ = clear_soft_references; 48 gc_cause_ = gc_cause; 49 freed_ = ObjectBytePair(); 50 freed_los_ = ObjectBytePair(); 51 freed_bytes_revoke_ = 0; 52 } 53 54 uint64_t Iteration::GetEstimatedThroughput() const { 55 // Add 1ms to prevent possible division by 0. 56 return (static_cast<uint64_t>(freed_.bytes) * 1000) / (NsToMs(GetDurationNs()) + 1); 57 } 58 59 GarbageCollector::GarbageCollector(Heap* heap, const std::string& name) 60 : heap_(heap), 61 name_(name), 62 pause_histogram_((name_ + " paused").c_str(), kPauseBucketSize, kPauseBucketCount), 63 cumulative_timings_(name), 64 pause_histogram_lock_("pause histogram lock", kDefaultMutexLevel, true) { 65 ResetCumulativeStatistics(); 66 } 67 68 void GarbageCollector::RegisterPause(uint64_t nano_length) { 69 GetCurrentIteration()->pause_times_.push_back(nano_length); 70 } 71 72 void GarbageCollector::ResetCumulativeStatistics() { 73 cumulative_timings_.Reset(); 74 total_time_ns_ = 0; 75 total_freed_objects_ = 0; 76 total_freed_bytes_ = 0; 77 MutexLock mu(Thread::Current(), pause_histogram_lock_); 78 pause_histogram_.Reset(); 79 } 80 81 void GarbageCollector::Run(GcCause gc_cause, bool clear_soft_references) { 82 ScopedTrace trace(StringPrintf("%s %s GC", PrettyCause(gc_cause), GetName())); 83 Thread* self = Thread::Current(); 84 uint64_t start_time = NanoTime(); 85 Iteration* current_iteration = GetCurrentIteration(); 86 current_iteration->Reset(gc_cause, clear_soft_references); 87 RunPhases(); // Run all the GC phases. 88 // Add the current timings to the cumulative timings. 89 cumulative_timings_.AddLogger(*GetTimings()); 90 // Update cumulative statistics with how many bytes the GC iteration freed. 91 total_freed_objects_ += current_iteration->GetFreedObjects() + 92 current_iteration->GetFreedLargeObjects(); 93 total_freed_bytes_ += current_iteration->GetFreedBytes() + 94 current_iteration->GetFreedLargeObjectBytes(); 95 uint64_t end_time = NanoTime(); 96 current_iteration->SetDurationNs(end_time - start_time); 97 if (Locks::mutator_lock_->IsExclusiveHeld(self)) { 98 // The entire GC was paused, clear the fake pauses which might be in the pause times and add 99 // the whole GC duration. 100 current_iteration->pause_times_.clear(); 101 RegisterPause(current_iteration->GetDurationNs()); 102 } 103 total_time_ns_ += current_iteration->GetDurationNs(); 104 for (uint64_t pause_time : current_iteration->GetPauseTimes()) { 105 MutexLock mu(self, pause_histogram_lock_); 106 pause_histogram_.AdjustAndAddValue(pause_time); 107 } 108 } 109 110 void GarbageCollector::SwapBitmaps() { 111 TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings()); 112 // Swap the live and mark bitmaps for each alloc space. This is needed since sweep re-swaps 113 // these bitmaps. The bitmap swapping is an optimization so that we do not need to clear the live 114 // bits of dead objects in the live bitmap. 115 const GcType gc_type = GetGcType(); 116 for (const auto& space : GetHeap()->GetContinuousSpaces()) { 117 // We never allocate into zygote spaces. 118 if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect || 119 (gc_type == kGcTypeFull && 120 space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect)) { 121 accounting::ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap(); 122 accounting::ContinuousSpaceBitmap* mark_bitmap = space->GetMarkBitmap(); 123 if (live_bitmap != nullptr && live_bitmap != mark_bitmap) { 124 heap_->GetLiveBitmap()->ReplaceBitmap(live_bitmap, mark_bitmap); 125 heap_->GetMarkBitmap()->ReplaceBitmap(mark_bitmap, live_bitmap); 126 CHECK(space->IsContinuousMemMapAllocSpace()); 127 space->AsContinuousMemMapAllocSpace()->SwapBitmaps(); 128 } 129 } 130 } 131 for (const auto& disc_space : GetHeap()->GetDiscontinuousSpaces()) { 132 space::LargeObjectSpace* space = disc_space->AsLargeObjectSpace(); 133 accounting::LargeObjectBitmap* live_set = space->GetLiveBitmap(); 134 accounting::LargeObjectBitmap* mark_set = space->GetMarkBitmap(); 135 heap_->GetLiveBitmap()->ReplaceLargeObjectBitmap(live_set, mark_set); 136 heap_->GetMarkBitmap()->ReplaceLargeObjectBitmap(mark_set, live_set); 137 space->SwapBitmaps(); 138 } 139 } 140 141 uint64_t GarbageCollector::GetEstimatedMeanThroughput() const { 142 // Add 1ms to prevent possible division by 0. 143 return (total_freed_bytes_ * 1000) / (NsToMs(GetCumulativeTimings().GetTotalNs()) + 1); 144 } 145 146 void GarbageCollector::ResetMeasurements() { 147 { 148 MutexLock mu(Thread::Current(), pause_histogram_lock_); 149 pause_histogram_.Reset(); 150 } 151 cumulative_timings_.Reset(); 152 total_time_ns_ = 0; 153 total_freed_objects_ = 0; 154 total_freed_bytes_ = 0; 155 } 156 157 GarbageCollector::ScopedPause::ScopedPause(GarbageCollector* collector) 158 : start_time_(NanoTime()), collector_(collector) { 159 Runtime::Current()->GetThreadList()->SuspendAll(__FUNCTION__); 160 } 161 162 GarbageCollector::ScopedPause::~ScopedPause() { 163 collector_->RegisterPause(NanoTime() - start_time_); 164 Runtime::Current()->GetThreadList()->ResumeAll(); 165 } 166 167 // Returns the current GC iteration and assocated info. 168 Iteration* GarbageCollector::GetCurrentIteration() { 169 return heap_->GetCurrentGcIteration(); 170 } 171 const Iteration* GarbageCollector::GetCurrentIteration() const { 172 return heap_->GetCurrentGcIteration(); 173 } 174 175 void GarbageCollector::RecordFree(const ObjectBytePair& freed) { 176 GetCurrentIteration()->freed_.Add(freed); 177 heap_->RecordFree(freed.objects, freed.bytes); 178 } 179 void GarbageCollector::RecordFreeLOS(const ObjectBytePair& freed) { 180 GetCurrentIteration()->freed_los_.Add(freed); 181 heap_->RecordFree(freed.objects, freed.bytes); 182 } 183 184 uint64_t GarbageCollector::GetTotalPausedTimeNs() { 185 MutexLock mu(Thread::Current(), pause_histogram_lock_); 186 return pause_histogram_.AdjustedSum(); 187 } 188 189 void GarbageCollector::DumpPerformanceInfo(std::ostream& os) { 190 const CumulativeLogger& logger = GetCumulativeTimings(); 191 const size_t iterations = logger.GetIterations(); 192 if (iterations == 0) { 193 return; 194 } 195 os << Dumpable<CumulativeLogger>(logger); 196 const uint64_t total_ns = logger.GetTotalNs(); 197 double seconds = NsToMs(logger.GetTotalNs()) / 1000.0; 198 const uint64_t freed_bytes = GetTotalFreedBytes(); 199 const uint64_t freed_objects = GetTotalFreedObjects(); 200 { 201 MutexLock mu(Thread::Current(), pause_histogram_lock_); 202 if (pause_histogram_.SampleSize() > 0) { 203 Histogram<uint64_t>::CumulativeData cumulative_data; 204 pause_histogram_.CreateHistogram(&cumulative_data); 205 pause_histogram_.PrintConfidenceIntervals(os, 0.99, cumulative_data); 206 } 207 } 208 os << GetName() << " total time: " << PrettyDuration(total_ns) 209 << " mean time: " << PrettyDuration(total_ns / iterations) << "\n" 210 << GetName() << " freed: " << freed_objects 211 << " objects with total size " << PrettySize(freed_bytes) << "\n" 212 << GetName() << " throughput: " << freed_objects / seconds << "/s / " 213 << PrettySize(freed_bytes / seconds) << "/s\n"; 214 } 215 216 } // namespace collector 217 } // namespace gc 218 } // namespace art 219