Compiler filter update

Tweak of the compiler filter to give better results for applications
which are not dominated by tight arithmetic loops. Deleted
the "DeferCompilation" setting - it didn't differ enough from the
"Space" setting.  Added "Everything" setting to support forced
compilation (for images and testing).  Previously used "Speed"
for that purpose, but in the speed setting there are some things we
don't want to compile.

Change-Id: Ia53b14f2044fc9738c1a4c1318f8204f2c25abe3
diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc
index 8321ff6..d7a4136 100644
--- a/compiler/dex/mir_analysis.cc
+++ b/compiler/dex/mir_analysis.cc
@@ -151,10 +151,10 @@
   AN_BRANCH,
 
   // 2B PACKED_SWITCH vAA, +BBBBBBBB
-  AN_NONE,
+  AN_SWITCH,
 
   // 2C SPARSE_SWITCH vAA, +BBBBBBBB
-  AN_NONE,
+  AN_SWITCH,
 
   // 2D CMPL_FLOAT vAA, vBB, vCC
   AN_MATH | AN_FP | AN_SINGLE,
@@ -841,6 +841,7 @@
   int branch_ops;
   int heavyweight_ops;
   bool has_computational_loop;
+  bool has_switch;
   float math_ratio;
   float fp_ratio;
   float array_ratio;
@@ -914,6 +915,9 @@
       if ((flags & AN_HEAVYWEIGHT) != 0) {
         stats->heavyweight_ops += loop_scale_factor;
       }
+      if ((flags & AN_SWITCH) != 0) {
+        stats->has_switch = true;
+      }
     }
     if (tbb == ending_bb) {
       done = true;
@@ -939,7 +943,7 @@
               << stats->math_ratio << ", fp:"
               << stats->fp_ratio << ", br:"
               << stats->branch_ratio << ", hw:"
-              << stats-> heavyweight_ratio << ", arr:"
+              << stats->heavyweight_ratio << ", arr:"
               << stats->array_ratio << ", hot:"
               << stats->has_computational_loop << ", "
               << PrettyMethod(cu_->method_idx, *cu_->dex_file);
@@ -971,8 +975,14 @@
     return false;
   }
 
-  // If high proportion of expensive operations, skip.
-  if (stats->heavyweight_ratio > 0.3) {
+  // Switch operations benefit greatly from compilation, so go ahead and spend the cycles.
+  if (stats->has_switch) {
+    return false;
+  }
+
+  // If significant in size and high proportion of expensive operations, skip.
+  if ((GetNumDalvikInsns() > Runtime::Current()->GetSmallMethodThreshold()) &&
+      (stats->heavyweight_ratio > 0.3)) {
     return true;
   }
 
@@ -984,8 +994,7 @@
   * Ultimate goal is to drive with profile data.
   */
 bool MIRGraph::SkipCompilation(Runtime::CompilerFilter compiler_filter) {
-  if (compiler_filter == Runtime::kSpeed) {
-    // If going for speed, compile everything.
+  if (compiler_filter == Runtime::kEverything) {
     return false;
   }
 
@@ -994,10 +1003,38 @@
     return true;
   }
 
-  // Filter 1: Skip huge methods (generally machine-generated initialization methods).
+  // Set up compilation cutoffs based on current filter mode.
+  size_t small_cutoff = 0;
+  size_t default_cutoff = 0;
+  switch (compiler_filter) {
+    case Runtime::kBalanced:
+      small_cutoff = Runtime::Current()->GetSmallMethodThreshold();
+      default_cutoff = Runtime::Current()->GetLargeMethodThreshold();
+      break;
+    case Runtime::kSpace:
+      small_cutoff = Runtime::Current()->GetTinyMethodThreshold();
+      default_cutoff = Runtime::Current()->GetSmallMethodThreshold();
+      break;
+    case Runtime::kSpeed:
+      small_cutoff = Runtime::Current()->GetHugeMethodThreshold();
+      default_cutoff = Runtime::Current()->GetHugeMethodThreshold();
+      break;
+    default:
+      LOG(FATAL) << "Unexpected compiler_filter_: " << compiler_filter;
+  }
+
+  // If size < cutoff, assume we'll compile - but allow removal.
+  bool skip_compilation = (GetNumDalvikInsns() >= default_cutoff);
+
+  /*
+   * Filter 1: Huge methods are likely to be machine generated, but some aren't.
+   * If huge, assume we won't compile, but allow futher analysis to turn it back on.
+   */
   if (GetNumDalvikInsns() > Runtime::Current()->GetHugeMethodThreshold()) {
-    // Ain't nobody got time for that.
-    return true;
+    skip_compilation = true;
+  } else if (compiler_filter == Runtime::kSpeed) {
+    // If not huge, compile.
+    return false;
   }
 
   // Filter 2: Skip class initializers.
@@ -1010,28 +1047,7 @@
     return false;
   }
 
-  /* In balanced mode, we generally assume that we'll be compiling, and then detect
-   * methods that won't benefit and remove them.  In space or deferred mode, we do the
-   * opposite: assume no compilation and then add back presumed hot methods.
-   */
-  bool skip_compilation = (compiler_filter == Runtime::kBalanced) ? false : true;
-
-
-  // Filter 4: go ahead and compile the small ones.
-  size_t small_cutoff = 0;
-  switch (compiler_filter) {
-    case Runtime::kBalanced:
-      small_cutoff = Runtime::Current()->GetSmallMethodThreshold();
-      break;
-    case Runtime::kSpace:
-      small_cutoff = Runtime::Current()->GetTinyMethodThreshold();
-      break;
-    case Runtime::kDeferCompilation:
-      small_cutoff = 0;
-      break;
-    default:
-      LOG(FATAL) << "Unexpected compiler_filter_: " << compiler_filter;
-  }
+  // Filter 4: if small, just compile.
   if (GetNumDalvikInsns() < small_cutoff) {
     return false;
   }
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index af1ae44..c02deab 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -38,7 +38,8 @@
   kArrayOp,
   kHeavyweightOp,
   kSimpleConstOp,
-  kMoveOp
+  kMoveOp,
+  kSwitch
 };
 
 #define AN_NONE (1 << kUninterestingOp)
