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
36namespace art {
37namespace gc {
38namespace collector {
39
40Iteration::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
45void 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
56uint64_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
61GarbageCollector::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
70void GarbageCollector::RegisterPause(uint64_t nano_length) {
71  GetCurrentIteration()->pause_times_.push_back(nano_length);
72}
73
74void 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
83void 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
113void 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
144uint64_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
149void 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
160GarbageCollector::ScopedPause::ScopedPause(GarbageCollector* collector)
161    : start_time_(NanoTime()), collector_(collector) {
162  Runtime::Current()->GetThreadList()->SuspendAll(__FUNCTION__);
163}
164
165GarbageCollector::ScopedPause::~ScopedPause() {
166  collector_->RegisterPause(NanoTime() - start_time_);
167  Runtime::Current()->GetThreadList()->ResumeAll();
168}
169
170// Returns the current GC iteration and assocated info.
171Iteration* GarbageCollector::GetCurrentIteration() {
172  return heap_->GetCurrentGcIteration();
173}
174const Iteration* GarbageCollector::GetCurrentIteration() const {
175  return heap_->GetCurrentGcIteration();
176}
177
178void GarbageCollector::RecordFree(const ObjectBytePair& freed) {
179  GetCurrentIteration()->freed_.Add(freed);
180  heap_->RecordFree(freed.objects, freed.bytes);
181}
182void GarbageCollector::RecordFreeLOS(const ObjectBytePair& freed) {
183  GetCurrentIteration()->freed_los_.Add(freed);
184  heap_->RecordFree(freed.objects, freed.bytes);
185}
186
187uint64_t GarbageCollector::GetTotalPausedTimeNs() {
188  MutexLock mu(Thread::Current(), pause_histogram_lock_);
189  return pause_histogram_.AdjustedSum();
190}
191
192void 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