Merge "Fix non concurrent GC ergonomics." into dalvik-dev
diff --git a/runtime/gc/accounting/card_table-inl.h b/runtime/gc/accounting/card_table-inl.h
index fa2ab27..c5e8812 100644
--- a/runtime/gc/accounting/card_table-inl.h
+++ b/runtime/gc/accounting/card_table-inl.h
@@ -65,8 +65,8 @@
(reinterpret_cast<uintptr_t>(card_end) & (sizeof(uintptr_t) - 1));
// Now we have the words, we can send these to be processed in parallel.
- auto* word_cur = reinterpret_cast<uintptr_t*>(card_cur);
- auto* word_end = reinterpret_cast<uintptr_t*>(aligned_end);
+ uintptr_t* word_cur = reinterpret_cast<uintptr_t*>(card_cur);
+ uintptr_t* word_end = reinterpret_cast<uintptr_t*>(aligned_end);
for (;;) {
while (LIKELY(*word_cur == 0)) {
++word_cur;
diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc
index 039415e..b7641a4 100644
--- a/runtime/gc/collector/garbage_collector.cc
+++ b/runtime/gc/collector/garbage_collector.cc
@@ -80,7 +80,7 @@
uint64_t pause_end = NanoTime();
pause_times_.push_back(pause_end - pause_start);
} else {
- auto* self = Thread::Current();
+ Thread* self = Thread::Current();
{
ReaderMutexLock mu(self, *Locks::mutator_lock_);
MarkingPhase();
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 5c31eb1..9c69fdf 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -268,7 +268,7 @@
void MarkSweep::ReclaimPhase() {
base::TimingLogger::ScopedSplit split("ReclaimPhase", &timings_);
- auto* self = Thread::Current();
+ Thread* self = Thread::Current();
if (!IsConcurrent()) {
base::TimingLogger::ScopedSplit split("ProcessReferences", &timings_);
@@ -745,14 +745,14 @@
ThreadPool* thread_pool = GetHeap()->GetThreadPool();
const bool parallel = kParallelCardScan && thread_pool != nullptr;
if (parallel) {
- auto* self = Thread::Current();
+ Thread* self = Thread::Current();
// Can't have a different split for each space since multiple spaces can have their cards being
// scanned at the same time.
timings_.StartSplit(paused ? "(Paused)ScanGrayObjects" : "ScanGrayObjects");
// Try to take some of the mark stack since we can pass this off to the worker tasks.
const Object** mark_stack_begin = const_cast<const Object**>(mark_stack_->Begin());
const Object** mark_stack_end = const_cast<const Object**>(mark_stack_->End());
- const auto mark_stack_size = mark_stack_end - mark_stack_begin;
+ const size_t mark_stack_size = mark_stack_end - mark_stack_begin;
const size_t thread_count = thread_pool->GetThreadCount() + 1;
// Estimated number of work tasks we will create.
const size_t mark_stack_tasks = GetHeap()->GetContinuousSpaces().size() * thread_count;
@@ -1209,8 +1209,8 @@
sweep_space = (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect);
}
if (sweep_space) {
- auto begin = reinterpret_cast<uintptr_t>(space->Begin());
- auto end = reinterpret_cast<uintptr_t>(space->End());
+ uintptr_t begin = reinterpret_cast<uintptr_t>(space->Begin());
+ uintptr_t end = reinterpret_cast<uintptr_t>(space->End());
scc.space = space->AsDlMallocSpace();
accounting::SpaceBitmap* live_bitmap = space->GetLiveBitmap();
accounting::SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 5b01104..e89dd66 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -59,17 +59,16 @@
namespace gc {
// When to create a log message about a slow GC, 100ms.
-static const uint64_t kSlowGcThreshold = MsToNs(100);
+static constexpr uint64_t kSlowGcThreshold = MsToNs(100);
// When to create a log message about a long pause, 5ms.
-static const uint64_t kLongGcPauseThreshold = MsToNs(5);
-static const bool kGCALotMode = false;
-static const size_t kGcAlotInterval = KB;
-static const bool kDumpGcPerformanceOnShutdown = false;
+static constexpr uint64_t kLongGcPauseThreshold = MsToNs(5);
+static constexpr bool kGCALotMode = false;
+static constexpr size_t kGcAlotInterval = KB;
+static constexpr bool kDumpGcPerformanceOnShutdown = false;
// Minimum amount of remaining bytes before a concurrent GC is triggered.
-static const size_t kMinConcurrentRemainingBytes = 128 * KB;
-const double Heap::kDefaultTargetUtilization = 0.5;
+static constexpr size_t kMinConcurrentRemainingBytes = 128 * KB;
// If true, measure the total allocation time.
-static const bool kMeasureAllocationTime = false;
+static constexpr bool kMeasureAllocationTime = false;
Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max_free,
double target_utilization, size_t capacity, const std::string& original_image_file_name,
@@ -100,8 +99,8 @@
// Initially care about pauses in case we never get notified of process states, or if the JNI
// code becomes broken.
care_about_pause_times_(true),
- concurrent_start_bytes_(concurrent_gc ? initial_size - kMinConcurrentRemainingBytes
- : std::numeric_limits<size_t>::max()),
+ concurrent_start_bytes_(concurrent_gc_ ? initial_size - kMinConcurrentRemainingBytes
+ : std::numeric_limits<size_t>::max()),
total_bytes_freed_ever_(0),
total_objects_freed_ever_(0),
large_object_threshold_(3 * kPageSize),
@@ -793,13 +792,26 @@
}
}
-inline bool Heap::IsOutOfMemoryOnAllocation(size_t alloc_size) {
- return num_bytes_allocated_ + alloc_size > growth_limit_;
+inline bool Heap::IsOutOfMemoryOnAllocation(size_t alloc_size, bool grow) {
+ size_t new_footprint = num_bytes_allocated_ + alloc_size;
+ if (UNLIKELY(new_footprint > max_allowed_footprint_)) {
+ if (UNLIKELY(new_footprint > growth_limit_)) {
+ return true;
+ }
+ if (!concurrent_gc_) {
+ if (!grow) {
+ return true;
+ } else {
+ max_allowed_footprint_ = new_footprint;
+ }
+ }
+ }
+ return false;
}
inline mirror::Object* Heap::TryToAllocate(Thread* self, space::AllocSpace* space, size_t alloc_size,
bool grow, size_t* bytes_allocated) {
- if (IsOutOfMemoryOnAllocation(alloc_size)) {
+ if (UNLIKELY(IsOutOfMemoryOnAllocation(alloc_size, grow))) {
return NULL;
}
return space->Alloc(self, alloc_size, bytes_allocated);
@@ -808,10 +820,10 @@
// DlMallocSpace-specific version.
inline mirror::Object* Heap::TryToAllocate(Thread* self, space::DlMallocSpace* space, size_t alloc_size,
bool grow, size_t* bytes_allocated) {
- if (IsOutOfMemoryOnAllocation(alloc_size)) {
+ if (UNLIKELY(IsOutOfMemoryOnAllocation(alloc_size, grow))) {
return NULL;
}
- if (!running_on_valgrind_) {
+ if (LIKELY(!running_on_valgrind_)) {
return space->AllocNonvirtual(self, alloc_size, bytes_allocated);
} else {
return space->Alloc(self, alloc_size, bytes_allocated);
@@ -819,7 +831,8 @@
}
template <class T>
-inline mirror::Object* Heap::Allocate(Thread* self, T* space, size_t alloc_size, size_t* bytes_allocated) {
+inline mirror::Object* Heap::Allocate(Thread* self, T* space, size_t alloc_size,
+ size_t* bytes_allocated) {
// Since allocation can cause a GC which will need to SuspendAll, make sure all allocations are
// done in the runnable state where suspension is expected.
DCHECK_EQ(self->GetState(), kRunnable);
@@ -832,8 +845,8 @@
return AllocateInternalWithGc(self, space, alloc_size, bytes_allocated);
}
-mirror::Object* Heap::AllocateInternalWithGc(Thread* self, space::AllocSpace* space, size_t alloc_size,
- size_t* bytes_allocated) {
+mirror::Object* Heap::AllocateInternalWithGc(Thread* self, space::AllocSpace* space,
+ size_t alloc_size, size_t* bytes_allocated) {
mirror::Object* ptr;
// The allocation failed. If the GC is running, block until it completes, and then retry the
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 72e6e43..cda252e 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -99,20 +99,20 @@
kVerifyAllFast, // Sanity check all heap accesses with quick(er) tests.
kVerifyAll // Sanity check all heap accesses.
};
-const HeapVerificationMode kDesiredHeapVerification = kNoHeapVerification;
+static constexpr HeapVerificationMode kDesiredHeapVerification = kNoHeapVerification;
class Heap {
public:
- static const size_t kDefaultInitialSize = 2 * MB;
- static const size_t kDefaultMaximumSize = 32 * MB;
- static const size_t kDefaultMaxFree = 2 * MB;
- static const size_t kDefaultMinFree = kDefaultMaxFree / 4;
+ static constexpr size_t kDefaultInitialSize = 2 * MB;
+ static constexpr size_t kDefaultMaximumSize = 32 * MB;
+ static constexpr size_t kDefaultMaxFree = 2 * MB;
+ static constexpr size_t kDefaultMinFree = kDefaultMaxFree / 4;
// Default target utilization.
- static const double kDefaultTargetUtilization;
+ static constexpr double kDefaultTargetUtilization = 0.5;
// Used so that we don't overflow the allocation time atomic integer.
- static const size_t kTimeAdjust = 1024;
+ static constexpr size_t kTimeAdjust = 1024;
// Create a heap with the requested sizes. The possible empty
// image_file_names names specify Spaces to load based on
@@ -434,7 +434,7 @@
LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool IsOutOfMemoryOnAllocation(size_t alloc_size);
+ bool IsOutOfMemoryOnAllocation(size_t alloc_size, bool grow);
// Pushes a list of cleared references out to the managed heap.
void EnqueueClearedReferences(mirror::Object** cleared_references);
diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc
index f7fdcfb..39d30bb2 100644
--- a/runtime/thread_pool.cc
+++ b/runtime/thread_pool.cc
@@ -23,7 +23,7 @@
namespace art {
-static const bool kMeasureWaitTime = false;
+static constexpr bool kMeasureWaitTime = false;
ThreadPoolWorker::ThreadPoolWorker(ThreadPool* thread_pool, const std::string& name,
size_t stack_size)
diff --git a/runtime/utils.h b/runtime/utils.h
index bd81114..fcbb992 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -289,12 +289,12 @@
uint64_t ThreadCpuNanoTime();
// Converts the given number of nanoseconds to milliseconds.
-static inline uint64_t NsToMs(uint64_t ns) {
+static constexpr inline uint64_t NsToMs(uint64_t ns) {
return ns / 1000 / 1000;
}
// Converts the given number of milliseconds to nanoseconds
-static inline uint64_t MsToNs(uint64_t ns) {
+static constexpr inline uint64_t MsToNs(uint64_t ns) {
return ns * 1000 * 1000;
}