Fix concurrent GC ergonomics
Fixed a race with the gc_request_pending_ boolean which would cause
two concurrent GCs to start in a row in most cases. This broke sticky
CMS ergonomics since the second GC was a sticky CMS which started way
too early resulting in low throughput. Since the throughput was low,
it switch to partial / full for the next iteration.
The race happened as follows, allocating thread would request
concurrent GC which woke up the daemon thread. The daemon thread
cleared the gc_request_pending_ boolean, but before we set the
concurrent_start_bytes_ to max in to prevent more request, the
allocating thread would call RequestConcurrentGC again. This caused
the next WaitForConcurrentGCRequest to return right away and a
concurrent GC to occur earlier than necessary.
Changed the allocation rate ergonomics to use allocation rate
during the GC instead of allocation rate inbetween GCs, this is
better since the allocation rate may become slower if the GC steals
mutator time, resulting in concurrent GCs starting a bit earlier
than they need to.
Fixed a bug in GrowForUtilization where we didn't use the adjusted
max_free when we shrank down the heap, this caused the sticky CMS to
occasionally shrink the heap more than necessary.
EvaluateAndApplyChanges:
Before: ~12.6s GC time
After: ~7.75s GC time
Change-Id: I354bc825b3c44ccfbfe867af0d437b17fe1fe022
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 529af95..cf94eb6 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -755,8 +755,10 @@
// Given the current contents of the alloc space, increase the allowed heap footprint to match
// the target utilization ratio. This should only be called immediately after a full garbage
- // collection.
- void GrowForUtilization(collector::GarbageCollector* collector_ran);
+ // collection. bytes_allocated_before_gc is used to measure bytes / second for the period which
+ // the GC was run.
+ void GrowForUtilization(collector::GarbageCollector* collector_ran,
+ uint64_t bytes_allocated_before_gc = 0);
size_t GetPercentFree();
@@ -881,6 +883,7 @@
Mutex* gc_request_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
std::unique_ptr<ConditionVariable> gc_request_cond_ GUARDED_BY(gc_request_lock_);
bool gc_request_pending_ GUARDED_BY(gc_request_lock_);
+ bool conc_gc_running_ GUARDED_BY(gc_request_lock_);
// Reference processor;
ReferenceProcessor reference_processor_;
@@ -971,12 +974,6 @@
// Parallel GC data structures.
std::unique_ptr<ThreadPool> thread_pool_;
- // The nanosecond time at which the last GC ended.
- uint64_t last_gc_time_ns_;
-
- // How many bytes were allocated at the end of the last GC.
- uint64_t last_gc_size_;
-
// Estimated allocation rate (bytes / second). Computed between the time of the last GC cycle
// and the start of the current one.
uint64_t allocation_rate_;