diff --git a/Makefile.am b/Makefile.am index e9d39381e11..03a33819e59 100644 --- a/Makefile.am +++ b/Makefile.am @@ -415,7 +415,6 @@ libopt_la_SOURCES = \ opt/interdex/InterDexPass.cpp \ opt/interdex/InterDexReshuffleImpl.cpp \ opt/interdex/InterDexReshufflePass.cpp \ - opt/interdex/MAInterDexReshufflePass.cpp \ opt/interdex/SortRemainingClassesPass.cpp \ opt/kotlin-lambda/RewriteKotlinSingletonInstance.cpp \ opt/kotlin-lambda/KotlinObjectInliner.cpp \ diff --git a/opt/class-merging/IntraDexClassMergingPass.h b/opt/class-merging/IntraDexClassMergingPass.h index 2ba3e5fc28a..7e89a1aa5ec 100644 --- a/opt/class-merging/IntraDexClassMergingPass.h +++ b/opt/class-merging/IntraDexClassMergingPass.h @@ -28,7 +28,7 @@ class IntraDexClassMergingPass : public Pass { using namespace redex_properties::interactions; using namespace redex_properties::names; return { - {DexLimitsObeyed, Establishes}, + {DexLimitsObeyed, Preserves}, {NoResolvablePureRefs, Preserves}, {InitialRenameClass, Preserves}, }; diff --git a/opt/interdex/InterDexReshufflePass.cpp b/opt/interdex/InterDexReshufflePass.cpp index 2672d11af00..97ce733488a 100644 --- a/opt/interdex/InterDexReshufflePass.cpp +++ b/opt/interdex/InterDexReshufflePass.cpp @@ -6,12 +6,14 @@ */ #include "InterDexReshufflePass.h" +#include "ClassMerging.h" #include "ConfigFiles.h" #include "DedupStrings.h" #include "DexClass.h" #include "DexStructure.h" #include "DexUtil.h" #include "InterDexPass.h" +#include "ModelSpecGenerator.h" #include "PassManager.h" #include "Show.h" #include "StlUtil.h" @@ -49,9 +51,29 @@ void InterDexReshufflePass::run_pass(DexStoresVector& stores, return; } - InterDexReshuffleImpl impl(conf, mgr, m_config, original_scope, root_dexen); - impl.compute_plan(); - impl.apply_plan(); + auto has_IDCM_pass = mgr.find_pass("IntraDexClassMergingPass"); + // The mergeability_aware reshuffle algorithm is only enabled when 1) there + // will be a IDCM pass; 2) m_allow_mergeability_aware is set true; and 3) This + // is the first run of InterDexReshufflePass. + bool enable_mergeability_aware_reshuffle = + has_IDCM_pass && m_allow_mergeability_aware && m_run == 0; + if (enable_mergeability_aware_reshuffle) { + TRACE(PM, 1, "Run regular mergeability-aware InterDexReshuffle"); + mgr.incr_metric("Mergeability_aware", 1); + class_merging::Model merging_model = class_merging::construct_global_model( + original_scope, mgr, conf, stores); + + InterDexReshuffleImpl impl(conf, mgr, m_config, original_scope, root_dexen, + merging_model); + impl.compute_plan(); + impl.apply_plan(); + } else { + TRACE(PM, 1, "Run regular InterDexReshuffle"); + mgr.incr_metric("Mergeability_aware", 0); + InterDexReshuffleImpl impl(conf, mgr, m_config, original_scope, root_dexen); + impl.compute_plan(); + impl.apply_plan(); + } // Sanity check std::unordered_set original_scope_set(original_scope.begin(), @@ -63,6 +85,8 @@ void InterDexReshufflePass::run_pass(DexStoresVector& stores, for (auto cls : original_scope_set) { always_assert(new_scope_set.count(cls)); } + + ++m_run; } static InterDexReshufflePass s_pass; diff --git a/opt/interdex/InterDexReshufflePass.h b/opt/interdex/InterDexReshufflePass.h index 35af0668cc9..3dc30913824 100644 --- a/opt/interdex/InterDexReshufflePass.h +++ b/opt/interdex/InterDexReshufflePass.h @@ -89,14 +89,30 @@ class InterDexReshufflePass : public Pass { m_config.max_batch_size, "How many class to move per batch. More might yield better results, " "but might take longer."); + bind("other_weight", + m_config.other_weight, + m_config.other_weight, + "Weight for non-deduped method in mergeability-aware reshuffle cost " + "function."); + bind("deduped_weight", + m_config.deduped_weight, + m_config.deduped_weight, + "Weight for deduped method in mergeability-aware reshuffle cost " + "function."); bind("exclude_below20pct_coldstart_classes", false, m_config.exclude_below20pct_coldstart_classes, "Whether to exclude coldstart classes in between 1pctColdStart and " "20pctColdStart marker" "from the reshuffle."); + bind("allow_mergeability_aware", true, m_allow_mergeability_aware); } private: ReshuffleConfig m_config; + + // Which iteration of `run_pass`. + size_t m_run{0}; + + bool m_allow_mergeability_aware; }; diff --git a/opt/interdex/MAInterDexReshufflePass.cpp b/opt/interdex/MAInterDexReshufflePass.cpp deleted file mode 100644 index df7c3528582..00000000000 --- a/opt/interdex/MAInterDexReshufflePass.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "MAInterDexReshufflePass.h" -#include "ClassMerging.h" -#include "ConfigFiles.h" -#include "DedupStrings.h" -#include "DexClass.h" -#include "DexStructure.h" -#include "DexUtil.h" -#include "InterDexPass.h" -#include "ModelSpecGenerator.h" -#include "PassManager.h" -#include "Show.h" -#include "StlUtil.h" -#include "Trace.h" -#include "Walkers.h" - -namespace { -const interdex::InterDexPass* get_interdex_pass(const PassManager& mgr) { - const auto* pass = - static_cast(mgr.find_pass("InterDexPass")); - always_assert_log(pass, "InterDexPass missing"); - return pass; -} -} // namespace - -void MergeabilityAwareInterDexReshufflePass::run_pass(DexStoresVector& stores, - ConfigFiles& conf, - PassManager& mgr) { - const auto* interdex_pass = get_interdex_pass(mgr); - if (!interdex_pass->minimize_cross_dex_refs()) { - mgr.incr_metric("no minimize_cross_dex_refs", 1); - TRACE(IDEXR, 1, - "MergeabilityAwareInterDexReshufflePass not run because InterDexPass " - "is not configured " - "for minimize_cross_dex_refs."); - return; - } - - auto has_IDCM_pass = mgr.find_pass("IntraDexClassMergingPass"); - if (!has_IDCM_pass) { - mgr.incr_metric("no IntraDexClassMergingPass", 1); - TRACE(IDEXR, 1, - "MergeabilityAwareInterDexReshufflePass not run because there is no " - "IntraDexClassMergingPass."); - return; - } - auto original_scope = build_class_scope(stores); - - auto& root_store = stores.at(0); - auto& root_dexen = root_store.get_dexen(); - if (root_dexen.size() == 1) { - // only a primary dex? Nothing to do - return; - } - - class_merging::Model merging_model = - class_merging::construct_global_model(original_scope, mgr, conf, stores); - - InterDexReshuffleImpl impl(conf, mgr, m_config, original_scope, root_dexen, - merging_model); - impl.compute_plan(); - impl.apply_plan(); - - // Sanity check - std::unordered_set original_scope_set(original_scope.begin(), - original_scope.end()); - auto new_scope = build_class_scope(stores); - std::unordered_set new_scope_set(new_scope.begin(), - new_scope.end()); - always_assert(original_scope_set.size() == new_scope_set.size()); - for (auto cls : original_scope_set) { - always_assert(new_scope_set.count(cls)); - } -} - -static MergeabilityAwareInterDexReshufflePass s_pass; diff --git a/opt/interdex/MAInterDexReshufflePass.h b/opt/interdex/MAInterDexReshufflePass.h deleted file mode 100644 index dbe4f29b870..00000000000 --- a/opt/interdex/MAInterDexReshufflePass.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include "DexClass.h" -#include "InterDex.h" -#include "InterDexReshuffleImpl.h" -#include "Pass.h" - -/* Similar to InterDexReshufflePass, this pass impls Local Search Algotithm to - * minize cross-dex refs by reshuffling classes among dex files. Different from - * InterDexReshufflePass, when reshuffling classes, this pass considers the - * classes mergeability. That is, if two classes may be merged in later IDCM, - * they have the high possibility to moved to the same dex. - */ -class MergeabilityAwareInterDexReshufflePass : public Pass { - public: - explicit MergeabilityAwareInterDexReshufflePass() - : Pass("MergeabilityAwareInterDexReshufflePass") {} - - redex_properties::PropertyInteractions get_property_interactions() - const override { - using namespace redex_properties::interactions; - using namespace redex_properties::names; - return { - {NoResolvablePureRefs, Preserves}, - {InitialRenameClass, Preserves}, - }; - } - - void run_pass(DexStoresVector&, ConfigFiles&, PassManager&) override; - - void bind_config() override { - bind("reserved_extra_frefs", - m_config.reserved_extra_frefs, - m_config.reserved_extra_frefs, - "How many extra frefs to be reserved for the dexes this pass " - "processes."); - bind("reserved_extra_trefs", - m_config.reserved_extra_trefs, - m_config.reserved_extra_trefs, - "How many extra trefs to be reserved for the dexes this pass " - "processes."); - bind("reserved_extra_mrefs", - m_config.reserved_extra_mrefs, - m_config.reserved_extra_mrefs, - "How many extra mrefs to be reserved for the dexes this pass " - "processes."); - bind("extra_linear_alloc_limit", - m_config.extra_linear_alloc_limit, - m_config.extra_linear_alloc_limit, - "How many extra linear_alloc_limit to be reserved for the dexes " - "this pass rocesses."); - bind("max_batches", - m_config.max_batches, - m_config.max_batches, - "How many batches to execute. More might yield better results, but " - "might take longer."); - bind("max_batch_size", - m_config.max_batch_size, - m_config.max_batch_size, - "How many class to move per batch. More might yield better results, " - "but might take longer."); - bind("other_weight", - m_config.other_weight, - m_config.other_weight, - "Weight for non-deduped method in mergeability-aware reshuffle cost " - "function."); - bind("deduped_weight", - m_config.deduped_weight, - m_config.deduped_weight, - "Weight for deduped method in mergeability-aware reshuffle cost " - "function."); - bind("exclude_below20pct_coldstart_classes", - false, - m_config.exclude_below20pct_coldstart_classes, - "Whether to exclude coldstart classes in between 1pctColdStart and " - "20pctColdStart marker" - "from the reshuffle."); - } - - private: - ReshuffleConfig m_config; -};