Compilation filter
This CL introduces a static compilation filter mechanism intended
to allow us to reduce compilation time and space requirements until
we have a profiling mechanism in place.
It supports 5 modes of filtering:
o interpret-only (compile nothing)
o deferred-compilation (compile only those methods believe to be
compute-intensive)
o space (optimized for space)
o balanced (best return on space investment)
o speed (compile everything)
A future CL will allow the default filtering mode to be set
via system property. For now, you can pass it in via command
line as follows:
dalvikvm -compiler-filter:[interpret-only|defer-compilation|
space|balanced|speed]
or dex2oat --runtime-arg -compiler-filter:[one of the above modes]
Creating a file named art/SMALL_ART will force the filter
default to interpret-only. Later on we'll move this capability
to a persistent system property.
or modify kDefaultCompilerFilter in runtime.h
It also changes the compiler driver to allow the compilers to
decline to compile a method by return NULL.
Change-Id: Ic73411818f8bb845a4a19a05b0395c50902c534f
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 84f186d..6052993 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -609,6 +609,28 @@
oat_location_option_string += oat_cache_filename;
const char* oat_location_option = oat_location_option_string.c_str();
+ std::string oat_compiler_filter_string("-compiler-filter:");
+ switch (Runtime::Current()->GetCompilerFilter()) {
+ 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;
+ case Runtime::kBalanced:
+ oat_compiler_filter_string += "balanced";
+ break;
+ case Runtime::kSpeed:
+ oat_compiler_filter_string += "speed";
+ break;
+ default:
+ LOG(FATAL) << "Unexpected case.";
+ }
+ const char* oat_compiler_filter_option = oat_compiler_filter_string.c_str();
+
// fork and exec dex2oat
pid_t pid = fork();
if (pid == 0) {
@@ -622,6 +644,7 @@
<< " --runtime-arg -Xmx64m"
<< " --runtime-arg -classpath"
<< " --runtime-arg " << class_path
+ << " --runtime-arg " << oat_compiler_filter_option
#if !defined(ART_TARGET)
<< " --host"
#endif
@@ -635,6 +658,7 @@
"--runtime-arg", "-Xmx64m",
"--runtime-arg", "-classpath",
"--runtime-arg", class_path,
+ "--runtime-arg", oat_compiler_filter_option,
#if !defined(ART_TARGET)
"--host",
#endif
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 5298181..70d8816 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -355,9 +355,12 @@
parsed->hook_exit_ = exit;
parsed->hook_abort_ = NULL; // We don't call abort(3) by default; see Runtime::Abort.
- parsed->small_mode_ = false;
- parsed->small_mode_method_threshold_ = Runtime::kDefaultSmallModeMethodThreshold;
- parsed->small_mode_method_dex_size_limit_ = Runtime::kDefaultSmallModeMethodDexSizeLimit;
+ parsed->compiler_filter_ = Runtime::kDefaultCompilerFilter;
+ parsed->huge_method_threshold_ = Runtime::kDefaultHugeMethodThreshold;
+ parsed->large_method_threshold_ = Runtime::kDefaultLargeMethodThreshold;
+ parsed->small_method_threshold_ = Runtime::kDefaultSmallMethodThreshold;
+ parsed->tiny_method_threshold_ = Runtime::kDefaultTinyMethodThreshold;
+ parsed->num_dex_methods_threshold_ = Runtime::kDefaultNumDexMethodsThreshold;
parsed->sea_ir_mode_ = false;
// gLogVerbosity.class_linker = true; // TODO: don't check this in!
@@ -572,14 +575,28 @@
Trace::SetDefaultClockSource(kProfilerClockSourceWall);
} else if (option == "-Xprofile:dualclock") {
Trace::SetDefaultClockSource(kProfilerClockSourceDual);
- } else if (option == "-small") {
- parsed->small_mode_ = true;
+ } 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 == "-sea_ir") {
parsed->sea_ir_mode_ = true;
- } else if (StartsWith(option, "-small-mode-methods-max:")) {
- parsed->small_mode_method_threshold_ = ParseIntegerOrDie(option);
- } else if (StartsWith(option, "-small-mode-methods-size-max:")) {
- parsed->small_mode_method_dex_size_limit_ = ParseIntegerOrDie(option);
+ } else if (StartsWith(option, "-huge-method-max:")) {
+ parsed->huge_method_threshold_ = ParseIntegerOrDie(option);
+ } else if (StartsWith(option, "-large-method-max:")) {
+ parsed->large_method_threshold_ = ParseIntegerOrDie(option);
+ } else if (StartsWith(option, "-small-method-max:")) {
+ parsed->small_method_threshold_ = ParseIntegerOrDie(option);
+ } else if (StartsWith(option, "-tiny-method-max:")) {
+ parsed->tiny_method_threshold_ = ParseIntegerOrDie(option);
+ } else if (StartsWith(option, "-num-dex-methods-max:")) {
+ parsed->num_dex_methods_threshold_ = ParseIntegerOrDie(option);
} else {
if (!ignore_unrecognized) {
// TODO: print usage via vfprintf
@@ -809,9 +826,12 @@
is_zygote_ = options->is_zygote_;
is_concurrent_gc_enabled_ = options->is_concurrent_gc_enabled_;
- small_mode_ = options->small_mode_;
- small_mode_method_threshold_ = options->small_mode_method_threshold_;
- small_mode_method_dex_size_limit_ = options->small_mode_method_dex_size_limit_;
+ compiler_filter_ = options->compiler_filter_;
+ huge_method_threshold_ = options->huge_method_threshold_;
+ large_method_threshold_ = options->large_method_threshold_;
+ small_method_threshold_ = options->small_method_threshold_;
+ tiny_method_threshold_ = options->tiny_method_threshold_;
+ num_dex_methods_threshold_ = options->num_dex_methods_threshold_;
sea_ir_mode_ = options->sea_ir_mode_;
vfprintf_ = options->hook_vfprintf_;
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 47fff29..d67265a 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -63,15 +63,25 @@
public:
typedef std::vector<std::pair<std::string, const void*> > Options;
- // In small mode, apps with fewer than this number of methods will be compiled
- // anyways.
- // TODO: come up with a reasonable default.
- static const size_t kDefaultSmallModeMethodThreshold = 0;
+ 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.
+ };
- // In small mode, methods smaller than this dex op count limit will get compiled
- // anyways.
- // TODO: come up with a reasonable default.
- static const size_t kDefaultSmallModeMethodDexSizeLimit = 300;
+ // Guide heuristics to determine whether to compile method if profile data not available.
+#if ART_SMALL_MODE
+ static const CompilerFilter kDefaultCompilerFilter = kInterpretOnly;
+#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 kDefaultNumDexMethodsThreshold = 900;
class ParsedOptions {
public:
@@ -108,11 +118,12 @@
void (*hook_exit_)(jint status);
void (*hook_abort_)();
std::vector<std::string> properties_;
- bool small_mode_;
-
- size_t small_mode_method_threshold_;
- size_t small_mode_method_dex_size_limit_;
-
+ CompilerFilter compiler_filter_;
+ size_t huge_method_threshold_;
+ size_t large_method_threshold_;
+ size_t small_method_threshold_;
+ size_t tiny_method_threshold_;
+ size_t num_dex_methods_threshold_;
bool sea_ir_mode_;
private:
@@ -145,21 +156,32 @@
sea_ir_mode_ = sea_ir_mode;
}
- bool IsSmallMode() const {
- return small_mode_;
+ CompilerFilter GetCompilerFilter() const {
+ return compiler_filter_;
}
-
- void SetSmallMode(bool small_mode) {
- small_mode_ = small_mode;
+ void SetCompilerFilter(CompilerFilter compiler_filter) {
+ compiler_filter_ = compiler_filter;
}
- size_t GetSmallModeMethodThreshold() const {
- return small_mode_method_threshold_;
+ size_t GetHugeMethodThreshold() const {
+ return huge_method_threshold_;
}
- size_t GetSmallModeMethodDexSizeLimit() const {
- return small_mode_method_dex_size_limit_;
+ size_t GetLargeMethodThreshold() const {
+ return large_method_threshold_;
+ }
+
+ size_t GetSmallMethodThreshold() const {
+ return small_method_threshold_;
+ }
+
+ size_t GetTinyMethodThreshold() const {
+ return tiny_method_threshold_;
+ }
+
+ size_t GetNumDexMethodsThreshold() const {
+ return num_dex_methods_threshold_;
}
const std::string& GetHostPrefix() const {
@@ -384,9 +406,12 @@
bool is_zygote_;
bool is_concurrent_gc_enabled_;
- bool small_mode_;
- size_t small_mode_method_threshold_;
- size_t small_mode_method_dex_size_limit_;
+ CompilerFilter compiler_filter_;
+ size_t huge_method_threshold_;
+ size_t large_method_threshold_;
+ size_t small_method_threshold_;
+ size_t tiny_method_threshold_;
+ size_t num_dex_methods_threshold_;
bool sea_ir_mode_;
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 9f0d911..f1de565 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -4180,16 +4180,7 @@
if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
return false;
}
-
- const Runtime* runtime = Runtime::Current();
- if (runtime->IsSmallMode() && runtime->UseCompileTimeClassPath()) {
- // In Small mode, we only compile small methods.
- const uint32_t code_size = code_item->insns_size_in_code_units_;
- return (code_size < runtime->GetSmallModeMethodDexSizeLimit());
- } else {
- // In normal mode, we compile everything.
- return true;
- }
+ return (Runtime::Current()->GetCompilerFilter() != Runtime::kInterpretOnly);
}
ReaderWriterMutex* MethodVerifier::dex_gc_maps_lock_ = NULL;