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 
Iteration()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 
Reset(GcCause gc_cause,bool clear_soft_references)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 
GetEstimatedThroughput() const56 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 
GarbageCollector(Heap * heap,const std::string & name)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 
RegisterPause(uint64_t nano_length)70 void GarbageCollector::RegisterPause(uint64_t nano_length) {
71   GetCurrentIteration()->pause_times_.push_back(nano_length);
72 }
73 
ResetCumulativeStatistics()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 
Run(GcCause gc_cause,bool clear_soft_references)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 
SwapBitmaps()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 
GetEstimatedMeanThroughput() const144 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 
ResetMeasurements()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 
ScopedPause(GarbageCollector * collector)160 GarbageCollector::ScopedPause::ScopedPause(GarbageCollector* collector)
161     : start_time_(NanoTime()), collector_(collector) {
162   Runtime::Current()->GetThreadList()->SuspendAll(__FUNCTION__);
163 }
164 
~ScopedPause()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.
GetCurrentIteration()171 Iteration* GarbageCollector::GetCurrentIteration() {
172   return heap_->GetCurrentGcIteration();
173 }
GetCurrentIteration() const174 const Iteration* GarbageCollector::GetCurrentIteration() const {
175   return heap_->GetCurrentGcIteration();
176 }
177 
RecordFree(const ObjectBytePair & freed)178 void GarbageCollector::RecordFree(const ObjectBytePair& freed) {
179   GetCurrentIteration()->freed_.Add(freed);
180   heap_->RecordFree(freed.objects, freed.bytes);
181 }
RecordFreeLOS(const ObjectBytePair & freed)182 void GarbageCollector::RecordFreeLOS(const ObjectBytePair& freed) {
183   GetCurrentIteration()->freed_los_.Add(freed);
184   heap_->RecordFree(freed.objects, freed.bytes);
185 }
186 
GetTotalPausedTimeNs()187 uint64_t GarbageCollector::GetTotalPausedTimeNs() {
188   MutexLock mu(Thread::Current(), pause_histogram_lock_);
189   return pause_histogram_.AdjustedSum();
190 }
191 
DumpPerformanceInfo(std::ostream & os)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