From 8bceccec7eddff8cd872aa20505b4a3a6be60a16 Mon Sep 17 00:00:00 2001 From: Jean Christophe Beyler Date: Tue, 29 Apr 2014 13:42:08 -0700 Subject: [PATCH] ART: Print and dump functionalities per pass LOG is a great logging tool but sometimes a pass has some debugging text it want to be able to turn on/off easily. By going via a print_pass flag, we can actually turn it on/off easily per pass when debugging/instrumenting. - Added a pass printer to help debug messages for future passes. - Added a print_pass flag in CompilationUnit to filter out messages. At the same time, did a similar system for dumping the CFG. - Also moved some API into public from protected. Change-Id: Ie0e89a8fc773e8583f3e4ffd6e4bd2eebdbb2bf4 Signed-off-by: Jean Christophe Beyler Signed-off-by: Razvan A Lupusoru Signed-off-by: Yixin Shou Signed-off-by: Chao-ying Fu Signed-off-by: Udayan Banerji --- compiler/dex/compiler_ir.h | 1 + compiler/dex/frontend.cc | 3 +- compiler/dex/pass.h | 15 ++++++++++ compiler/dex/pass_driver.h | 27 ++++++++++++++++-- compiler/dex/pass_driver_me.cc | 64 +++++++++++++++++++++++++++++++++--------- dex2oat/dex2oat.cc | 14 +++++++++ 6 files changed, 107 insertions(+), 17 deletions(-) diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h index 35d777ec7..66fb608d3 100644 --- a/compiler/dex/compiler_ir.h +++ b/compiler/dex/compiler_ir.h @@ -88,6 +88,7 @@ struct CompilationUnit { std::unique_ptr mir_graph; // MIR container. std::unique_ptr cg; // Target-specific codegen. TimingLogger timings; + bool print_pass; // Do we want to print a pass or not? }; } // namespace art diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc index 9bad736c8..e2463025d 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -105,7 +105,8 @@ CompilationUnit::CompilationUnit(ArenaPool* pool) arena_stack(pool), mir_graph(nullptr), cg(nullptr), - timings("QuickCompiler", true, false) { + timings("QuickCompiler", true, false), + print_pass(false) { } CompilationUnit::~CompilationUnit() { diff --git a/compiler/dex/pass.h b/compiler/dex/pass.h index 4ce040e9a..b4906d67d 100644 --- a/compiler/dex/pass.h +++ b/compiler/dex/pass.h @@ -89,6 +89,21 @@ class Pass { return false; } + static void BasePrintMessage(CompilationUnit* c_unit, const char* pass_name, const char* message, ...) { + // Check if we want to log something or not. + if (c_unit->print_pass) { + // Stringify the message. + va_list args; + va_start(args, message); + std::string stringified_message; + StringAppendV(&stringified_message, message, args); + va_end(args); + + // Log the message and ensure to include pass name. + LOG(INFO) << pass_name << ": " << stringified_message; + } + } + protected: /** @brief The pass name: used for searching for a pass when running a particular pass or debugging. */ const char* const pass_name_; diff --git a/compiler/dex/pass_driver.h b/compiler/dex/pass_driver.h index aa0d1ae46..788f24b46 100644 --- a/compiler/dex/pass_driver.h +++ b/compiler/dex/pass_driver.h @@ -141,7 +141,6 @@ class PassDriver { } } - protected: /** * @brief Gets the list of passes currently schedule to execute. * @return pass_list_ @@ -150,14 +149,27 @@ class PassDriver { return pass_list_; } - virtual void InitializePasses() { - SetDefaultPasses(); + static void SetPrintAllPasses() { + default_print_passes_ = true; + } + + static void SetDumpPassList(const char* list) { + dump_pass_list_.reset(list); + } + + static void SetPrintPassList(const char* list) { + print_pass_list_.reset(list); } void SetDefaultPasses() { pass_list_ = PassDriver::g_default_pass_list; } + protected: + virtual void InitializePasses() { + SetDefaultPasses(); + } + /** * @brief Apply a patch: perform start/work/end functions. */ @@ -185,6 +197,15 @@ class PassDriver { /** @brief The default pass list is used to initialize pass_list_. */ static std::vector g_default_pass_list; + + /** @brief Do we, by default, want to be printing the log messages? */ + static bool default_print_passes_; + + /** @brief What are the passes we want to be printing the log messages? */ + static std::unique_ptr print_pass_list_; + + /** @brief What are the passes we want to be dumping the CFG? */ + static std::unique_ptr dump_pass_list_; }; } // namespace art diff --git a/compiler/dex/pass_driver_me.cc b/compiler/dex/pass_driver_me.cc index d0545004f..099cfee5b 100644 --- a/compiler/dex/pass_driver_me.cc +++ b/compiler/dex/pass_driver_me.cc @@ -77,6 +77,19 @@ uint16_t const PassDriver::g_passes_size = arraysize(PassDriver std::vector PassDriver::g_default_pass_list(PassDriver::g_passes, PassDriver::g_passes + PassDriver::g_passes_size); +// By default, do not have a dump pass list. +template<> +std::unique_ptr PassDriver::dump_pass_list_(nullptr); + +// By default, do not have a print pass list. +template<> +std::unique_ptr PassDriver::print_pass_list_(nullptr); + +// By default, we do not print the pass' information. +template<> +bool PassDriver::default_print_passes_ = false; + + PassDriverME::PassDriverME(CompilationUnit* cu) : PassDriver(), pass_me_data_holder_(), dump_cfg_folder_("/sdcard/") { pass_me_data_holder_.bb = nullptr; @@ -136,26 +149,51 @@ bool PassDriverME::RunPass(const Pass* pass, bool time_split) { // 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 = default_print_passes_; + + const char* print_pass_list = print_pass_list_.get(); + + if (print_pass_list != nullptr && strstr(print_pass_list, pass->GetName()) != nullptr) { + c_unit->print_pass = true; + } + // Applying the pass: first start, doWork, and end calls. ApplyPass(&pass_me_data_holder_, pass); // Do we want to log it? - if ((c_unit->enable_debug& (1 << kDebugDumpCFG)) != 0) { - // Do we have a pass folder? - const PassME* me_pass = (down_cast(pass)); - const char* passFolder = me_pass->GetDumpCFGFolder(); - DCHECK(passFolder != nullptr); - - if (passFolder[0] != 0) { - // Create directory prefix. - std::string prefix = GetDumpCFGFolder(); - prefix += passFolder; - prefix += "/"; - - c_unit->mir_graph->DumpCFG(prefix.c_str(), false); + bool should_dump = ((c_unit->enable_debug & (1 << kDebugDumpCFG)) != 0); + + const char* dump_pass_list = dump_pass_list_.get(); + + if (dump_pass_list != nullptr) { + bool found = strstr(dump_pass_list, pass->GetName()); + should_dump = (should_dump || found); + } + + if (should_dump) { + // Do we want to log it? + if ((c_unit->enable_debug& (1 << kDebugDumpCFG)) != 0) { + // Do we have a pass folder? + const PassME* me_pass = (down_cast(pass)); + const char* passFolder = me_pass->GetDumpCFGFolder(); + DCHECK(passFolder != nullptr); + + if (passFolder[0] != 0) { + // Create directory prefix. + std::string prefix = GetDumpCFGFolder(); + prefix += passFolder; + prefix += "/"; + + c_unit->mir_graph->DumpCFG(prefix.c_str(), false); + } } } + + c_unit->print_pass = old_print_pass; } // If the pass gate passed, we can declare success. diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index f0b575041..6d05e5e85 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -922,6 +922,20 @@ static int dex2oat(int argc, char** argv) { } else if (option.starts_with("--disable-passes=")) { std::string disable_passes = option.substr(strlen("--disable-passes=")).data(); PassDriverME::CreateDefaultPassList(disable_passes); + } else if (option.starts_with("--print-passes=")) { + std::string print_passes = option.substr(strlen("--print-passes=")).data(); + size_t len = print_passes.length() + 1; + char* duplicate = new char[len]; + strncpy(duplicate, print_passes.c_str(), len); + PassDriverME::SetPrintPassList(duplicate); + } else if (option == "--print-all-passes") { + PassDriverME::SetPrintAllPasses(); + } else if (option.starts_with("--dump-cfg-passes=")) { + std::string dump_passes = option.substr(strlen("--dump-cfg-passes=")).data(); + size_t len = dump_passes.length() + 1; + char* duplicate = new char[len]; + strncpy(duplicate, dump_passes.c_str(), len); + PassDriverME::SetDumpPassList(duplicate); } else { Usage("Unknown argument %s", option.data()); } -- 2.11.0