001/* 002 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.phases.common; 024 025import java.util.*; 026 027import com.oracle.graal.compiler.common.cfg.*; 028import com.oracle.graal.graph.*; 029import com.oracle.graal.nodes.*; 030import com.oracle.graal.nodes.calc.*; 031import com.oracle.graal.nodes.cfg.*; 032import com.oracle.graal.nodes.debug.*; 033import com.oracle.graal.nodes.extended.*; 034import com.oracle.graal.nodes.java.*; 035import com.oracle.graal.nodes.memory.*; 036import com.oracle.graal.nodes.spi.*; 037import com.oracle.graal.nodes.virtual.*; 038import com.oracle.graal.phases.*; 039import com.oracle.graal.phases.schedule.*; 040 041/** 042 * This phase add counters for the dynamically executed number of nodes. Incrementing the counter 043 * for each node would be too costly, so this phase takes the compromise that it trusts split 044 * probabilities, but not loop frequencies. This means that it will insert counters at the start of 045 * a method and at each loop header. 046 * 047 * A schedule is created so that floating nodes can also be taken into account. The weight of a node 048 * is determined heuristically in the {@link ProfileCompiledMethodsPhase#getNodeWeight(Node)} 049 * method. 050 * 051 * Additionally, there's a second counter that's only increased for code sections without invokes. 052 */ 053public class ProfileCompiledMethodsPhase extends Phase { 054 055 private static final String GROUP_NAME = "~profiled weight"; 056 private static final String GROUP_NAME_WITHOUT = "~profiled weight (invoke-free sections)"; 057 private static final String GROUP_NAME_INVOKES = "~profiled invokes"; 058 059 private static final boolean WITH_SECTION_HEADER = Boolean.parseBoolean(System.getProperty("ProfileCompiledMethodsPhase.WITH_SECTION_HEADER", "false")); 060 private static final boolean WITH_INVOKE_FREE_SECTIONS = Boolean.parseBoolean(System.getProperty("ProfileCompiledMethodsPhase.WITH_FREE_SECTIONS", "false")); 061 private static final boolean WITH_INVOKES = Boolean.parseBoolean(System.getProperty("ProfileCompiledMethodsPhase.WITH_INVOKES", "true")); 062 063 @Override 064 protected void run(StructuredGraph graph) { 065 SchedulePhase schedule = new SchedulePhase(); 066 schedule.apply(graph, false); 067 068 ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true); 069 for (Loop<Block> loop : cfg.getLoops()) { 070 double loopProbability = cfg.blockFor(loop.getHeader().getBeginNode()).probability(); 071 if (loopProbability > (1D / Integer.MAX_VALUE)) { 072 addSectionCounters(loop.getHeader().getBeginNode(), loop.getBlocks(), loop.getChildren(), schedule, cfg); 073 } 074 } 075 // don't put the counter increase directly after the start (problems with OSR) 076 FixedWithNextNode current = graph.start(); 077 while (current.next() instanceof FixedWithNextNode) { 078 current = (FixedWithNextNode) current.next(); 079 } 080 addSectionCounters(current, cfg.getBlocks(), cfg.getLoops(), schedule, cfg); 081 082 if (WITH_INVOKES) { 083 for (Node node : graph.getNodes()) { 084 if (node instanceof Invoke) { 085 Invoke invoke = (Invoke) node; 086 DynamicCounterNode.addCounterBefore(GROUP_NAME_INVOKES, invoke.callTarget().targetName(), 1, true, invoke.asNode()); 087 088 } 089 } 090 } 091 } 092 093 private static void addSectionCounters(FixedWithNextNode start, Collection<Block> sectionBlocks, Collection<Loop<Block>> childLoops, SchedulePhase schedule, ControlFlowGraph cfg) { 094 HashSet<Block> blocks = new HashSet<>(sectionBlocks); 095 for (Loop<?> loop : childLoops) { 096 blocks.removeAll(loop.getBlocks()); 097 } 098 double weight = getSectionWeight(schedule, blocks) / cfg.blockFor(start).probability(); 099 DynamicCounterNode.addCounterBefore(GROUP_NAME, sectionHead(start), (long) weight, true, start.next()); 100 if (WITH_INVOKE_FREE_SECTIONS && !hasInvoke(blocks)) { 101 DynamicCounterNode.addCounterBefore(GROUP_NAME_WITHOUT, sectionHead(start), (long) weight, true, start.next()); 102 } 103 } 104 105 private static String sectionHead(Node node) { 106 if (WITH_SECTION_HEADER) { 107 return node.toString(); 108 } else { 109 return ""; 110 } 111 } 112 113 private static double getSectionWeight(SchedulePhase schedule, Collection<Block> blocks) { 114 double count = 0; 115 for (Block block : blocks) { 116 double blockProbability = block.probability(); 117 for (Node node : schedule.getBlockToNodesMap().get(block)) { 118 count += blockProbability * getNodeWeight(node); 119 } 120 } 121 return count; 122 } 123 124 private static double getNodeWeight(Node node) { 125 if (node instanceof AbstractMergeNode) { 126 return ((AbstractMergeNode) node).phiPredecessorCount(); 127 } else if (node instanceof AbstractBeginNode || node instanceof AbstractEndNode || node instanceof MonitorIdNode || node instanceof ConstantNode || node instanceof ParameterNode || 128 node instanceof CallTargetNode || node instanceof ValueProxy || node instanceof VirtualObjectNode || node instanceof ReinterpretNode) { 129 return 0; 130 } else if (node instanceof AccessMonitorNode) { 131 return 10; 132 } else if (node instanceof Access) { 133 return 2; 134 } else if (node instanceof LogicNode || node instanceof ConvertNode || node instanceof BinaryNode || node instanceof NotNode) { 135 return 1; 136 } else if (node instanceof IntegerDivNode || node instanceof DivNode || node instanceof IntegerRemNode || node instanceof RemNode) { 137 return 10; 138 } else if (node instanceof MulNode) { 139 return 3; 140 } else if (node instanceof Invoke) { 141 return 5; 142 } else if (node instanceof IfNode || node instanceof SafepointNode) { 143 return 1; 144 } else if (node instanceof SwitchNode) { 145 return node.successors().count(); 146 } else if (node instanceof ReturnNode || node instanceof UnwindNode || node instanceof DeoptimizeNode) { 147 return node.successors().count(); 148 } else if (node instanceof AbstractNewObjectNode) { 149 return 10; 150 } else if (node instanceof VirtualState) { 151 return 0; 152 } 153 return 2; 154 } 155 156 private static boolean hasInvoke(Collection<Block> blocks) { 157 boolean hasInvoke = false; 158 for (Block block : blocks) { 159 for (FixedNode fixed : block.getNodes()) { 160 if (fixed instanceof Invoke) { 161 hasInvoke = true; 162 } 163 } 164 } 165 return hasInvoke; 166 } 167}