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