Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: runtime/vm/flow_graph_inliner.cc

Issue 11541002: Use call counts to prevent cold calls from being inlined. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | runtime/vm/object.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/flow_graph_inliner.h" 5 #include "vm/flow_graph_inliner.h"
6 6
7 #include "vm/compiler.h" 7 #include "vm/compiler.h"
8 #include "vm/flags.h" 8 #include "vm/flags.h"
9 #include "vm/flow_graph.h" 9 #include "vm/flow_graph.h"
10 #include "vm/flow_graph_builder.h" 10 #include "vm/flow_graph_builder.h"
(...skipping 18 matching lines...) Expand all
29 DEFINE_FLAG(int, inlining_in_loop_size_threshold, 80, 29 DEFINE_FLAG(int, inlining_in_loop_size_threshold, 80,
30 "Inline functions in loops that have threshold or fewer instructions"); 30 "Inline functions in loops that have threshold or fewer instructions");
31 DEFINE_FLAG(int, inlining_callee_call_sites_threshold, 1, 31 DEFINE_FLAG(int, inlining_callee_call_sites_threshold, 1,
32 "Always inline functions containing threshold or fewer calls."); 32 "Always inline functions containing threshold or fewer calls.");
33 DEFINE_FLAG(int, inlining_constant_arguments_count, 1, 33 DEFINE_FLAG(int, inlining_constant_arguments_count, 1,
34 "Inline function calls with sufficient constant arguments " 34 "Inline function calls with sufficient constant arguments "
35 "and up to the increased threshold on instructions"); 35 "and up to the increased threshold on instructions");
36 DEFINE_FLAG(int, inlining_constant_arguments_size_threshold, 60, 36 DEFINE_FLAG(int, inlining_constant_arguments_size_threshold, 60,
37 "Inline function calls with sufficient constant arguments " 37 "Inline function calls with sufficient constant arguments "
38 "and up to the increased threshold on instructions"); 38 "and up to the increased threshold on instructions");
39 DEFINE_FLAG(int, inlining_hotness, 10,
40 "Inline only hotter calls, in percents (0 .. 100); "
41 "default 10%: calls above-equal 10% of max-count are inlined.");
39 42
40 DECLARE_FLAG(bool, print_flow_graph); 43 DECLARE_FLAG(bool, print_flow_graph);
41 DECLARE_FLAG(int, deoptimization_counter_threshold); 44 DECLARE_FLAG(int, deoptimization_counter_threshold);
42 DECLARE_FLAG(bool, verify_compiler); 45 DECLARE_FLAG(bool, verify_compiler);
43 DECLARE_FLAG(bool, compiler_stats); 46 DECLARE_FLAG(bool, compiler_stats);
44 47
45 #define TRACE_INLINING(statement) \ 48 #define TRACE_INLINING(statement) \
46 do { \ 49 do { \
47 if (FLAG_trace_inlining) statement; \ 50 if (FLAG_trace_inlining) statement; \
48 } while (false) 51 } while (false)
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 // A collection of call sites to consider for inlining. 181 // A collection of call sites to consider for inlining.
179 class CallSites : public FlowGraphVisitor { 182 class CallSites : public FlowGraphVisitor {
180 public: 183 public:
181 explicit CallSites(FlowGraph* flow_graph) 184 explicit CallSites(FlowGraph* flow_graph)
182 : FlowGraphVisitor(flow_graph->postorder()), // We don't use this order. 185 : FlowGraphVisitor(flow_graph->postorder()), // We don't use this order.
183 static_calls_(), 186 static_calls_(),
184 closure_calls_(), 187 closure_calls_(),
185 instance_calls_(), 188 instance_calls_(),
186 skip_static_call_deopt_ids_() { } 189 skip_static_call_deopt_ids_() { }
187 190
188 GrowableArray<StaticCallInstr*>* static_calls() { 191 const GrowableArray<StaticCallInstr*>& static_calls() const {
189 return &static_calls_; 192 return static_calls_;
190 } 193 }
191 194
192 GrowableArray<ClosureCallInstr*>* closure_calls() { 195 const GrowableArray<ClosureCallInstr*>& closure_calls() const {
193 return &closure_calls_; 196 return closure_calls_;
194 } 197 }
195 198
196 GrowableArray<PolymorphicInstanceCallInstr*>* instance_calls() { 199 struct InstanceCallInfo {
197 return &instance_calls_; 200 PolymorphicInstanceCallInstr* call;
201 double ratio;
202 explicit InstanceCallInfo(PolymorphicInstanceCallInstr* call_arg)
203 : call(call_arg), ratio(0.0) {}
204 };
205
206 const GrowableArray<InstanceCallInfo>& instance_calls() const {
207 return instance_calls_;
198 } 208 }
199 209
200 bool HasCalls() const { 210 bool HasCalls() const {
201 return !(static_calls_.is_empty() && 211 return !(static_calls_.is_empty() &&
202 closure_calls_.is_empty() && 212 closure_calls_.is_empty() &&
203 instance_calls_.is_empty()); 213 instance_calls_.is_empty());
204 } 214 }
205 215
206 void Clear() { 216 void Clear() {
207 static_calls_.Clear(); 217 static_calls_.Clear();
208 closure_calls_.Clear(); 218 closure_calls_.Clear();
209 instance_calls_.Clear(); 219 instance_calls_.Clear();
210 skip_static_call_deopt_ids_.Clear(); 220 skip_static_call_deopt_ids_.Clear();
211 } 221 }
212 222
213 void FindCallSites(FlowGraph* graph) { 223 void FindCallSites(FlowGraph* graph) {
214 ASSERT(graph != NULL); 224 ASSERT(graph != NULL);
215 const Function& function = graph->parsed_function().function(); 225 const Function& function = graph->parsed_function().function();
216 ASSERT(function.HasCode()); 226 ASSERT(function.HasCode());
217 const Code& code = Code::Handle(function.unoptimized_code()); 227 const Code& code = Code::Handle(function.unoptimized_code());
228
218 skip_static_call_deopt_ids_.Clear(); 229 skip_static_call_deopt_ids_.Clear();
219 code.ExtractUncalledStaticCallDeoptIds(&skip_static_call_deopt_ids_); 230 code.ExtractUncalledStaticCallDeoptIds(&skip_static_call_deopt_ids_);
231
232 const intptr_t instance_call_start_ix = instance_calls_.length();
220 for (BlockIterator block_it = graph->postorder_iterator(); 233 for (BlockIterator block_it = graph->postorder_iterator();
221 !block_it.Done(); 234 !block_it.Done();
222 block_it.Advance()) { 235 block_it.Advance()) {
223 for (ForwardInstructionIterator it(block_it.Current()); 236 for (ForwardInstructionIterator it(block_it.Current());
224 !it.Done(); 237 !it.Done();
225 it.Advance()) { 238 it.Advance()) {
226 it.Current()->Accept(this); 239 it.Current()->Accept(this);
227 } 240 }
228 } 241 }
242 // Compute instance call site ratio.
243 const intptr_t num_instance_calls =
244 instance_calls_.length() - instance_call_start_ix;
245 intptr_t max_count = 0;
246 GrowableArray<intptr_t> call_counts(num_instance_calls);
247 for (intptr_t i = 0; i < num_instance_calls; ++i) {
248 const intptr_t aggregate_count =
249 instance_calls_[i + instance_call_start_ix].
250 call-> ic_data().AggregateCount();
Vyacheslav Egorov (Google) 2012/12/18 11:55:51 remove space after ->
srdjan 2012/12/18 16:37:51 Done.
251 call_counts.Add(aggregate_count);
252 if (aggregate_count > max_count) max_count = aggregate_count;
253 }
254
255
256 for (intptr_t i = 0; i < num_instance_calls; ++i) {
257 const double ratio = static_cast<double>(call_counts[i]) / max_count;
258 instance_calls_[i + instance_call_start_ix].ratio = ratio;
259 }
229 } 260 }
230 261
231 void VisitClosureCall(ClosureCallInstr* call) { 262 void VisitClosureCall(ClosureCallInstr* call) {
232 closure_calls_.Add(call); 263 closure_calls_.Add(call);
233 } 264 }
234 265
235 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) { 266 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) {
236 instance_calls_.Add(call); 267 instance_calls_.Add(InstanceCallInfo(call));
237 } 268 }
238 269
239 void VisitStaticCall(StaticCallInstr* call) { 270 void VisitStaticCall(StaticCallInstr* call) {
240 if (!call->function().IsInlineable()) return; 271 if (!call->function().IsInlineable()) return;
241 const intptr_t call_deopt_id = call->deopt_id(); 272 const intptr_t call_deopt_id = call->deopt_id();
242 for (intptr_t i = 0; i < skip_static_call_deopt_ids_.length(); i++) { 273 for (intptr_t i = 0; i < skip_static_call_deopt_ids_.length(); i++) {
243 if (call_deopt_id == skip_static_call_deopt_ids_[i]) { 274 if (call_deopt_id == skip_static_call_deopt_ids_[i]) {
244 // Do not inline this call. 275 // Do not inline this call.
245 return; 276 return;
246 } 277 }
247 } 278 }
248 static_calls_.Add(call); 279 static_calls_.Add(call);
249 } 280 }
250 281
251 private: 282 private:
252 GrowableArray<StaticCallInstr*> static_calls_; 283 GrowableArray<StaticCallInstr*> static_calls_;
253 GrowableArray<ClosureCallInstr*> closure_calls_; 284 GrowableArray<ClosureCallInstr*> closure_calls_;
254 GrowableArray<PolymorphicInstanceCallInstr*> instance_calls_; 285 GrowableArray<InstanceCallInfo> instance_calls_;
255 GrowableArray<intptr_t> skip_static_call_deopt_ids_; 286 GrowableArray<intptr_t> skip_static_call_deopt_ids_;
256 287
257 DISALLOW_COPY_AND_ASSIGN(CallSites); 288 DISALLOW_COPY_AND_ASSIGN(CallSites);
258 }; 289 };
259 290
260 291
261 class CallSiteInliner : public ValueObject { 292 class CallSiteInliner : public ValueObject {
262 public: 293 public:
263 explicit CallSiteInliner(FlowGraph* flow_graph) 294 explicit CallSiteInliner(FlowGraph* flow_graph)
264 : caller_graph_(flow_graph), 295 : caller_graph_(flow_graph),
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after
623 } 654 }
624 *in_cache = false; 655 *in_cache = false;
625 ParsedFunction* parsed_function = new ParsedFunction(function); 656 ParsedFunction* parsed_function = new ParsedFunction(function);
626 Parser::ParseFunction(parsed_function); 657 Parser::ParseFunction(parsed_function);
627 parsed_function->AllocateVariables(); 658 parsed_function->AllocateVariables();
628 return parsed_function; 659 return parsed_function;
629 } 660 }
630 661
631 void InlineStaticCalls() { 662 void InlineStaticCalls() {
632 const GrowableArray<StaticCallInstr*>& calls = 663 const GrowableArray<StaticCallInstr*>& calls =
633 *inlining_call_sites_->static_calls(); 664 inlining_call_sites_->static_calls();
634 TRACE_INLINING(OS::Print(" Static Calls (%d)\n", calls.length())); 665 TRACE_INLINING(OS::Print(" Static Calls (%d)\n", calls.length()));
635 for (intptr_t i = 0; i < calls.length(); ++i) { 666 for (intptr_t i = 0; i < calls.length(); ++i) {
636 StaticCallInstr* call = calls[i]; 667 StaticCallInstr* call = calls[i];
637 GrowableArray<Value*> arguments(call->ArgumentCount()); 668 GrowableArray<Value*> arguments(call->ArgumentCount());
638 for (int i = 0; i < call->ArgumentCount(); ++i) { 669 for (int i = 0; i < call->ArgumentCount(); ++i) {
639 arguments.Add(call->ArgumentAt(i)->value()); 670 arguments.Add(call->ArgumentAt(i)->value());
640 } 671 }
641 TryInlining(call->function(), call->argument_names(), &arguments, call); 672 TryInlining(call->function(), call->argument_names(), &arguments, call);
642 } 673 }
643 } 674 }
644 675
645 void InlineClosureCalls() { 676 void InlineClosureCalls() {
646 const GrowableArray<ClosureCallInstr*>& calls = 677 const GrowableArray<ClosureCallInstr*>& calls =
647 *inlining_call_sites_->closure_calls(); 678 inlining_call_sites_->closure_calls();
648 TRACE_INLINING(OS::Print(" Closure Calls (%d)\n", calls.length())); 679 TRACE_INLINING(OS::Print(" Closure Calls (%d)\n", calls.length()));
649 for (intptr_t i = 0; i < calls.length(); ++i) { 680 for (intptr_t i = 0; i < calls.length(); ++i) {
650 ClosureCallInstr* call = calls[i]; 681 ClosureCallInstr* call = calls[i];
651 // Find the closure of the callee. 682 // Find the closure of the callee.
652 ASSERT(call->ArgumentCount() > 0); 683 ASSERT(call->ArgumentCount() > 0);
653 const CreateClosureInstr* closure = 684 const CreateClosureInstr* closure =
654 call->ArgumentAt(0)->value()->definition()->AsCreateClosure(); 685 call->ArgumentAt(0)->value()->definition()->AsCreateClosure();
655 if (closure == NULL) { 686 if (closure == NULL) {
656 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n")); 687 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n"));
657 continue; 688 continue;
658 } 689 }
659 GrowableArray<Value*> arguments(call->ArgumentCount()); 690 GrowableArray<Value*> arguments(call->ArgumentCount());
660 for (int i = 0; i < call->ArgumentCount(); ++i) { 691 for (int i = 0; i < call->ArgumentCount(); ++i) {
661 arguments.Add(call->ArgumentAt(i)->value()); 692 arguments.Add(call->ArgumentAt(i)->value());
662 } 693 }
663 TryInlining(closure->function(), 694 TryInlining(closure->function(),
664 call->argument_names(), 695 call->argument_names(),
665 &arguments, 696 &arguments,
666 call); 697 call);
667 } 698 }
668 } 699 }
669 700
670 void InlineInstanceCalls() { 701 void InlineInstanceCalls() {
671 const GrowableArray<PolymorphicInstanceCallInstr*>& calls = 702 const GrowableArray<CallSites::InstanceCallInfo>& call_info =
672 *inlining_call_sites_->instance_calls(); 703 inlining_call_sites_->instance_calls();
673 TRACE_INLINING(OS::Print(" Polymorphic Instance Calls (%d)\n", 704 TRACE_INLINING(OS::Print(" Polymorphic Instance Calls (%d)\n",
674 calls.length())); 705 call_info.length()));
675 for (intptr_t i = 0; i < calls.length(); ++i) { 706 for (intptr_t i = 0; i < call_info.length(); ++i) {
676 PolymorphicInstanceCallInstr* instr = calls[i]; 707 PolymorphicInstanceCallInstr* instr = call_info[i].call;
677 const ICData& ic_data = instr->ic_data(); 708 const ICData& ic_data = instr->ic_data();
678 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); 709 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
679 if (instr->with_checks()) { 710 if (instr->with_checks()) {
680 TRACE_INLINING(OS::Print( 711 TRACE_INLINING(OS::Print(
681 " => %s (deopt count %d)\n Bailout: %"Pd" checks\n", 712 " => %s (deopt count %d)\n Bailout: %"Pd" checks\n",
682 target.ToCString(), 713 target.ToCString(),
683 target.deoptimization_counter(), 714 target.deoptimization_counter(),
684 ic_data.NumberOfChecks())); 715 ic_data.NumberOfChecks()));
716 continue;
717 }
718 if ((call_info[i].ratio * 100) < FLAG_inlining_hotness) {
719 TRACE_INLINING(OS::Print(
720 " => %s (deopt count %d)\n Bailout: cold %f\n",
721 target.ToCString(),
722 target.deoptimization_counter(),
723 call_info[i].ratio));
685 continue; 724 continue;
686 } 725 }
687 GrowableArray<Value*> arguments(instr->ArgumentCount()); 726 GrowableArray<Value*> arguments(instr->ArgumentCount());
688 for (int i = 0; i < instr->ArgumentCount(); ++i) { 727 for (int arg_i = 0; arg_i < instr->ArgumentCount(); ++arg_i) {
689 arguments.Add(instr->ArgumentAt(i)->value()); 728 arguments.Add(instr->ArgumentAt(arg_i)->value());
690 } 729 }
691 TryInlining(target, 730 TryInlining(target,
692 instr->instance_call()->argument_names(), 731 instr->instance_call()->argument_names(),
693 &arguments, 732 &arguments,
694 instr); 733 instr);
695 } 734 }
696 } 735 }
697 736
698 void AdjustForOptionalParameters(const ParsedFunction& parsed_function, 737 void AdjustForOptionalParameters(const ParsedFunction& parsed_function,
699 const Array& argument_names, 738 const Array& argument_names,
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
843 OS::Print("After Inlining of %s\n", flow_graph_-> 882 OS::Print("After Inlining of %s\n", flow_graph_->
844 parsed_function().function().ToFullyQualifiedCString()); 883 parsed_function().function().ToFullyQualifiedCString());
845 FlowGraphPrinter printer(*flow_graph_); 884 FlowGraphPrinter printer(*flow_graph_);
846 printer.PrintBlocks(); 885 printer.PrintBlocks();
847 } 886 }
848 } 887 }
849 } 888 }
850 } 889 }
851 890
852 } // namespace dart 891 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/object.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698