Tweak native allocation GC triggering thresholds

There is some evidence that collecting more frequently for small Java
heap apps sometimes causes problems. Relative to the original P state,
we should now collect less frequently, if we are either at the beginning
of a Java GC cycle, or the Java heap is large. Otherwise, we should be
similar to the original, modulo accounting changes.

Report a better cause if native allocation ends up waiting for the
GC.

Increase kNotifyNativeInterval on host, since mallinfo() cost appears to
be the cause of a Kotlin benchmark regression on host.

Increase kHugeNativeAllocs enough so that we should normally never block
for a GC we trigger. It looks like 175-alloc-big-bignums still passes on
walleye in spite of this, but we may have to disable that test on
target if it becomes flakey.

Bug: 121052300
Bug: 121039645
Bug: 122099093

Test: Treehugger, art/test/testrunner/testrunner.py --host --64 -t 175-alloc-big-bignums
Change-Id: I6fbd107d4a2519225f628f2c1f96dad034849d12
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 8d19cd0..d699da0 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -3798,7 +3798,7 @@
   if (!Runtime::Current()->IsShuttingDown(self)) {
     // Wait for any GCs currently running to finish.
     if (WaitForGcToComplete(cause, self) == collector::kGcTypeNone) {
-      // If the we can't run the GC type we wanted to run, find the next appropriate one and try
+      // If we can't run the GC type we wanted to run, find the next appropriate one and try
       // that instead. E.g. can't do partial, so do full instead.
       collector::GcType next_gc_type = next_gc_type_;
       // If forcing full and next gc type is sticky, override with a non-sticky type.
@@ -3977,8 +3977,13 @@
 // If weighted java + native memory use exceeds our target by kStopForNativeFactor, and
 // newly allocated memory exceeds kHugeNativeAlloc, we wait for GC to complete to avoid
 // running out of memory.
-static constexpr float kStopForNativeFactor = 2.0;
-static constexpr size_t kHugeNativeAllocs = 200*1024*1024;
+static constexpr float kStopForNativeFactor = 4.0;
+// TODO: Allow this to be tuned. We want this much smaller for some apps, like Calculator.
+// But making it too small can cause jank in apps like launcher that intentionally allocate
+// large amounts of memory in rapid succession. (b/122099093)
+// For now, we punt, and use a value that should be easily large enough to disable this in all
+// questionable setting, but that is clearly too large to be effective for small memory devices.
+static constexpr size_t kHugeNativeAllocs = 1 * GB;
 
 // Return the ratio of the weighted native + java allocated bytes to its target value.
 // A return value > 1.0 means we should collect. Significantly larger values mean we're falling
@@ -3998,8 +4003,9 @@
     size_t new_native_bytes = UnsignedDifference(current_native_bytes, old_native_bytes);
     size_t weighted_native_bytes = new_native_bytes / kNewNativeDiscountFactor
         + old_native_bytes / kOldNativeDiscountFactor;
-    size_t adj_start_bytes = concurrent_start_bytes_
-        + NativeAllocationGcWatermark() / kNewNativeDiscountFactor;
+    size_t add_bytes_allowed = static_cast<size_t>(
+        NativeAllocationGcWatermark() * HeapGrowthMultiplier());
+    size_t adj_start_bytes = concurrent_start_bytes_ + add_bytes_allowed / kNewNativeDiscountFactor;
     return static_cast<float>(GetBytesAllocated() + weighted_native_bytes)
          / static_cast<float>(adj_start_bytes);
   }
@@ -4017,7 +4023,7 @@
         if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
           LOG(INFO) << "Stopping for native allocation, urgency: " << gc_urgency;
         }
-        WaitForGcToComplete(kGcCauseForAlloc, self);
+        WaitForGcToComplete(kGcCauseForNativeAlloc, self);
       }
     } else {
       CollectGarbageInternal(NonStickyGcType(), kGcCauseForNativeAlloc, false);
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index aa09cbe..9e4ec09 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -157,7 +157,12 @@
   // Client should call NotifyNativeAllocation every kNotifyNativeInterval allocations.
   // Should be chosen so that time_to_call_mallinfo / kNotifyNativeInterval is on the same order
   // as object allocation time. time_to_call_mallinfo seems to be on the order of 1 usec.
+#ifdef __ANDROID__
   static constexpr uint32_t kNotifyNativeInterval = 32;
+#else
+  // Some host mallinfo() implementations are slow. And memory is less scarce.
+  static constexpr uint32_t kNotifyNativeInterval = 128;
+#endif
 
   // RegisterNativeAllocation checks immediately whether GC is needed if size exceeds the
   // following. kCheckImmediatelyThreshold * kNotifyNativeInterval should be small enough to
@@ -1136,15 +1141,9 @@
   // collect. We collect when a weighted sum of Java memory plus native memory exceeds
   // the similarly weighted sum of the Java heap size target and this value.
   ALWAYS_INLINE size_t NativeAllocationGcWatermark() const {
-    // It probably makes most sense to use a constant multiple of target_footprint_ .
-    // This is a good indication of the live data size, together with the
-    // intended space-time trade-off, as expressed by SetTargetHeapUtilization.
-    // For a fixed target utilization, the amount of GC effort per native
-    // allocated byte remains roughly constant as the Java heap size changes.
-    // But we previously triggered on max_free_ native allocation which is often much
-    // smaller. To avoid unexpected growth, we partially keep that limit in place for now.
-    // TODO: Consider HeapGrowthMultiplier(). Maybe.
-    return std::min(target_footprint_.load(std::memory_order_relaxed), 2 * max_free_);
+    // We keep the traditional limit of max_free_ in place for small heaps,
+    // but allow it to be adjusted upward for large heaps to limit GC overhead.
+    return target_footprint_.load(std::memory_order_relaxed) / 8 + max_free_;
   }
 
   ALWAYS_INLINE void IncrementNumberOfBytesFreedRevoke(size_t freed_bytes_revoke);