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

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

Issue 17646002: Use call counts to determine which static calls to inline. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 6 months 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 | « runtime/vm/flow_graph_builder.cc ('k') | runtime/vm/intermediate_language.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) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 // A collection of call sites to consider for inlining. 182 // A collection of call sites to consider for inlining.
183 class CallSites : public FlowGraphVisitor { 183 class CallSites : public FlowGraphVisitor {
184 public: 184 public:
185 explicit CallSites(FlowGraph* flow_graph) 185 explicit CallSites(FlowGraph* flow_graph)
186 : FlowGraphVisitor(flow_graph->postorder()), // We don't use this order. 186 : FlowGraphVisitor(flow_graph->postorder()), // We don't use this order.
187 static_calls_(), 187 static_calls_(),
188 closure_calls_(), 188 closure_calls_(),
189 instance_calls_(), 189 instance_calls_(),
190 skip_static_call_deopt_ids_() { } 190 skip_static_call_deopt_ids_() { }
191 191
192 const GrowableArray<StaticCallInstr*>& static_calls() const {
193 return static_calls_;
194 }
195
196 const GrowableArray<ClosureCallInstr*>& closure_calls() const { 192 const GrowableArray<ClosureCallInstr*>& closure_calls() const {
197 return closure_calls_; 193 return closure_calls_;
198 } 194 }
199 195
200 struct InstanceCallInfo { 196 struct InstanceCallInfo {
201 PolymorphicInstanceCallInstr* call; 197 PolymorphicInstanceCallInstr* call;
202 double ratio; 198 double ratio;
203 explicit InstanceCallInfo(PolymorphicInstanceCallInstr* call_arg) 199 explicit InstanceCallInfo(PolymorphicInstanceCallInstr* call_arg)
204 : call(call_arg), ratio(0.0) {} 200 : call(call_arg), ratio(0.0) {}
205 }; 201 };
206 202
203 struct StaticCallInfo {
204 StaticCallInstr* call;
205 double ratio;
206 explicit StaticCallInfo(StaticCallInstr* value)
207 : call(value), ratio(0.0) {}
208 };
209
207 const GrowableArray<InstanceCallInfo>& instance_calls() const { 210 const GrowableArray<InstanceCallInfo>& instance_calls() const {
208 return instance_calls_; 211 return instance_calls_;
209 } 212 }
210 213
214 const GrowableArray<StaticCallInfo>& static_calls() const {
215 return static_calls_;
216 }
217
211 bool HasCalls() const { 218 bool HasCalls() const {
212 return !(static_calls_.is_empty() && 219 return !(static_calls_.is_empty() &&
213 closure_calls_.is_empty() && 220 closure_calls_.is_empty() &&
214 instance_calls_.is_empty()); 221 instance_calls_.is_empty());
215 } 222 }
216 223
217 void Clear() { 224 void Clear() {
218 static_calls_.Clear(); 225 static_calls_.Clear();
219 closure_calls_.Clear(); 226 closure_calls_.Clear();
220 instance_calls_.Clear(); 227 instance_calls_.Clear();
221 skip_static_call_deopt_ids_.Clear(); 228 skip_static_call_deopt_ids_.Clear();
222 } 229 }
223 230
231 void ComputeCallSiteRatio(intptr_t static_call_start_ix,
232 intptr_t instance_call_start_ix) {
233 const intptr_t num_static_calls =
234 static_calls_.length() - static_call_start_ix;
235 const intptr_t num_instance_calls =
236 instance_calls_.length() - instance_call_start_ix;
237
238 intptr_t max_count = 0;
239 GrowableArray<intptr_t> instance_call_counts(num_instance_calls);
240 for (intptr_t i = 0; i < num_instance_calls; ++i) {
241 const intptr_t aggregate_count =
242 instance_calls_[i + instance_call_start_ix].
243 call->ic_data().AggregateCount();
244 instance_call_counts.Add(aggregate_count);
245 if (aggregate_count > max_count) max_count = aggregate_count;
246 }
247
248 GrowableArray<intptr_t> static_call_counts(num_static_calls);
249 for (intptr_t i = 0; i < num_static_calls; ++i) {
250 const intptr_t aggregate_count =
251 static_calls_[i + static_call_start_ix].
252 call->ic_data()->AggregateCount();
253 static_call_counts.Add(aggregate_count);
254 if (aggregate_count > max_count) max_count = aggregate_count;
255 }
256
257 for (intptr_t i = 0; i < num_instance_calls; ++i) {
258 const double ratio =
259 static_cast<double>(instance_call_counts[i]) / max_count;
260 instance_calls_[i + instance_call_start_ix].ratio = ratio;
261 }
262 for (intptr_t i = 0; i < num_static_calls; ++i) {
263 const double ratio =
264 static_cast<double>(static_call_counts[i]) / max_count;
265 static_calls_[i + static_call_start_ix].ratio = ratio;
266 }
267 }
268
224 void FindCallSites(FlowGraph* graph) { 269 void FindCallSites(FlowGraph* graph) {
225 ASSERT(graph != NULL); 270 ASSERT(graph != NULL);
226 const Function& function = graph->parsed_function().function(); 271 const Function& function = graph->parsed_function().function();
227 ASSERT(function.HasCode()); 272 ASSERT(function.HasCode());
228 const Code& code = Code::Handle(function.unoptimized_code()); 273 const Code& code = Code::Handle(function.unoptimized_code());
229 274
230 skip_static_call_deopt_ids_.Clear(); 275 skip_static_call_deopt_ids_.Clear();
231 code.ExtractUncalledStaticCallDeoptIds(&skip_static_call_deopt_ids_); 276 code.ExtractUncalledStaticCallDeoptIds(&skip_static_call_deopt_ids_);
232 277
233 const intptr_t instance_call_start_ix = instance_calls_.length(); 278 const intptr_t instance_call_start_ix = instance_calls_.length();
279 const intptr_t static_call_start_ix = static_calls_.length();
234 for (BlockIterator block_it = graph->postorder_iterator(); 280 for (BlockIterator block_it = graph->postorder_iterator();
235 !block_it.Done(); 281 !block_it.Done();
236 block_it.Advance()) { 282 block_it.Advance()) {
237 for (ForwardInstructionIterator it(block_it.Current()); 283 for (ForwardInstructionIterator it(block_it.Current());
238 !it.Done(); 284 !it.Done();
239 it.Advance()) { 285 it.Advance()) {
240 it.Current()->Accept(this); 286 it.Current()->Accept(this);
241 } 287 }
242 } 288 }
243 // Compute instance call site ratio. 289 ComputeCallSiteRatio(static_call_start_ix, instance_call_start_ix);
244 const intptr_t num_instance_calls =
245 instance_calls_.length() - instance_call_start_ix;
246 intptr_t max_count = 0;
247 GrowableArray<intptr_t> call_counts(num_instance_calls);
248 for (intptr_t i = 0; i < num_instance_calls; ++i) {
249 const intptr_t aggregate_count =
250 instance_calls_[i + instance_call_start_ix].
251 call->ic_data().AggregateCount();
252 call_counts.Add(aggregate_count);
253 if (aggregate_count > max_count) max_count = aggregate_count;
254 }
255
256
257 for (intptr_t i = 0; i < num_instance_calls; ++i) {
258 const double ratio = static_cast<double>(call_counts[i]) / max_count;
259 instance_calls_[i + instance_call_start_ix].ratio = ratio;
260 }
261 } 290 }
262 291
263 void VisitClosureCall(ClosureCallInstr* call) { 292 void VisitClosureCall(ClosureCallInstr* call) {
264 closure_calls_.Add(call); 293 closure_calls_.Add(call);
265 } 294 }
266 295
267 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) { 296 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) {
268 instance_calls_.Add(InstanceCallInfo(call)); 297 instance_calls_.Add(InstanceCallInfo(call));
269 } 298 }
270 299
271 void VisitStaticCall(StaticCallInstr* call) { 300 void VisitStaticCall(StaticCallInstr* call) {
272 if (!call->function().IsInlineable()) return; 301 if (!call->function().IsInlineable()) return;
273 const intptr_t call_deopt_id = call->deopt_id(); 302 const intptr_t call_deopt_id = call->deopt_id();
274 for (intptr_t i = 0; i < skip_static_call_deopt_ids_.length(); i++) { 303 for (intptr_t i = 0; i < skip_static_call_deopt_ids_.length(); i++) {
275 if (call_deopt_id == skip_static_call_deopt_ids_[i]) { 304 if (call_deopt_id == skip_static_call_deopt_ids_[i]) {
276 // Do not inline this call. 305 // Do not inline this call.
277 return; 306 return;
278 } 307 }
279 } 308 }
280 static_calls_.Add(call); 309 static_calls_.Add(StaticCallInfo(call));
281 } 310 }
282 311
283 private: 312 private:
284 GrowableArray<StaticCallInstr*> static_calls_; 313 GrowableArray<StaticCallInfo> static_calls_;
285 GrowableArray<ClosureCallInstr*> closure_calls_; 314 GrowableArray<ClosureCallInstr*> closure_calls_;
286 GrowableArray<InstanceCallInfo> instance_calls_; 315 GrowableArray<InstanceCallInfo> instance_calls_;
287 GrowableArray<intptr_t> skip_static_call_deopt_ids_; 316 GrowableArray<intptr_t> skip_static_call_deopt_ids_;
288 317
289 DISALLOW_COPY_AND_ASSIGN(CallSites); 318 DISALLOW_COPY_AND_ASSIGN(CallSites);
290 }; 319 };
291 320
292 321
293 struct InlinedCallData { 322 struct InlinedCallData {
294 InlinedCallData(Definition* call, GrowableArray<Value*>* arguments) 323 InlinedCallData(Definition* call, GrowableArray<Value*>* arguments)
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after
706 ParsedFunction* parsed_function = new ParsedFunction(function); 735 ParsedFunction* parsed_function = new ParsedFunction(function);
707 Parser::ParseFunction(parsed_function); 736 Parser::ParseFunction(parsed_function);
708 parsed_function->AllocateVariables(); 737 parsed_function->AllocateVariables();
709 return parsed_function; 738 return parsed_function;
710 } 739 }
711 740
712 // Include special handling for List. factory: inlining it is not helpful 741 // Include special handling for List. factory: inlining it is not helpful
713 // if the incoming argument is a non-constant value. 742 // if the incoming argument is a non-constant value.
714 // TODO(srdjan): Fix inlining of List. factory. 743 // TODO(srdjan): Fix inlining of List. factory.
715 void InlineStaticCalls() { 744 void InlineStaticCalls() {
716 const GrowableArray<StaticCallInstr*>& calls = 745 const GrowableArray<CallSites::StaticCallInfo>& call_info =
717 inlining_call_sites_->static_calls(); 746 inlining_call_sites_->static_calls();
718 TRACE_INLINING(OS::Print(" Static Calls (%d)\n", calls.length())); 747 TRACE_INLINING(OS::Print(" Static Calls (%d)\n", call_info.length()));
719 for (intptr_t i = 0; i < calls.length(); ++i) { 748 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) {
720 StaticCallInstr* call = calls[i]; 749 StaticCallInstr* call = call_info[call_idx].call;
721 if (call->function().name() == Symbols::ListFactory().raw()) { 750 if (call->function().name() == Symbols::ListFactory().raw()) {
722 // Inline only if no arguments or a constant was passed. 751 // Inline only if no arguments or a constant was passed.
723 ASSERT(call->function().NumImplicitParameters() == 1); 752 ASSERT(call->function().NumImplicitParameters() == 1);
724 ASSERT(call->ArgumentCount() <= 2); 753 ASSERT(call->ArgumentCount() <= 2);
725 // Arg 0: Instantiator type arguments. 754 // Arg 0: Instantiator type arguments.
726 // Arg 1: Length (optional). 755 // Arg 1: Length (optional).
727 if ((call->ArgumentCount() == 2) && 756 if ((call->ArgumentCount() == 2) &&
728 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { 757 (!call->PushArgumentAt(1)->value()->BindsToConstant())) {
729 // Do not inline since a non-constant argument was passed. 758 // Do not inline since a non-constant argument was passed.
730 continue; 759 continue;
731 } 760 }
732 } 761 }
762 if ((call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
Florian Schneider 2013/06/25 08:48:32 Maybe we need to adapt the threshold now that stat
763 const Function& target = call->function();
764 TRACE_INLINING(OS::Print(
765 " => %s (deopt count %d)\n Bailout: cold %f\n",
766 target.ToCString(),
767 target.deoptimization_counter(),
768 call_info[call_idx].ratio));
769 continue;
770 }
733 GrowableArray<Value*> arguments(call->ArgumentCount()); 771 GrowableArray<Value*> arguments(call->ArgumentCount());
734 for (int i = 0; i < call->ArgumentCount(); ++i) { 772 for (int i = 0; i < call->ArgumentCount(); ++i) {
735 arguments.Add(call->PushArgumentAt(i)->value()); 773 arguments.Add(call->PushArgumentAt(i)->value());
736 } 774 }
737 InlinedCallData call_data(call, &arguments); 775 InlinedCallData call_data(call, &arguments);
738 if (TryInlining(call->function(), call->argument_names(), &call_data)) { 776 if (TryInlining(call->function(), call->argument_names(), &call_data)) {
739 InlineCall(&call_data); 777 InlineCall(&call_data);
740 } 778 }
741 } 779 }
742 } 780 }
(...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after
1343 OS::Print("After Inlining of %s\n", flow_graph_-> 1381 OS::Print("After Inlining of %s\n", flow_graph_->
1344 parsed_function().function().ToFullyQualifiedCString()); 1382 parsed_function().function().ToFullyQualifiedCString());
1345 FlowGraphPrinter printer(*flow_graph_); 1383 FlowGraphPrinter printer(*flow_graph_);
1346 printer.PrintBlocks(); 1384 printer.PrintBlocks();
1347 } 1385 }
1348 } 1386 }
1349 } 1387 }
1350 } 1388 }
1351 1389
1352 } // namespace dart 1390 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_builder.cc ('k') | runtime/vm/intermediate_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698