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

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

Issue 11269040: More inlining flags and tuned heuristics. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Style and phrasing. Created 8 years, 1 month 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
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"
11 #include "vm/flow_graph_optimizer.h" 11 #include "vm/flow_graph_optimizer.h"
12 #include "vm/il_printer.h" 12 #include "vm/il_printer.h"
13 #include "vm/intrinsifier.h" 13 #include "vm/intrinsifier.h"
14 #include "vm/longjump.h" 14 #include "vm/longjump.h"
15 #include "vm/object.h" 15 #include "vm/object.h"
16 #include "vm/object_store.h" 16 #include "vm/object_store.h"
17 #include "vm/timer.h" 17 #include "vm/timer.h"
18 18
19 namespace dart { 19 namespace dart {
20 20
21 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining"); 21 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining");
22 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function"); 22 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function");
23 DEFINE_FLAG(int, inlining_size_threshold, 50, 23
24 "Inline only functions with up to threshold instructions (default 50)"); 24 // Flags for inlining heuristics.
25 // TODO(srdjan): set to 3 once crash in apidoc.dart is resolved.
26 DEFINE_FLAG(int, inlining_depth_threshold, 3, 25 DEFINE_FLAG(int, inlining_depth_threshold, 3,
27 "Inline recursively up to threshold depth (default 3)"); 26 "Inline function calls up to threshold nesting depth");
27 DEFINE_FLAG(int, inlining_size_threshold, 20,
28 "Always inline functions that have threshold or fewer instructions");
29 DEFINE_FLAG(int, inlining_in_loop_size_threshold, 60,
30 "Inline functions in loops that have threshold or fewer instructions");
31 DEFINE_FLAG(int, inlining_callee_call_sites_threshold, 1,
32 "Always inline functions containing threshold or fewer calls.");
33 DEFINE_FLAG(int, inlining_constant_arguments_count, 1,
34 "Inline function calls with sufficient constant arguments "
35 "and up to the increased threshold on instructions");
36 DEFINE_FLAG(int, inlining_constant_arguments_size_threshold, 40,
37 "Inline function calls with sufficient constant arguments "
38 "and up to the increased threshold on instructions");
srdjan 2012/10/25 20:38:50 Indent 4 characters (continuation of a 'statement
zerny-google 2012/10/29 16:44:25 Done.
39
28 DECLARE_FLAG(bool, print_flow_graph); 40 DECLARE_FLAG(bool, print_flow_graph);
29 DECLARE_FLAG(int, deoptimization_counter_threshold); 41 DECLARE_FLAG(int, deoptimization_counter_threshold);
30 DECLARE_FLAG(bool, verify_compiler); 42 DECLARE_FLAG(bool, verify_compiler);
31 DECLARE_FLAG(bool, compiler_stats); 43 DECLARE_FLAG(bool, compiler_stats);
32 DECLARE_FLAG(bool, reject_named_argument_as_positional); 44 DECLARE_FLAG(bool, reject_named_argument_as_positional);
33 45
34 #define TRACE_INLINING(statement) \ 46 #define TRACE_INLINING(statement) \
35 do { \ 47 do { \
36 if (FLAG_trace_inlining) statement; \ 48 if (FLAG_trace_inlining) statement; \
37 } while (false) 49 } while (false)
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 // Pair of an argument name and its value. 133 // Pair of an argument name and its value.
122 struct NamedArgument : ValueObject { 134 struct NamedArgument : ValueObject {
123 public: 135 public:
124 String* name; 136 String* name;
125 Value* value; 137 Value* value;
126 NamedArgument(String* name, Value* value) 138 NamedArgument(String* name, Value* value)
127 : name(name), value(value) { } 139 : name(name), value(value) { }
128 }; 140 };
129 141
130 142
143 // Helper to collect information about a callee graph.
srdjan 2012/10/25 20:38:50 about inlineable callee graphs
zerny-google 2012/10/29 16:44:25 Done.
144 class GraphInfoCollector : public ValueObject {
145 public:
146 explicit GraphInfoCollector()
srdjan 2012/10/25 20:38:50 remove explicit
zerny-google 2012/10/29 16:44:25 Done.
147 : call_site_count_(0),
148 instruction_count_(0) { }
149
150 void Collect(const FlowGraph& graph) {
151 call_site_count_ = 0;
152 instruction_count_ = 0;
153 for (BlockIterator block_it = graph.postorder_iterator();
154 !block_it.Done();
155 block_it.Advance()) {
156 for (ForwardInstructionIterator it(block_it.Current());
157 !it.Done();
158 it.Advance()) {
159 ++instruction_count_;
160 if (it.Current()->IsStaticCall() ||
161 it.Current()->IsClosureCall() ||
162 it.Current()->IsPolymorphicInstanceCall()) {
163 ++call_site_count_;
164 }
165 }
166 }
167 }
168
169 intptr_t call_site_count() const { return call_site_count_; }
170 intptr_t instruction_count() const { return instruction_count_; }
171
172 private:
173 intptr_t call_site_count_;
174 intptr_t instruction_count_;
175 };
176
177
131 // A collection of call sites to consider for inlining. 178 // A collection of call sites to consider for inlining.
132 class CallSites : public FlowGraphVisitor { 179 class CallSites : public FlowGraphVisitor {
133 public: 180 public:
134 explicit CallSites(FlowGraph* flow_graph) 181 explicit CallSites(FlowGraph* flow_graph)
135 : FlowGraphVisitor(flow_graph->postorder()), // We don't use this order. 182 : FlowGraphVisitor(flow_graph->postorder()), // We don't use this order.
136 static_calls_(), 183 static_calls_(),
137 closure_calls_(), 184 closure_calls_(),
138 instance_calls_() { } 185 instance_calls_() { }
139 186
140 GrowableArray<StaticCallInstr*>* static_calls() { 187 GrowableArray<StaticCallInstr*>* static_calls() {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 : caller_graph_(flow_graph), 247 : caller_graph_(flow_graph),
201 next_ssa_temp_index_(flow_graph->max_virtual_register_number()), 248 next_ssa_temp_index_(flow_graph->max_virtual_register_number()),
202 inlined_(false), 249 inlined_(false),
203 initial_size_(flow_graph->InstructionCount()), 250 initial_size_(flow_graph->InstructionCount()),
204 inlined_size_(0), 251 inlined_size_(0),
205 inlining_depth_(1), 252 inlining_depth_(1),
206 collected_call_sites_(NULL), 253 collected_call_sites_(NULL),
207 inlining_call_sites_(NULL), 254 inlining_call_sites_(NULL),
208 function_cache_() { } 255 function_cache_() { }
209 256
257 // Inlining heuristics based on Cooper et al. 2008.
258 bool ShouldWeInline(intptr_t loop_depth,
259 intptr_t size,
srdjan 2012/10/25 20:38:50 Size of what? Please name better
zerny-google 2012/10/29 16:44:25 s/size/instr_count
260 intptr_t call_sites,
srdjan 2012/10/25 20:38:50 num_call_sites?
zerny-google 2012/10/29 16:44:25 s/call_sites/call_site_count
261 intptr_t constant_args) {
262 if (size <= FLAG_inlining_size_threshold) {
263 return true;
264 }
265 if (call_sites <= FLAG_inlining_callee_call_sites_threshold) {
266 return true;
267 }
268 if ((loop_depth > 0) && (size <= FLAG_inlining_in_loop_size_threshold)) {
269 return true;
270 }
271 if ((constant_args >= FLAG_inlining_constant_arguments_count) &&
272 (size <= FLAG_inlining_constant_arguments_size_threshold)) {
273 return true;
274 }
275 return false;
276 }
277
210 void InlineCalls() { 278 void InlineCalls() {
211 // If inlining depth is less then one abort. 279 // If inlining depth is less then one abort.
212 if (FLAG_inlining_depth_threshold < 1) return; 280 if (FLAG_inlining_depth_threshold < 1) return;
213 // Create two call site collections to swap between. 281 // Create two call site collections to swap between.
214 CallSites sites1(caller_graph_); 282 CallSites sites1(caller_graph_);
215 CallSites sites2(caller_graph_); 283 CallSites sites2(caller_graph_);
216 CallSites* call_sites_temp = NULL; 284 CallSites* call_sites_temp = NULL;
217 collected_call_sites_ = &sites1; 285 collected_call_sites_ = &sites1;
218 inlining_call_sites_ = &sites2; 286 inlining_call_sites_ = &sites2;
219 // Collect initial call sites. 287 // Collect initial call sites.
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
281 } 349 }
282 350
283 // Abort if we are running legacy support for optional parameters. 351 // Abort if we are running legacy support for optional parameters.
284 if (!FLAG_reject_named_argument_as_positional && 352 if (!FLAG_reject_named_argument_as_positional &&
285 function.HasOptionalPositionalParameters() && 353 function.HasOptionalPositionalParameters() &&
286 (!argument_names.IsNull() && (argument_names.Length() > 0))) { 354 (!argument_names.IsNull() && (argument_names.Length() > 0))) {
287 function.set_is_inlinable(false); 355 function.set_is_inlinable(false);
288 TRACE_INLINING(OS::Print( 356 TRACE_INLINING(OS::Print(
289 " Bailout: named optional positional parameter\n")); 357 " Bailout: named optional positional parameter\n"));
290 return false; 358 return false;
291 } 359 }
srdjan 2012/10/25 20:38:50 Could you use a modified inlining_size_threshold v
Kevin Millikin (Google) 2012/10/26 12:07:22 We could definitely do that. In fact, we could ca
zerny-google 2012/10/29 16:44:25 The is_inlinable bit approximated this (line 479),
292 360
293 Isolate* isolate = Isolate::Current(); 361 Isolate* isolate = Isolate::Current();
294 // Save and clear IC data. 362 // Save and clear IC data.
295 const Array& prev_ic_data = Array::Handle(isolate->ic_data_array()); 363 const Array& prev_ic_data = Array::Handle(isolate->ic_data_array());
296 isolate->set_ic_data_array(Array::null()); 364 isolate->set_ic_data_array(Array::null());
297 // Save and clear deopt id. 365 // Save and clear deopt id.
298 const intptr_t prev_deopt_id = isolate->deopt_id(); 366 const intptr_t prev_deopt_id = isolate->deopt_id();
299 isolate->set_deopt_id(0); 367 isolate->set_deopt_id(0);
300 // Install bailout jump. 368 // Install bailout jump.
301 LongJump* base = isolate->long_jump_base(); 369 LongJump* base = isolate->long_jump_base();
(...skipping 11 matching lines...) Expand all
313 } 381 }
314 382
315 // Load IC data for the callee. 383 // Load IC data for the callee.
316 if (function.HasCode()) { 384 if (function.HasCode()) {
317 const Code& unoptimized_code = 385 const Code& unoptimized_code =
318 Code::Handle(function.unoptimized_code()); 386 Code::Handle(function.unoptimized_code());
319 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray()); 387 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray());
320 } 388 }
321 389
322 // Build the callee graph. 390 // Build the callee graph.
391 const intptr_t loop_depth = call->GetBlock()->loop_depth();
323 FlowGraphBuilder builder(*parsed_function); 392 FlowGraphBuilder builder(*parsed_function);
324 builder.SetInitialBlockId(caller_graph_->max_block_id()); 393 builder.SetInitialBlockId(caller_graph_->max_block_id());
325 FlowGraph* callee_graph; 394 FlowGraph* callee_graph;
326 { 395 {
327 TimerScope timer(FLAG_compiler_stats, 396 TimerScope timer(FLAG_compiler_stats,
328 &CompilerStats::graphinliner_build_timer, 397 &CompilerStats::graphinliner_build_timer,
329 isolate); 398 isolate);
330 callee_graph = builder.BuildGraph(FlowGraphBuilder::kValueContext); 399 callee_graph =
400 builder.BuildGraph(FlowGraphBuilder::kValueContext, loop_depth);
331 } 401 }
332 402
333 // The parameter stubs are a copy of the actual arguments providing 403 // The parameter stubs are a copy of the actual arguments providing
334 // concrete information about the values, for example constant values, 404 // concrete information about the values, for example constant values,
335 // without linking between the caller and callee graphs. 405 // without linking between the caller and callee graphs.
336 // TODO(zerny): Put more information in the stubs, eg, type information. 406 // TODO(zerny): Put more information in the stubs, eg, type information.
337 GrowableArray<Definition*> param_stubs(function.NumParameters()); 407 GrowableArray<Definition*> param_stubs(function.NumParameters());
338 408
339 // Create a parameter stub for each fixed positional parameter. 409 // Create a parameter stub for each fixed positional parameter.
340 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { 410 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) {
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
385 callee_graph->ComputeUseLists(); 455 callee_graph->ComputeUseLists();
386 } 456 }
387 457
388 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 458 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
389 OS::Print("Callee graph for inlining %s\n", 459 OS::Print("Callee graph for inlining %s\n",
390 function.ToFullyQualifiedCString()); 460 function.ToFullyQualifiedCString());
391 FlowGraphPrinter printer(*callee_graph); 461 FlowGraphPrinter printer(*callee_graph);
392 printer.PrintBlocks(); 462 printer.PrintBlocks();
393 } 463 }
394 464
395 // If result is more than size threshold then abort. 465 // Collect information about the call site and caller graph.
396 // TODO(zerny): Do this after CP and dead code elimination. 466 // TODO(zerny): Do this after CP and dead code elimination.
397 intptr_t size = callee_graph->InstructionCount(); 467 intptr_t constants_count = 0;
398 if (size > FLAG_inlining_size_threshold) { 468 for (intptr_t i = 0; i < param_stubs.length(); ++i) {
399 function.set_is_inlinable(false); 469 if (param_stubs[i]->IsConstant()) ++constants_count;
470 }
471 GraphInfoCollector info;
472 info.Collect(*callee_graph);
473 const intptr_t size = info.instruction_count();
474 // Use heuristics do decide if this call should be inlined.
475 if (!ShouldWeInline(loop_depth,
476 size,
477 info.call_site_count(),
478 constants_count)) {
479 // If size is larger than all thresholds, don't consider it again.
480 if ((size > FLAG_inlining_size_threshold) &&
481 (size > FLAG_inlining_in_loop_size_threshold) &&
482 (size > FLAG_inlining_callee_call_sites_threshold) &&
483 (size > FLAG_inlining_constant_arguments_size_threshold)) {
484 function.set_is_inlinable(false);
485 }
400 isolate->set_long_jump_base(base); 486 isolate->set_long_jump_base(base);
401 isolate->set_deopt_id(prev_deopt_id); 487 isolate->set_deopt_id(prev_deopt_id);
402 isolate->set_ic_data_array(prev_ic_data.raw()); 488 isolate->set_ic_data_array(prev_ic_data.raw());
403 TRACE_INLINING(OS::Print(" Bailout: graph size %"Pd"\n", size)); 489 TRACE_INLINING(OS::Print(" Bailout: heuristics with "
490 "loop depth: %"Pd", "
491 "code size: %"Pd", "
492 "call sites: %"Pd", "
493 "const args: %"Pd"\n",
494 loop_depth,
495 size,
496 info.call_site_count(),
497 constants_count));
404 return false; 498 return false;
405 } 499 }
406 500
407 // If depth is less or equal to threshold recursively add call sites. 501 // If depth is less or equal to threshold recursively add call sites.
408 if (inlining_depth_ < FLAG_inlining_depth_threshold) { 502 if (inlining_depth_ < FLAG_inlining_depth_threshold) {
409 collected_call_sites_->FindCallSites(callee_graph); 503 collected_call_sites_->FindCallSites(callee_graph);
410 } 504 }
411 505
412 { 506 {
413 TimerScope timer(FLAG_compiler_stats, 507 TimerScope timer(FLAG_compiler_stats,
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after
696 OS::Print("After Inlining of %s\n", flow_graph_-> 790 OS::Print("After Inlining of %s\n", flow_graph_->
697 parsed_function().function().ToFullyQualifiedCString()); 791 parsed_function().function().ToFullyQualifiedCString());
698 FlowGraphPrinter printer(*flow_graph_); 792 FlowGraphPrinter printer(*flow_graph_);
699 printer.PrintBlocks(); 793 printer.PrintBlocks();
700 } 794 }
701 } 795 }
702 } 796 }
703 } 797 }
704 798
705 } // namespace dart 799 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698