Home | History | Annotate | Download | only in collector
      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 
     30 namespace art {
     31 namespace gc {
     32 namespace collector {
     33 
     34 Iteration::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 
     39 void 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 
     49 uint64_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 
     54 GarbageCollector::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 
     62 void GarbageCollector::RegisterPause(uint64_t nano_length) {
     63   GetCurrentIteration()->pause_times_.push_back(nano_length);
     64 }
     65 
     66 void 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 
     74 void 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 
    103 void 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 
    134 uint64_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 
    139 void 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 
    147 GarbageCollector::ScopedPause::ScopedPause(GarbageCollector* collector)
    148     : start_time_(NanoTime()), collector_(collector) {
    149   Runtime::Current()->GetThreadList()->SuspendAll();
    150 }
    151 
    152 GarbageCollector::ScopedPause::~ScopedPause() {
    153   collector_->RegisterPause(NanoTime() - start_time_);
    154   Runtime::Current()->GetThreadList()->ResumeAll();
    155 }
    156 
    157 // Returns the current GC iteration and assocated info.
    158 Iteration* GarbageCollector::GetCurrentIteration() {
    159   return heap_->GetCurrentGcIteration();
    160 }
    161 const Iteration* GarbageCollector::GetCurrentIteration() const {
    162   return heap_->GetCurrentGcIteration();
    163 }
    164 
    165 void GarbageCollector::RecordFree(const ObjectBytePair& freed) {
    166   GetCurrentIteration()->freed_.Add(freed);
    167   heap_->RecordFree(freed.objects, freed.bytes);
    168 }
    169 void 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