diff options
author | 2021-07-09 17:06:03 +0100 | |
---|---|---|
committer | 2021-09-13 17:54:53 +0000 | |
commit | 3de02fb67de386368c9fe39ab5a0133afcf1d785 (patch) | |
tree | 39b82839945a26dfb857a403effa4ba248145715 /compiler/optimizing/loop_optimization.cc | |
parent | 18074d2b59ae56dcfccea770ceb515215c8eb53f (diff) |
ART: Removes SuspendCheck for plain loops with a low trip count.
This change removes SuspendCheck for plain loops with a low trip count.
The SuspendCheck in the codegen makes sure that the thread can be
interrupted during execution for GC. Not being able to do so might
decrease the responsiveness of GC in the case when a very long loop
or a long recursion is being executed.
However, for plain loops with a small trip count, the removal of
SuspendCheck should not affect the GC's responsiveness by a large
margin. Consequently, since the thread won't be interrupted for
plain loops, it is assumed that the performance might increase
by removing SuspendCheck.
Test: art/test.py -v -j12 --host --64 -t 2233-checker\
-remove-loop-suspend-check --run-test --optimizing
Change-Id: Ic9f1387059669645ad836d8277bfbc7553aa6e2f
Diffstat (limited to 'compiler/optimizing/loop_optimization.cc')
-rw-r--r-- | compiler/optimizing/loop_optimization.cc | 55 |
1 files changed, 51 insertions, 4 deletions
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc index 02ee4ec057..cd054822cd 100644 --- a/compiler/optimizing/loop_optimization.cc +++ b/compiler/optimizing/loop_optimization.cc @@ -636,6 +636,47 @@ bool HLoopOptimization::TraverseLoopsInnerToOuter(LoopNode* node) { } // +// This optimization applies to loops with plain simple operations +// (I.e. no calls to java code or runtime) with a known small trip_count * instr_count +// value. +// +bool HLoopOptimization::TryToRemoveSuspendCheckFromLoopHeader(LoopAnalysisInfo* analysis_info, + bool generate_code) { + if (!graph_->SuspendChecksAreAllowedToBeRemoved()) { + return false; + } + + int64_t trip_count = analysis_info->GetTripCount(); + + if (trip_count == LoopAnalysisInfo::kUnknownTripCount) { + return false; + } + + int64_t instruction_count = analysis_info->GetNumberOfInstructions(); + int64_t total_instruction_count = trip_count * instruction_count; + + // The inclusion of the HasInstructionsPreventingScalarOpts() prevents this + // optimization from being applied to loops that have calls. + bool can_optimize = + total_instruction_count <= HLoopOptimization::kMaxTotalInstRemoveSuspendCheck && + !analysis_info->HasInstructionsPreventingScalarOpts(); + + if (!can_optimize) { + return false; + } + + if (generate_code) { + HLoopInformation* loop_info = analysis_info->GetLoopInfo(); + HBasicBlock* header = loop_info->GetHeader(); + HInstruction* instruction = header->GetLoopInformation()->GetSuspendCheck(); + header->RemoveInstruction(instruction); + loop_info->SetSuspendCheck(nullptr); + } + + return true; +} + +// // Optimization. // @@ -779,7 +820,7 @@ bool HLoopOptimization::TryOptimizeInnerLoopFinite(LoopNode* node) { } bool HLoopOptimization::OptimizeInnerLoop(LoopNode* node) { - return TryOptimizeInnerLoopFinite(node) || TryPeelingAndUnrolling(node); + return TryOptimizeInnerLoopFinite(node) || TryLoopScalarOpts(node); } @@ -885,7 +926,7 @@ bool HLoopOptimization::TryFullUnrolling(LoopAnalysisInfo* analysis_info, bool g return true; } -bool HLoopOptimization::TryPeelingAndUnrolling(LoopNode* node) { +bool HLoopOptimization::TryLoopScalarOpts(LoopNode* node) { HLoopInformation* loop_info = node->loop_info; int64_t trip_count = LoopAnalysis::GetLoopTripCount(loop_info, &induction_range_); LoopAnalysisInfo analysis_info(loop_info); @@ -898,10 +939,16 @@ bool HLoopOptimization::TryPeelingAndUnrolling(LoopNode* node) { if (!TryFullUnrolling(&analysis_info, /*generate_code*/ false) && !TryPeelingForLoopInvariantExitsElimination(&analysis_info, /*generate_code*/ false) && - !TryUnrollingForBranchPenaltyReduction(&analysis_info, /*generate_code*/ false)) { + !TryUnrollingForBranchPenaltyReduction(&analysis_info, /*generate_code*/ false) && + !TryToRemoveSuspendCheckFromLoopHeader(&analysis_info, /*generate_code*/ false)) { return false; } + // Try the suspend check removal even for non-clonable loops. Also this + // optimization doesn't interfere with other scalar loop optimizations so it can + // be done prior to them. + bool removed_suspend_check = TryToRemoveSuspendCheckFromLoopHeader(&analysis_info); + // Run 'IsLoopClonable' the last as it might be time-consuming. if (!LoopClonerHelper::IsLoopClonable(loop_info)) { return false; @@ -909,7 +956,7 @@ bool HLoopOptimization::TryPeelingAndUnrolling(LoopNode* node) { return TryFullUnrolling(&analysis_info) || TryPeelingForLoopInvariantExitsElimination(&analysis_info) || - TryUnrollingForBranchPenaltyReduction(&analysis_info); + TryUnrollingForBranchPenaltyReduction(&analysis_info) || removed_suspend_check; } // |