Inliner heuristic: prevent inlining based on code item size.

It's impossible to know the the exact number of `HInstruction`s that
will be generated for an inlined method, but there is some loose
correlation between this number and code item size. Namely, the number
of `HInstruction`s is on average equal to 2/3 of code item size (this
was determined by compiling top 100 apps with an instrumented version
of dex2oat that printed the two numbers).

This heuristic is a bit stricter: it prevents methods from inlining if
3/4 of their code item size exceeds inlining budget. The decision to
use 3/4 instead of 2/3 is based on experimental run on top 100 apps
with two metrics (computed based on inliner stats as reported by
--dump-stats):

A. the number of previously successful inline attempts that got
   cancelled due to heuristic, measured as (X - Y)/X, where X, Y is
   sum of the following inliner stats without and with heuristic:
     - InlinedInvoke
     - InlinedPolymorphicCall
     - InlinedLastInvokeVirtualOrInterface

B. the number of previously failed inline attempts that got cancelled
   due to heuristic (preventing waste of resources and compile time),
   measured as (X - Y)/X, where X, Y is sum of the following inliner
   stats without and with heuristic:
     - NotInlinedInstructionBudget
     - NotInlinedAlwaysThrows
     - NotInlinedInfiniteLoop
     - NotInlinedIrreducibleLoopCaller
     - NotInlinedIrreducibleLoopCallee
     - NotInlinedLoopWithoutExit
     - NotInlinedStackMaps
     - NotInlinedUnresolvedEntrypoint
     - NotInlinedBss
     - NotInlinedCannotBuild

Metrics for factors 1/1 > 4/5 > 3/4 (chosen) > 5/7 > 2/3 > 1/2:

With heuristic factor 1/1:
- metric A is at max 3.3% for any given app and 0.239% on average
- metric B is at max 97.6% and 42.7% on average

With heuristic factor 4/5:
- metric A is at max 3.3% for any given app and 0.131% on average
- metric B is at max 97.6% and 42.2% on average

With heuristic factor 3/4 (the chosen value):
- metric A is at max 0.5% for any given app and 0.054% on average
- metric B is at max 97.3% and 41.3% on average

With heuristic factor 5/7:
- metric A is at max 0.5% for any given app and 0.054% on average
- metric B is at max 97.3% and 41.1% on average

With heuristic factor 2/3:
- metric A is at max 0.5% for any given app and 0.053% on average
- metric B is at max 96.9% and 40.9% on average

With heuristic factor 1/2:
- metric A is at max 0.2% for any given app and 0.007% on average
- metric B is at max 77.7% and 32.8% on average

Factor 3/4 was chosen as it is the highest factor that still has a low
percent of prevented-successful, but high percent of prevented-failed
inline attempts.

Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 393108375
Flag: EXEMPT Behavioural changes (no significant impact)

Change-Id: I9adc6c21fc23220046fdba33ae47a7e991acc666
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index f0f0a73..cda8d49 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1600,6 +1600,21 @@
     return false;
   }
 
+  // The heuristic below tries to prevent inline attempts where the graph is built but discarded
+  // later due to its size being over the budget. A rough estimate of method size (`HInstruction`
+  // count) is 2/3 of code item size (it is not always true - a large code item may result in just
+  // a few `HInstruction`s, but experiments show such methods are relatively rare). We use factor
+  // 3/4 rather than 2/3 as the experiments show that it results in approximately the same number
+  // of prevented-successful inline attempts, but higher prevented-failed attempts.
+  size_t estimated_size = (accessor.InsnsSizeInCodeUnits() * 3u) / 4u;
+  if (estimated_size > inlining_budget_) {
+    LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedCodeItem)
+        << "Method " << method->PrettyMethod()
+        << " is not inlined because its estimated size based on code item exceeds inlining budget: "
+        << estimated_size << " > " << inlining_budget_;
+    return false;
+  }
+
   return true;
 }