@@ -55,6 +56,7 @@
 #define AN_HEAVYWEIGHT (1 << kHeavyweightOp)
 #define AN_SIMPLECONST (1 << kSimpleConstOp)
 #define AN_MOVE (1 << kMoveOp)
+#define AN_SWITCH (1 << kSwitch)
 #define AN_COMPUTATIONAL (AN_MATH | AN_ARRAYOP | AN_MOVE | AN_SIMPLECONST)
 
 enum DataFlowAttributePos {
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 511788b..1d7f68d 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -867,9 +867,10 @@
   // give it away now and then switch to a more managable ScopedObjectAccess.
   Thread::Current()->TransitionFromRunnableToSuspended(kNative);
   // If we're doing the image, override the compiler filter to force full compilation. Must be
-  // done ahead of WellKnownClasses::Init that causes verification.
-  if (image && Runtime::Current()->GetCompilerFilter() == Runtime::kInterpretOnly) {
-    Runtime::Current()->SetCompilerFilter(Runtime::kSpeed);
+  // done ahead of WellKnownClasses::Init that causes verification.  Note: doesn't force
+  // compilation of class initializers.
+  if (image) {
+    Runtime::Current()->SetCompilerFilter(Runtime::kEverything);
   }
   // Whilst we're in native take the opportunity to initialize well known classes.
   WellKnownClasses::Init(Thread::Current()->GetJniEnv());
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 0110b36..69f004d 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -575,9 +575,6 @@
     case Runtime::kInterpretOnly:
       oat_compiler_filter_string += "interpret-only";
       break;
-    case Runtime::kDeferCompilation:
-      oat_compiler_filter_string += "defer-compilation";
-      break;
     case Runtime::kSpace:
       oat_compiler_filter_string += "space";
       break;
@@ -587,6 +584,9 @@
     case Runtime::kSpeed:
       oat_compiler_filter_string += "speed";
       break;
+    case Runtime::kEverything:
+      oat_compiler_filter_string += "everything";
+      break;
     default:
       LOG(FATAL) << "Unexpected case.";
   }
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index c4a9503..65bd495 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -583,14 +583,14 @@
       Trace::SetDefaultClockSource(kProfilerClockSourceDual);
     } else if (option == "-compiler-filter:interpret-only") {
       parsed->compiler_filter_ = kInterpretOnly;
-    } else if (option == "-compiler-filter:defer-compilation") {
-      parsed->compiler_filter_ = kDeferCompilation;
     } else if (option == "-compiler-filter:space") {
       parsed->compiler_filter_ = kSpace;
     } else if (option == "-compiler-filter:balanced") {
       parsed->compiler_filter_ = kBalanced;
     } else if (option == "-compiler-filter:speed") {
       parsed->compiler_filter_ = kSpeed;
+    } else if (option == "-compiler-filter:everything") {
+      parsed->compiler_filter_ = kEverything;
     } else if (option == "-sea_ir") {
       parsed->sea_ir_mode_ = true;
     } else if (StartsWith(option, "-huge-method-max:")) {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 8aba762..be29a86 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -65,10 +65,10 @@
 
   enum CompilerFilter {
     kInterpretOnly,       // Compile nothing.
-    kDeferCompilation,    // Temporary minimal compilation, will redo during device idle time.
     kSpace,               // Maximize space savings.
     kBalanced,            // Try to get the best performance return on compilation investment.
-    kSpeed                // Compile all methods.
+    kSpeed,               // Maximize runtime performance.
+    kEverything           // Force compilation (Note: excludes compilaton of class initializers).
   };
 
   // Guide heuristics to determine whether to compile method if profile data not available.
@@ -77,10 +77,10 @@
 #else
   static const CompilerFilter kDefaultCompilerFilter = kSpeed;
 #endif
-  static const size_t kDefaultHugeMethodThreshold = 6000;
-  static const size_t kDefaultLargeMethodThreshold = 1000;
-  static const size_t kDefaultSmallMethodThreshold = 200;
-  static const size_t kDefaultTinyMethodThreshold = 10;
+  static const size_t kDefaultHugeMethodThreshold = 10000;
+  static const size_t kDefaultLargeMethodThreshold = 600;
+  static const size_t kDefaultSmallMethodThreshold = 60;
+  static const size_t kDefaultTinyMethodThreshold = 20;
   static const size_t kDefaultNumDexMethodsThreshold = 900;
 
   class ParsedOptions {