diff options
-rw-r--r-- | compiler/dex/compiler_ir.cc | 1 | ||||
-rw-r--r-- | compiler/dex/compiler_ir.h | 10 | ||||
-rw-r--r-- | compiler/dex/pass_driver.h | 14 | ||||
-rw-r--r-- | compiler/dex/pass_driver_me.h | 138 | ||||
-rw-r--r-- | compiler/dex/pass_driver_me_opts.cc | 4 | ||||
-rw-r--r-- | compiler/dex/pass_driver_me_post_opt.cc | 4 | ||||
-rw-r--r-- | compiler/dex/pass_me.h | 67 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 19 |
8 files changed, 245 insertions, 12 deletions
diff --git a/compiler/dex/compiler_ir.cc b/compiler/dex/compiler_ir.cc index 7a5b114c8d..e1d489a051 100644 --- a/compiler/dex/compiler_ir.cc +++ b/compiler/dex/compiler_ir.cc @@ -54,6 +54,7 @@ CompilationUnit::CompilationUnit(ArenaPool* pool) } CompilationUnit::~CompilationUnit() { + overridden_pass_options.clear(); } void CompilationUnit::StartTimingSplit(const char* label) { diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h index 67bf88aef8..b20840adbc 100644 --- a/compiler/dex/compiler_ir.h +++ b/compiler/dex/compiler_ir.h @@ -17,6 +17,7 @@ #ifndef ART_COMPILER_DEX_COMPILER_IR_H_ #define ART_COMPILER_DEX_COMPILER_IR_H_ +#include <string> #include <vector> #include "compiler_enums.h" @@ -91,6 +92,15 @@ struct CompilationUnit { std::unique_ptr<Backend> cg; // Target-specific codegen. TimingLogger timings; bool print_pass; // Do we want to print a pass or not? + + /** + * @brief Holds pass options for current pass being applied to compilation unit. + * @details This is updated for every pass to contain the overridden pass options + * that were specified by user. The pass itself will check this to see if the + * default settings have been changed. The key is simply the option string without + * the pass name. + */ + SafeMap<const std::string, int> overridden_pass_options; }; } // namespace art diff --git a/compiler/dex/pass_driver.h b/compiler/dex/pass_driver.h index bd8f53cd5a..8a3eae1486 100644 --- a/compiler/dex/pass_driver.h +++ b/compiler/dex/pass_driver.h @@ -161,6 +161,17 @@ class PassDriver { print_pass_list_ = list; } + /** + * @brief Used to set a string that contains the overridden pass options. + * @details An overridden pass option means that the pass uses this option + * instead of using its default option. + * @param s The string passed by user with overridden options. The string is in format + * Pass1Name:Pass1Option:Pass1Setting,Pass2Name:Pass2Option::Pass2Setting + */ + static void SetOverriddenPassOptions(const std::string& s) { + overridden_pass_options_list_ = s; + } + void SetDefaultPasses() { pass_list_ = PassDriver<PassDriverType>::g_default_pass_list; } @@ -206,6 +217,9 @@ class PassDriver { /** @brief What are the passes we want to be dumping the CFG? */ static std::string dump_pass_list_; + + /** @brief String of all options that should be overridden for selected passes */ + static std::string overridden_pass_options_list_; }; } // namespace art diff --git a/compiler/dex/pass_driver_me.h b/compiler/dex/pass_driver_me.h index 133593ceb9..537ceb665e 100644 --- a/compiler/dex/pass_driver_me.h +++ b/compiler/dex/pass_driver_me.h @@ -17,6 +17,8 @@ #ifndef ART_COMPILER_DEX_PASS_DRIVER_ME_H_ #define ART_COMPILER_DEX_PASS_DRIVER_ME_H_ +#include <cstdlib> +#include <cstring> #include "bb_optimizations.h" #include "dataflow_iterator.h" #include "dataflow_iterator-inl.h" @@ -94,19 +96,27 @@ class PassDriverME: public PassDriver<PassDriverType> { c_unit->NewTimingSplit(pass->GetName()); } - // Check the pass gate first. - bool should_apply_pass = pass->Gate(&pass_me_data_holder_); - if (should_apply_pass) { - bool old_print_pass = c_unit->print_pass; - - c_unit->print_pass = PassDriver<PassDriverType>::default_print_passes_; - - const char* print_pass_list = PassDriver<PassDriverType>::print_pass_list_.c_str(); + // First, work on determining pass verbosity. + bool old_print_pass = c_unit->print_pass; + c_unit->print_pass = PassDriver<PassDriverType>::default_print_passes_; + const char* print_pass_list = PassDriver<PassDriverType>::print_pass_list_.c_str(); + if (print_pass_list != nullptr && strstr(print_pass_list, pass->GetName()) != nullptr) { + c_unit->print_pass = true; + } - if (print_pass_list != nullptr && strstr(print_pass_list, pass->GetName()) != nullptr) { - c_unit->print_pass = true; + // Next, check if there are any overridden settings for the pass that change default configuration. + c_unit->overridden_pass_options.clear(); + FillOverriddenPassSettings(pass->GetName(), c_unit->overridden_pass_options); + if (c_unit->print_pass) { + for (auto setting_it : c_unit->overridden_pass_options) { + LOG(INFO) << "Overridden option \"" << setting_it.first << ":" + << setting_it.second << "\" for pass \"" << pass->GetName() << "\""; } + } + // Check the pass gate first. + bool should_apply_pass = pass->Gate(&pass_me_data_holder_); + if (should_apply_pass) { // Applying the pass: first start, doWork, and end calls. this->ApplyPass(&pass_me_data_holder_, pass); @@ -137,10 +147,11 @@ class PassDriverME: public PassDriver<PassDriverType> { } } } - - c_unit->print_pass = old_print_pass; } + // Before wrapping up with this pass, restore old pass verbosity flag. + c_unit->print_pass = old_print_pass; + // If the pass gate passed, we can declare success. return should_apply_pass; } @@ -149,6 +160,18 @@ class PassDriverME: public PassDriver<PassDriverType> { return dump_cfg_folder_; } + static void PrintPassOptions() { + for (auto pass : PassDriver<PassDriverType>::g_default_pass_list) { + const PassME* me_pass = down_cast<const PassME*>(pass); + if (me_pass->HasOptions()) { + LOG(INFO) << "Pass options for \"" << me_pass->GetName() << "\" are:"; + SafeMap<const std::string, int> overridden_settings; + FillOverriddenPassSettings(me_pass->GetName(), overridden_settings); + me_pass->PrintPassOptions(overridden_settings); + } + } + } + protected: /** @brief The data holder that contains data needed for the PassDriverME. */ PassMEDataHolder pass_me_data_holder_; @@ -175,6 +198,97 @@ class PassDriverME: public PassDriver<PassDriverType> { Iterator iterator(c_unit->mir_graph.get()); DoWalkBasicBlocks(data, pass, &iterator); } + + /** + * @brief Fills the settings_to_fill by finding all of the applicable options in the overridden_pass_options_list_. + * @param pass_name The pass name for which to fill settings. + * @param settings_to_fill Fills the options to contain the mapping of name of option to the new configuration. + */ + static void FillOverriddenPassSettings(const char* pass_name, SafeMap<const std::string, int>& settings_to_fill) { + const std::string& settings = PassDriver<PassDriverType>::overridden_pass_options_list_; + const size_t settings_len = settings.size(); + + // Before anything, check if we care about anything right now. + if (settings_len == 0) { + return; + } + + const size_t pass_name_len = strlen(pass_name); + const size_t min_setting_size = 4; // 2 delimiters, 1 setting name, 1 setting + size_t search_pos = 0; + + // If there is no room for pass options, exit early. + if (settings_len < pass_name_len + min_setting_size) { + return; + } + + do { + search_pos = settings.find(pass_name, search_pos); + + // Check if we found this pass name in rest of string. + if (search_pos == std::string::npos) { + // No more settings for this pass. + break; + } + + // The string contains the pass name. Now check that there is + // room for the settings: at least one char for setting name, + // two chars for two delimiter, and at least one char for setting. + if (search_pos + pass_name_len + min_setting_size >= settings_len) { + // No more settings for this pass. + break; + } + + // Update the current search position to not include the pass name. + search_pos += pass_name_len; + + // The format must be "PassName:SettingName:#" where # is the setting. + // Thus look for the first ":" which must exist. + if (settings[search_pos] != ':') { + // Missing delimiter right after pass name. + continue; + } else { + search_pos += 1; + } + + // Now look for the actual setting by finding the next ":" delimiter. + const size_t setting_name_pos = search_pos; + size_t setting_pos = settings.find(':', setting_name_pos); + + if (setting_pos == std::string::npos) { + // Missing a delimiter that would capture where setting starts. + continue; + } else if (setting_pos == setting_name_pos) { + // Missing setting thus did not move from setting name + continue; + } else { + // Skip the delimiter. + setting_pos += 1; + } + + // Look for the terminating delimiter which must be a comma. + size_t next_configuration_separator = settings.find(',', setting_pos); + if (next_configuration_separator == std::string::npos) { + next_configuration_separator = settings_len; + } + + // Prevent end of string errors. + if (next_configuration_separator == setting_pos) { + continue; + } + + // Get the actual setting itself. Strtol is being used to convert because it is + // exception safe. If the input is not sane, it will set a setting of 0. + std::string setting_string = settings.substr(setting_pos, next_configuration_separator - setting_pos); + int setting = std::strtol(setting_string.c_str(), 0, 0); + + std::string setting_name = settings.substr(setting_name_pos, setting_pos - setting_name_pos - 1); + + settings_to_fill.Put(setting_name, setting); + + search_pos = next_configuration_separator; + } while (true); + } }; } // namespace art #endif // ART_COMPILER_DEX_PASS_DRIVER_ME_H_ diff --git a/compiler/dex/pass_driver_me_opts.cc b/compiler/dex/pass_driver_me_opts.cc index c72a4a667e..aea7543f8a 100644 --- a/compiler/dex/pass_driver_me_opts.cc +++ b/compiler/dex/pass_driver_me_opts.cc @@ -69,6 +69,10 @@ std::string PassDriver<PassDriverMEOpts>::print_pass_list_ = std::string(); template<> bool PassDriver<PassDriverMEOpts>::default_print_passes_ = false; +// By default, there are no overridden pass settings. +template<> +std::string PassDriver<PassDriverMEOpts>::overridden_pass_options_list_ = std::string(); + void PassDriverMEOpts::ApplyPass(PassDataHolder* data, const Pass* pass) { // First call the base class' version. PassDriver::ApplyPass(data, pass); diff --git a/compiler/dex/pass_driver_me_post_opt.cc b/compiler/dex/pass_driver_me_post_opt.cc index 14108af632..4acab6c6e5 100644 --- a/compiler/dex/pass_driver_me_post_opt.cc +++ b/compiler/dex/pass_driver_me_post_opt.cc @@ -73,4 +73,8 @@ std::string PassDriver<PassDriverMEPostOpt>::print_pass_list_ = std::string(); template<> bool PassDriver<PassDriverMEPostOpt>::default_print_passes_ = false; +// By default, there are no overridden pass settings. +template<> +std::string PassDriver<PassDriverMEPostOpt>::overridden_pass_options_list_ = std::string(); + } // namespace art diff --git a/compiler/dex/pass_me.h b/compiler/dex/pass_me.h index c7276eb905..0865afd1a4 100644 --- a/compiler/dex/pass_me.h +++ b/compiler/dex/pass_me.h @@ -80,12 +80,53 @@ class PassME: public Pass { } ~PassME() { + default_options_.clear(); } virtual DataFlowAnalysisMode GetTraversal() const { return traversal_type_; } + /** + * @return Returns whether the pass has any configurable options. + */ + bool HasOptions() const { + return default_options_.size() != 0; + } + + /** + * @brief Prints the pass options along with default settings if there are any. + * @details The printing is done using LOG(INFO). + */ + void PrintPassDefaultOptions() const { + for (auto option_it = default_options_.begin(); option_it != default_options_.end(); option_it++) { + LOG(INFO) << "\t" << option_it->first << ":" << std::dec << option_it->second; + } + } + + /** + * @brief Prints the pass options along with either default or overridden setting. + * @param overridden_options The overridden settings for this pass. + */ + void PrintPassOptions(SafeMap<const std::string, int>& overridden_options) const { + // We walk through the default options only to get the pass names. We use GetPassOption to + // also consider the overridden ones. + for (auto option_it = default_options_.begin(); option_it != default_options_.end(); option_it++) { + LOG(INFO) << "\t" << option_it->first << ":" << std::dec << GetPassOption(option_it->first, overridden_options); + } + } + + /** + * @brief Used to obtain the option for a pass. + * @details Will return the overridden option if it exists or default one. + * @param option_name The name of option whose setting to look for. + * @param c_unit The compilation unit currently being handled. + * @return Returns the setting for the pass option. + */ + int GetPassOption(const char* option_name, CompilationUnit* c_unit) const { + return GetPassOption(option_name, c_unit->overridden_pass_options); + } + const char* GetDumpCFGFolder() const { return dump_cfg_folder_; } @@ -95,6 +136,25 @@ class PassME: public Pass { } protected: + int GetPassOption(const char* option_name, const SafeMap<const std::string, int>& overridden_options) const { + // First check if there are any overridden settings. + auto overridden_it = overridden_options.find(std::string(option_name)); + if (overridden_it != overridden_options.end()) { + return overridden_it->second; + } + + // Next check the default options. + auto default_it = default_options_.find(option_name); + + if (default_it == default_options_.end()) { + // An invalid option is being requested. + DCHECK(false); + return 0; + } + + return default_it->second; + } + /** @brief Type of traversal: determines the order to execute the pass on the BasicBlocks. */ const DataFlowAnalysisMode traversal_type_; @@ -103,6 +163,13 @@ class PassME: public Pass { /** @brief CFG Dump Folder: what sub-folder to use for dumping the CFGs post pass. */ const char* const dump_cfg_folder_; + + /** + * @brief Contains a map of options with the default settings. + * @details The constructor of the specific pass instance should fill this + * with default options. + * */ + SafeMap<const char*, int> default_options_; }; } // namespace art #endif // ART_COMPILER_DEX_PASS_ME_H_ diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 19b37afa1c..aef235b82a 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -226,6 +226,15 @@ static void Usage(const char* fmt, ...) { UsageError(" --disable-passes=<pass-names>: disable one or more passes separated by comma."); UsageError(" Example: --disable-passes=UseCount,BBOptimizations"); UsageError(""); + UsageError(" --print-pass-options: print a list of passes that have configurable options along " + "with the setting."); + UsageError(" Will print default if no overridden setting exists."); + UsageError(""); + UsageError(" --pass-options=Pass1Name:Pass1OptionName:Pass1Option#," + "Pass2Name:Pass2OptionName:Pass2Option#"); + UsageError(" Used to specify a pass specific option. The setting itself must be integer."); + UsageError(" Separator used between options is a comma."); + UsageError(""); std::cerr << "See log for usage error information\n"; exit(EXIT_FAILURE); } @@ -847,6 +856,7 @@ static int dex2oat(int argc, char** argv) { bool dump_stats = false; bool dump_timing = false; bool dump_passes = false; + bool print_pass_options = false; bool include_patch_information = CompilerOptions::kDefaultIncludePatchInformation; bool include_debug_symbols = kIsDebugBuild; bool dump_slow_timing = kIsDebugBuild; @@ -1033,6 +1043,11 @@ static int dex2oat(int argc, char** argv) { } else if (option.starts_with("--dump-cfg-passes=")) { std::string dump_passes = option.substr(strlen("--dump-cfg-passes=")).data(); PassDriverMEOpts::SetDumpPassList(dump_passes); + } else if (option == "--print-pass-options") { + print_pass_options = true; + } else if (option.starts_with("--pass-options=")) { + std::string options = option.substr(strlen("--pass-options=")).data(); + PassDriverMEOpts::SetOverriddenPassOptions(options); } else if (option == "--include-patch-information") { include_patch_information = true; } else if (option == "--no-include-patch-information") { @@ -1179,6 +1194,10 @@ static int dex2oat(int argc, char** argv) { break; } + if (print_pass_options) { + PassDriverMEOpts::PrintPassOptions(); + } + std::unique_ptr<CompilerOptions> compiler_options(new CompilerOptions(compiler_filter, huge_method_threshold, large_method_threshold, |