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