blob: b083b2a51dfe8cd8b3f5ea853d7b4357f0338f79 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* COPYRIGHT_NOTICE */
/**
* @author Jack Liu, Mikhail Y. Fursov, Chen-Dong Yuan
*/
#include "EMInterface.h"
#include "Jitrino.h"
#include "Inst.h"
#include "Stl.h"
#include "StaticProfiler.h"
#include "Dominator.h"
#include "Loop.h"
#include "FlowGraph.h"
#include <string.h>
#include <stdio.h>
#include <limits.h>
#include <sstream>
namespace Jitrino {
#define MAX(a, b) ((a)>(b)?a:b)
static bool isMethodTrivial( ControlFlowGraph& cfg );
static void checkBCMapping( ControlFlowGraph& cfg );
static U_32 computeCheckSum( MemoryManager& mm, IRManager& irm, const StlSet<Node*>& nodesToIgnore, bool bcLevel);
static bool calculateProbsFromProfile(MemoryManager& mm, ControlFlowGraph& fg, const Edges& edges, DominatorTree* dt, LoopTree* lt, EdgeMethodProfile* profile, bool bcLevelProfiling, const StlSet<Node*>& nodesToIgnore);
static Node* selectNodeToInstrument(IRManager& irm, Edge* edge);
static void selectEdgesToInstrument(MemoryManager& mm, IRManager& irm, Edges& result, const StlSet<Node*>& nodesToIgnore, bool bcLevel);
static U_32 genKey( U_32 n, Edge* edge, bool bcLevel, bool debug);
static bool hasCatch( Node* node );
static void selectNodesToIgnore(IRManager& irm, LoopTree* lt, StlSet<Node*>& result, bool bcLevel);
class EdgeProfileFlags {
public:
bool bcLevelProfiling;
EdgeProfileFlags() : bcLevelProfiling(false) {}
};
class EdgeProfilerAction : public Action {
public:
void init() {
flags.bcLevelProfiling = getBoolArg("bcLevel", false);
}
const EdgeProfileFlags& getFlags() {return flags;}
protected:
EdgeProfileFlags flags;
};
DEFINE_SESSION_ACTION_WITH_ACTION(EdgeProfilerInstrumentationPass, EdgeProfilerAction, edge_instrument, "Perform edge instrumentation pass")
void EdgeProfilerInstrumentationPass::_run(IRManager& irm)
{
ControlFlowGraph& flowGraph = irm.getFlowGraph();
MemoryManager mm("Edge InstrumentationPass");
MethodDesc& md = irm.getMethodDesc();
InstFactory& instFactory = irm.getInstFactory();
EdgeProfilerAction* action = (EdgeProfilerAction*)getAction();
const EdgeProfileFlags& flags = action->getFlags();
bool debug = Log::isEnabled();
if (debug) {
Log::out()<<"EdgeProfilerInstrumentationPass. BcLevel="<<flags.bcLevelProfiling<<std::endl;
}
if (flags.bcLevelProfiling) {
checkBCMapping(flowGraph);
}
OptPass::computeDominatorsAndLoops(irm);
LogStream& irdump = log(LogStream::IRDUMP);
if (irdump.isEnabled()) {
printHIR(irm, "IR before instrumentation");
}
LoopTree* lt = irm.getLoopTree();
//set of nodes with out-edges are not taken into account during instrumentation
//and checksum calculation
//such nodes are optional in CFG. E.g. nodes with class initializers insts
StlSet<Node*> nodesToIgnore(mm);
selectNodesToIgnore(irm, lt, nodesToIgnore, flags.bcLevelProfiling);
//compute checksum first
U_32 _checkSum = computeCheckSum(mm, irm, nodesToIgnore, flags.bcLevelProfiling);
StlVector<U_32> counterKeys(mm);
// Instrument method entry first.
Node* entryNode = flowGraph.getEntryNode();
entryNode->prependInst(instFactory.makeIncCounter(0));
bool methodIsTrivial = isMethodTrivial(flowGraph);
if (!methodIsTrivial) {
// Scan the CFG node in topological order and record the blocks and
// edges where we need to add instrumentation code.
// The actual instrumentation will be done in a separate phase so that
// we won't disturb the CFG as we are traversing it.
Edges edgesToInstrument(mm);
selectEdgesToInstrument(mm, irm, edgesToInstrument, nodesToIgnore, flags.bcLevelProfiling);
//compute edge-ids before CFG modification: edge-ids are part of CFG consistency check.
for (Edges::const_iterator it = edgesToInstrument.begin(), end = edgesToInstrument.end(); it!=end; ++it) {
Edge* edge = *it;
U_32 key = genKey((U_32)counterKeys.size() + 1, edge, flags.bcLevelProfiling, debug);
assert( key != 0 );
counterKeys.push_back(key);
}
// Now revisit all of the edges that need to be instrumented
// and generate instrumentation code.
U_32 i = 0;
for (Edges::const_iterator it = edgesToInstrument.begin(), end = edgesToInstrument.end(); it!=end; ++it, ++i) {
Edge* edge = *it;
Node* nodeToInstrument = selectNodeToInstrument(irm, edge);
assert(nodeToInstrument!=NULL && nodeToInstrument->isBlockNode());
U_32 key = counterKeys[i];
Inst* incInst = instFactory.makeIncCounter( key );
assert(((Inst*)nodeToInstrument->getFirstInst())->getOpcode() != Op_IncCounter );
nodeToInstrument->prependInst(incInst);
}
if (flags.bcLevelProfiling) { //remove duplicates from keys
std::sort(counterKeys.begin(), counterKeys.end());
counterKeys.resize(std::unique(counterKeys.begin(), counterKeys.end()) - counterKeys.begin());
}
}
irm.getCompilationInterface().lockMethodData();
ProfilingInterface* pi = irm.getProfilingInterface();
if (!pi->hasMethodProfile(ProfileType_Edge, md, JITProfilingRole_GEN)) {
pi->createEdgeMethodProfile(mm , md, (U_32)counterKeys.size(), counterKeys.empty()?NULL:(U_32*)&counterKeys.front(), _checkSum);
}
irm.getCompilationInterface().unlockMethodData();
if (debug) {
Log::out() << std::endl << "EdgePC:: instrumented, nCounters="<<counterKeys.size() <<" checksum="<<_checkSum << std::endl;
}
}
DEFINE_SESSION_ACTION_WITH_ACTION(EdgeProfilerAnnotationPass, EdgeProfilerAction, edge_annotate, "Perform edge annotation pass")
void EdgeProfilerAnnotationPass::_run(IRManager& irm) {
ControlFlowGraph& flowGraph = irm.getFlowGraph();
MethodDesc& md = irm.getMethodDesc();
MemoryManager mm("Edge AnnotationPass");
bool debug = Log::isEnabled();
EdgeProfilerAction* action = (EdgeProfilerAction*)getAction();
const EdgeProfileFlags& flags = action->getFlags();
if (debug) {
Log::out()<<"EdgeProfilerAnnotationPass. BcLevel="<<flags.bcLevelProfiling<<std::endl;
}
// Create the edge profile structure for the compiled method in 'irm'.
ProfilingInterface* pi = irm.getProfilingInterface();
bool edgeProfilerMode = pi->isProfilingEnabled(ProfileType_Edge, JITProfilingRole_USE);
bool entryBackedgeProfilerMode = !edgeProfilerMode && pi->isProfilingEnabled(ProfileType_EntryBackedge, JITProfilingRole_USE);
U_32 entryCount = (edgeProfilerMode || entryBackedgeProfilerMode) ? pi->getProfileMethodCount(md) : 0;
if (isMethodTrivial(flowGraph) || !edgeProfilerMode || entryCount == 0) {
// Annotate the CFG using static profiler heuristics.
if (debug) {
Log::out()<<"Using static profiler to estimate trivial graph"<<std::endl;
}
StaticProfiler::estimateGraph(irm, entryCount);
return;
}
OptPass::computeDominatorsAndLoops(irm);
DominatorTree* dt = irm.getDominatorTree();
LoopTree* lt = irm.getLoopTree();
LogStream& irdump = log(LogStream::IRDUMP);
if (irdump.isEnabled()) {
printHIR(irm, "IR before instrumentation");
}
// sync checksum
StlSet<Node*> nodesToIgnore(mm); //see instrumentation pass for comments
selectNodesToIgnore(irm, lt, nodesToIgnore, flags.bcLevelProfiling);
U_32 cfgCheckSum = computeCheckSum(mm, irm, nodesToIgnore, flags.bcLevelProfiling);
EdgeMethodProfile* edgeProfile = pi->getEdgeMethodProfile(mm, md);
U_32 profileCheckSum = edgeProfile->getCheckSum();
//assert(profileCheckSum == cfgCheckSum);
if (cfgCheckSum == profileCheckSum) {
// Start propagating the CFG from instrumented edges.
Edges edges(mm);
selectEdgesToInstrument(mm, irm, edges, nodesToIgnore, flags.bcLevelProfiling);
//assert if num counters is not equal -> must be guaranteed after checksum check
//for BC-level profiling checksum calculation is simplified -> no assertion
assert(edges.size() == edgeProfile->getNumCounters() || flags.bcLevelProfiling);
bool res = calculateProbsFromProfile(mm, flowGraph, edges, dt, lt, edgeProfile, flags.bcLevelProfiling, nodesToIgnore);
if (res) {
flowGraph.setEdgeProfile(true);
}
}
if (!flowGraph.hasEdgeProfile()) {
if (debug) {
Log::out()<<"DynProf failed: using static profiler to estimate graph!"<<std::endl;
}
StaticProfiler::estimateGraph(irm, 10000, true);
}
if (irm.getParent() == NULL) {
// fix profile: estimate cold paths that was never executed and recalculate frequencies
StaticProfiler::fixEdgeProbs(irm);
flowGraph.smoothEdgeProfile();
}
}
static inline void setEdgeFreq(StlVector<double>& edgeFreqs, Edge* edge, double freq, bool debug) {
if (debug) {
Log::out()<<"\t settings edge(id="<<edge->getId()<<") freq ("; FlowGraph::printLabel(Log::out(), edge->getSourceNode());
Log::out() << "->"; FlowGraph::printLabel(Log::out(), edge->getTargetNode()); Log::out()<<") to "<<freq << std::endl;
}
assert(freq>=0);
edgeFreqs[edge->getId()] = freq;
}
static void updateDispatchPathsToCatch(Node* node, StlVector<double>& edgeFreqs, bool debug) {
double freq = node->getExecCount();
const Edges& inEdges = node->getInEdges();
for (Edges::const_iterator it = inEdges.begin(), end = inEdges.end(); it!=end; ++it) {
Edge* edge = *it;
Node* srcNode = edge->getSourceNode();
if (srcNode->isDispatchNode() && freq > edgeFreqs[edge->getId()]) {
setEdgeFreq(edgeFreqs, edge, freq, debug);
srcNode->setExecCount(std::max(0.0, srcNode->getExecCount()) + freq);
updateDispatchPathsToCatch(srcNode, edgeFreqs, debug);
}
}
}
static bool calculateProbsFromProfile(MemoryManager& mm, ControlFlowGraph& fg, const Edges& pEdges,
DominatorTree* dt, LoopTree* lt, EdgeMethodProfile* profile,
bool bcLevelProfiling, const StlSet<Node*>& nodesToIgnore)
{
//calculate edge freqs and use them to calculate edge probs.
bool debug = Log::isEnabled();
if (debug) {
Log::out()<<"Starting probs calculation" <<std::endl;
}
U_32 entryCount = *profile->getEntryCounter();
//1. assign default value to nodes and edges, this value is used for consistency checks latter
StlVector<Node*> nodes(mm);
fg.getNodesPostOrder(nodes);
for (StlVector<Node*>::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) {
Node* node = *it;
node->setExecCount(-1);
const Edges& edges = node->getOutEdges();
for (Edges::const_iterator it2 = edges.begin(), end2 = edges.end(); it2!=end2; ++it2) {
Edge* edge = *it2;
edge->setEdgeProb(-1);
}
}
//2. calculate edge-freq for every edge.
//2.1 get freqs from profile
StlVector<double> edgeFreqs(mm, fg.getMaxEdgeId(), -1);
U_32 n = 1;
for (Edges::const_iterator it = pEdges.begin(), end = pEdges.end(); it!=end; ++it, ++n) {
Edge* edge = *it;
U_32 key = genKey(n, edge, bcLevelProfiling, debug);
U_32* counterAddr = profile->getCounter(key);
//assert(bcLevelProfiling || counterAddr!=NULL); -> TODO: hits in lazy resolution mode
U_32 freq = 0;
if (counterAddr == NULL) {
if (!bcLevelProfiling) { //avoid crash, use static profiler for a method
return false;
}
} else {
freq = *counterAddr;
}
setEdgeFreq(edgeFreqs, edge, freq, debug);
}
//2.2 propagate edge frequencies on linear paths
// this operation is needed because we do not instrument artificial edges (edges that connect nodes with the same bc-mapping)
if (bcLevelProfiling) {
for (StlVector<Node*>::reverse_iterator it = nodes.rbegin(), end = nodes.rend(); it!=end; ++it) {
Node* node = *it;
const Edges& outEdges = node->getOutEdges();
for (Edges::const_iterator it2 = outEdges.begin(), end2 = outEdges.end(); it2!=end2; ++it2) {
Edge* edge = *it2;
double freq = edgeFreqs[edge->getId()];
if (freq==-1) { //this edge has no profile -> can't use it for propagation
continue;
}
Node* targetNode = edge->getTargetNode();
//check pattern for artificial nodes: 1 unconditional + no changes in bcmapping
if (targetNode->isBlockNode() && targetNode->getOutDegree() <= 2 && targetNode->getUnconditionalEdge()!=NULL) {
Edge* unconditionalEdge = targetNode->getUnconditionalEdge();
if (targetNode->getFirstInst()->getBCOffset() == unconditionalEdge->getTargetNode()->getFirstInst()->getBCOffset()) {
double ufreq = edgeFreqs[unconditionalEdge->getId()];
double newUFreq= freq + MAX(ufreq, 0);
if (debug) {
Log::out()<<"Restoring profile for artificial edge : edge-id="<<unconditionalEdge->getId()<<std::endl;
}
setEdgeFreq(edgeFreqs, unconditionalEdge, newUFreq, debug);
}
}
}
}
}
//2.3 fix catch freqs, so we will have estimated D->C edges
if (debug) {
Log::out()<<"\tFixing catch freqs"<<std::endl;
}
for (StlVector<Node*>::reverse_iterator it = nodes.rbegin(), end = nodes.rend(); it!=end; ++it) {
Node* node = *it;
bool ignored = nodesToIgnore.find(node)!=nodesToIgnore.end();
if (!node->isCatchBlock() || ignored) {
continue;
}
//set up catch block prob -> will be used for dispatch nodes.
double nodeFreq = 0;
const Edges& outEdges = node->getOutEdges();
for (Edges::const_iterator it2 = outEdges.begin(), end2 = outEdges.end(); it2!=end2; ++it2) {
Edge* edge = *it2;
double edgeFreq = edgeFreqs[edge->getId()];
edgeFreq = MAX(0, edgeFreq); //if Cn->Ln edge is marked as artificial it's not instrumented
nodeFreq+=edgeFreq;
}
node->setExecCount(nodeFreq);
if (debug) {
Log::out()<<"\t\t fixing catch node ";FlowGraph::printLabel(Log::out(), node);Log::out()<<" freq="<<nodeFreq<<std::endl;
}
updateDispatchPathsToCatch(node, edgeFreqs, debug);
}
//2.4 calculate freqs for every edge in topological order
// set up nodes exec count for every node.
if (debug) {
Log::out()<<"\tPropagating edge freqs"<<std::endl;
}
for (StlVector<Node*>::reverse_iterator it = nodes.rbegin(), end = nodes.rend(); it!=end; ++it) {
Node* node = *it;
bool ignored = nodesToIgnore.find(node)!=nodesToIgnore.end();
double nodeFreq = 0;
const Edges& outEdges = node->getOutEdges();
const Edges& inEdges = node->getInEdges();
if (debug) {
Log::out()<<"\t\tNode="; FlowGraph::printLabel(Log::out(), node);Log::out()<<" in-edges="<<inEdges.size() << " was ignored="<<ignored<<std::endl;
}
if (node->getInDegree() == 0) {
assert(node == fg.getEntryNode());
nodeFreq = entryCount;
} else if (node->isCatchBlock()) { //set up catch block prob -> will be used for dispatch nodes.
if (ignored) {
// ignored catch edge (successor of ignored node or catch-loop)
// max we can do here is to try to get catch freq from in-edge
double _freq = 0;
Edge* inEdge = *node->getInEdges().begin();
if (node->getInDegree() == 1 && edgeFreqs[inEdge->getId()]>=0) {
_freq = edgeFreqs[inEdge->getId()];
}
Edge* outEdge = *node->getOutEdges().begin();
nodeFreq = edgeFreqs[outEdge->getId()] = _freq;
} else {//all out-edges were instrumented -> easy to calculate freq
nodeFreq = node->getExecCount(); //already assigned
assert(nodeFreq>=0);
}
} else {
for (Edges::const_iterator it2 = inEdges.begin(), end2 = inEdges.end(); it2!=end2; ++it2) {
Edge* edge = *it2;
Node* srcNode = edge->getSourceNode();
//assign edge-freq when available
//or 0-freq when source is dispatch (catches handled separately)
//or freq of src node when src node was removed from instrumentation(equal freq for all out-edges)
double edgeFreq = 0;
if (nodesToIgnore.find(srcNode)!=nodesToIgnore.end()) {
assert(srcNode->getExecCount()!= -1 || (srcNode->isCatchBlock() && dt->dominates(node, srcNode)) || (hasCatch(node) && srcNode->isEmpty()));
edgeFreq = srcNode->getExecCount();
} else if (srcNode->isBlockNode()) {
edgeFreq = edgeFreqs[edge->getId()];
}
if (debug) {
Log::out()<<"\t\t\tedge id="<<edge->getId()<<" from="; FlowGraph::printLabel(Log::out(), srcNode);
Log::out()<<" freq="<<edgeFreq<<std::endl;
}
if (edgeFreq == -1) {
//the only way to get not estimated edge here is to have catch loops (monexit pattern)
#ifdef _DEBUG
Node* head = lt->getLoopHeader(node, false); //catch loops are not instrumented
assert(head != NULL && (head->isCatchBlock() || head->isDispatchNode() || hasCatch(head)));
#endif
edgeFreq = 0;
setEdgeFreq(edgeFreqs, edge, edgeFreq, debug);
}
nodeFreq +=edgeFreq;
}
}
if (debug) {
Log::out()<<"\t\t\tnode freq="<<nodeFreq<<std::endl;
}
assert(nodeFreq!=-1);
node->setExecCount(nodeFreq);
if (node->isExitNode()) {
continue;
}
//now we able to calculate all outgoing edge freqs for current node
//if node is bb -> only 1 edge is allowed to be without freq here and we will fix it
//if node is dispatch -> use catch node freqs
//if node was ignored -> equal freq for every bb edge, 0 to dispatch edge
double freqLeft = nodeFreq;
if (ignored) {
if ( outEdges.size()==1 ) {
Edge* edge = *outEdges.begin();
setEdgeFreq(edgeFreqs, edge, nodeFreq, debug);
} else {
double freqPerBB = nodeFreq / (outEdges.size() - (node->getExceptionEdge() == NULL ? 0 : 1));
for (Edges::const_iterator it = outEdges.begin(), end = outEdges.end(); it!=end; ++it) {
Edge* edge = *it;
setEdgeFreq(edgeFreqs, edge, edge->getTargetNode()->isBlockNode() ? freqPerBB : 0, debug);
}
}
} else if (node->isBlockNode()) {
Edge* notEstimatedEdge = NULL;
for (Edges::const_iterator it2 = outEdges.begin(), end2 = outEdges.end(); it2!=end2; ++it2) {
Edge* edge = *it2;
double edgeFreq = edgeFreqs[edge->getId()];
if (edgeFreq != -1) {
freqLeft-=edgeFreq;
} else {
// here we can have 2 not-estimated edges only of this block was connected to 'ignored' node during annotation.
if (notEstimatedEdge == NULL) {
notEstimatedEdge = edge;
} else if (notEstimatedEdge->getTargetNode()->isDispatchNode()) {
setEdgeFreq(edgeFreqs, notEstimatedEdge, 0, debug);
notEstimatedEdge = edge;
} else {
setEdgeFreq(edgeFreqs, edge, 0, debug);
}
}
}
if (notEstimatedEdge!=NULL) {
freqLeft = freqLeft < 0 ? 0 : freqLeft;
setEdgeFreq(edgeFreqs, notEstimatedEdge, freqLeft, debug);
}
} else if (node->isDispatchNode()) {
//for all not estimated on step 2.2 D->X edges set edge prob to min (0).
for (Edges::const_iterator it = outEdges.begin(), end = outEdges.end(); it!=end; ++it) {
Edge* edge = *it;
double _freq = edgeFreqs[edge->getId()];
if (_freq==-1) {
setEdgeFreq(edgeFreqs, edge, 0, false);
}
}
}
}
//3. calculate edge probs using edge freqs.
if (debug) {
Log::out()<<"Calculating edge probs using freqs.."<<std::endl;
}
for (StlVector<Node*>::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it, n++) {
Node* node = *it;
double nodeFreq = node->getExecCount();
assert(nodeFreq!=-1);
const Edges& edges = node->getOutEdges();
for (Edges::const_iterator it2 = edges.begin(), end2 = edges.end(); it2!=end2; ++it2) {
Edge* edge = *it2;
double edgeFreq =edgeFreqs[edge->getId()];
assert(edgeFreq!=-1);
double edgeProb = nodeFreq == 0 ? 0 : edgeFreq / nodeFreq ;
// assert(edgeProb >= 0 && edgeProb <= 1);
edge->setEdgeProb(edgeProb);
}
}
if (debug) {
Log::out()<<"Finished probs calculation";
}
return true;
}
//
// Compute the checksum contribution of the given Edge
//
static U_32 _computeCheckSum(Node* node, const StlSet<Node*>& nodesToIgnore, StlVector<bool>& flags, U_32 depth, bool debug) {
assert(flags[node->getId()] == false);
flags[node->getId()] = true;
//node is removed from checksum calculation if
// 1) it's in ignore list
// 2) it's dispatch or catch -> due to the fact that ignore-list nodes can add more dispatches & catches(finally-blocks)
bool ignored = nodesToIgnore.find(node)!=nodesToIgnore.end();
bool skipped = ignored || node->getOutDegree()==1
|| (node->isCatchBlock() && node->isEmpty()) || node->isDispatchNode() || node->isExitNode();
U_32 dSum = skipped ? 0 : depth;
U_32 childDepth = skipped ? depth : depth + 1;
const Edges& outEdges = node->getOutEdges();
U_32 childsSum = 0;
for (Edges::const_iterator it = outEdges.begin(), end = outEdges.end(); it!=end; ++it) {
Edge* edge = *it;
Node* childNode = edge->getTargetNode();
//visit only those not visited child nodes that are not dispatch edges of ignored nodes
if (flags[childNode->getId()] == false && !(ignored && childNode->isDispatchNode())) {
childsSum+=_computeCheckSum(childNode, nodesToIgnore, flags, childDepth, debug);
}
}
if (debug){
Log::out()<< "\t<checksum calculation: node:"; FlowGraph::printLabel(Log::out(), node);
Log::out() << "=+"<<dSum<<" depth="<<depth<< " child sum="<<childsSum<<std::endl;
}
return dSum+childsSum;
}
static U_32 computeCheckSum( MemoryManager& mm, IRManager& irm, const StlSet<Node*>& nodesToIgnore, bool bcLevel) {
bool debug = Log::isEnabled();
if (debug) {
Log::out()<< "calculating checksum.." << std::endl;
}
U_32 checkSum = 0;
if (!bcLevel) {
ControlFlowGraph& cfg = irm.getFlowGraph();
StlVector<bool> flags(mm, cfg.getMaxNodeId(), false);
checkSum = _computeCheckSum(cfg.getEntryNode(), nodesToIgnore, flags, 1, debug);
} else {
checkSum = irm.getMethodDesc().getByteCodeSize();
}
if( debug){
Log::out()<< "checkSum= "<<checkSum<<std::endl;
}
return checkSum;
}
static Node* selectNodeToInstrument(IRManager& irm, Edge* edge) {
ControlFlowGraph& fg = irm.getFlowGraph();
Node* srcNode = edge->getSourceNode();
Node* dstNode = edge->getTargetNode();
Node* result = NULL;
assert(srcNode->isBlockNode() && dstNode->isBlockNode());
if (srcNode->isCatchBlock()) {
// catch blocks handled separately. We must add counter only after catch inst
assert(srcNode->hasOnlyOneSuccEdge() || hasCatch(srcNode));
if (srcNode->hasOnlyOneSuccEdge() && hasCatch(srcNode)) { //filter-out catches with ret -> instrument srcNode
result = srcNode;
} else {
result = dstNode;
}
} else {
result = srcNode->hasOnlyOneSuccEdge() ? srcNode : dstNode;
}
if( result->hasTwoOrMorePredEdges() ){
// Splice a new block on edge from srcNode to dstNode and put
// instrumentation code there.
result = fg.spliceBlockOnEdge(edge, irm.getInstFactory().makeLabel());
}
return result;
}
static bool hasCatch( Node* node ) {
Inst* inst = (Inst*)node->getFirstInst();
assert(inst->isLabel());
// Op_Catch is allowed to be not in the second position only (after label inst)
// but in arbitrary position if Op_Phi insts present.
do {
inst = inst->getNextInst();
} while (inst!=NULL && inst->getOpcode() == Op_Phi);
return inst != NULL && inst->getOpcode() == Op_Catch;
}
/*static bool hasCounter( Node* node ) {
for (Inst* inst = node->getFirstInst()->next(); inst!=node->getFirstInst(); inst = inst->next()) {
if (inst->getOpcode() == Op_IncCounter) {
return true;
}
}
return false;
}*/
static void selectNodesToIgnore(IRManager& irm, LoopTree* lt, StlSet<Node*>& result, bool bcLevel) {
ControlFlowGraph& fg = irm.getFlowGraph();
bool debug = Log::isEnabled();
if (debug) {
Log::out() << "Selecting nodes to ignore:"<<std::endl;
}
const Nodes& nodes = fg.getNodes();
for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) {
Node* node = *it;
//first pattern to ignore: class initializers in non-bc-level mode
Node* loopHead = lt->getLoopHeader(node, false);
bool inCatchLoop = loopHead!=NULL && (loopHead->isCatchBlock() || loopHead->isDispatchNode() || hasCatch(loopHead));
if (!bcLevel && node->isBlockNode()
&& node->getOutDegree() == 2 && node->getExceptionEdge()!=NULL
&& ((Inst*)node->getLastInst())->getOpcode() == Op_InitType)
{
result.insert(node);
if (debug) {
Log::out() << "\tIgnoring Op_InitType node:";FlowGraph::printLabel(Log::out(), node);Log::out() << std::endl;
}
} else if (inCatchLoop && node->isEmpty()) {
//common block for multiple catches in catch loop -> add to ignore
result.insert(node);
if (debug) {
Log::out() << "\tIgnoring catch-loop preheader node:";FlowGraph::printLabel(Log::out(), node);Log::out() << std::endl;
}
} else if (node->isCatchBlock()) {
Node* blockWithCatchInst = NULL;
if (hasCatch(node)) {
// blockWithCatchInst = node; //TODO: recheck
} else {
assert(node->hasOnlyOneSuccEdge());
Edge* e = *node->getOutEdges().begin();
blockWithCatchInst = e->getTargetNode();
}
if (blockWithCatchInst!=NULL && blockWithCatchInst->hasTwoOrMorePredEdges()) { //avoid mon-exit loops (catch loops) instrumentation
result.insert(node);
if (debug) {
Log::out() << "\tIgnoring '1-catch-inst*N-catches' node:";FlowGraph::printLabel(Log::out(), node);Log::out() << std::endl;
}
}
}
}
if (debug) {
Log::out() << "DONE. ignored nodes: " << result.size() << std::endl;
}
}
static void _selectEdgesToInstrument(Node* srcNode, IRManager& irm, Edges& result,
const StlSet<Node*>& nodesToIgnore, StlVector<bool>& flags, bool bcLevel)
{
bool profileDispatchEdges = true; //TODO: cmd-line param
assert(flags[srcNode->getId()] == false);
flags[srcNode->getId()] = true;
Node* returnNode = irm.getFlowGraph().getReturnNode();
LoopTree* loopTree = irm.getLoopTree();
const Edges& oEdges = srcNode->getOutEdges();
bool ignored = nodesToIgnore.find(srcNode)!=nodesToIgnore.end();
if (!ignored && srcNode->isBlockNode()) {
Edge* skipEdge = NULL; //instrument all edges except one
if (srcNode->isCatchBlock()) {
// for a catch block we can have only 1 successor edge if catch inst is in next block
// if catch inst is in catch block -> instrument every outgoing edge to be able to restore catch
// node frequency.
assert(hasCatch(srcNode) || srcNode->hasOnlyOneSuccEdge());
} else if (!bcLevel) { //instrument all edges if bcLevel profiling. Artificial edges will be filtered later
for(Edges::const_iterator it = oEdges.begin(); it!= oEdges.end(); ++it ){
Edge* edge = *it;
Node* targetNode = edge->getTargetNode();
bool isBackEdge = loopTree->isBackEdge(edge);
//we must instrument backedges to be able to restore loop iteration count
if( isBackEdge || (!targetNode->isBlockNode() && profileDispatchEdges) ){
// We run into a dispatch node, so we have to instrument all the other edges.
skipEdge = NULL;
break;
}
// It is profitable to instrument along the loop exit edge.
if (skipEdge == NULL || loopTree->isLoopExit(skipEdge)) {
skipEdge = edge;
}
}
}
bool debug = Log::isEnabled();
for(Edges::const_iterator it = oEdges.begin(); it!= oEdges.end(); ++it ){
Edge* edge = *it;
Node* targetNode = edge->getTargetNode();
if( targetNode->isBlockNode() && edge!=skipEdge){
bool skip = false;
if (bcLevel && targetNode->getNodeStartBCOffset() == edge->getSourceNode()->getNodeEndBCOffset()) {
skip = true;//skip this edge, it's artificial code
}
if (bcLevel && targetNode == returnNode) {
skip = true;
}
if (!skip) {
result.push_back(edge);
}
if (debug) {
Log::out()<<"\tedge id="<<edge->getId()<<" ("; FlowGraph::printLabel(Log::out(), edge->getSourceNode());
Log::out()<<"->"; FlowGraph::printLabel(Log::out(), edge->getTargetNode());Log::out()<<")";
if (skip) Log::out()<<" SKIPPED as artificial ";
Log::out()<<std::endl;
}
}
}
}
// process all child nodes. for ignored nodes we do not process dispatches
// because new catch block can be created that must also be ignored
for(Edges::const_iterator it = oEdges.begin(); it!= oEdges.end(); ++it ){
Edge* edge = *it;
Node* targetNode = edge->getTargetNode();
if (flags[targetNode->getId()] == false && !(ignored && targetNode->isDispatchNode())) {
_selectEdgesToInstrument(targetNode, irm, result, nodesToIgnore, flags, bcLevel);
}
}
}
static void selectEdgesToInstrument(MemoryManager& mm, IRManager& irm, Edges& result,
const StlSet<Node*>& nodesToIgnore, bool bcLevel)
{
ControlFlowGraph& fg = irm.getFlowGraph();
StlVector<bool> flags(mm, fg.getMaxNodeId(), false);
bool debug = Log::isEnabled();
if (debug) {
Log::out() << "List of edges to instrument: "<<std::endl;
}
_selectEdgesToInstrument(fg.getEntryNode(), irm, result, nodesToIgnore, flags, bcLevel);
if (debug) {
Log::out() << "End of list.."<<std::endl;
}
}
//
// Return true if the method represented by <cfg> is trivial.
// A method is trivial if it is a leaf method, and it has no if-then-else
// statement.
//
static bool isMethodTrivial( ControlFlowGraph& cfg ) {
const Nodes& nodes = cfg.getNodes();
Nodes::const_iterator niter;
for( niter = nodes.begin(); niter != nodes.end(); niter++ ){
Node* node = *niter;
if( !node->isBlockNode() || node->isEmpty() ){
continue;
}
Inst* last = (Inst*)node->getLastInst();
// This method is not a leaf method.
if( last->getOpcode() >= Op_DirectCall && last->getOpcode() <= Op_VMHelperCall ){
return false;
}
Edges::const_iterator eiter;
const Edges& oEdges = node->getOutEdges();
int succ = 0;
for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) {
Edge* edge = *eiter;
if( edge->getTargetNode()->isBlockNode() ){
succ++;
}
}
// This method has if-then-else statement(s).
if( succ > 1 ){
return false;
}
}
return true;
}
static U_32 genKey( U_32 pos, Edge* edge, bool bcLevel, bool debug) {
U_32 key = 0;
if (debug) {
Log::out()<<"\t\t key for edge with id="<<edge->getId()<<" ("; FlowGraph::printLabel(Log::out(), edge->getSourceNode());
Log::out() << "->"; FlowGraph::printLabel(Log::out(), edge->getTargetNode()); Log::out()<<") is ";Log::out().flush();
}
if (bcLevel) {
uint16 bcBefore = edge->getSourceNode()->getNodeEndBCOffset();
uint16 bcAfter = edge->getTargetNode()->getNodeStartBCOffset();
assert(bcBefore!=ILLEGAL_BC_MAPPING_VALUE && bcAfter!=ILLEGAL_BC_MAPPING_VALUE);
key = (((U_32)bcBefore)<<16) + bcAfter;
} else {
//TODO: this algorithm is not 100% effective: we can't rely on edges order in CFG
U_32 edgePos = 0;
const Edges& edges = edge->getSourceNode()->getOutEdges();
for (Edges::const_iterator it = edges.begin(), end = edges.end(); it!=end; ++it) {
Edge* outEdge = *it;
if (outEdge == edge) {
break;
}
if (outEdge->isDispatchEdge()) { //dispatch edge order is the reason of the most of the edge ordering errors
continue;
}
edgePos++;
}
key = pos + (edgePos << 16);
}
if (debug) {
Log::out() << key << std::endl;
}
return key;
}
static void checkBCMapping( ControlFlowGraph& cfg ) {
#ifdef _DEBUG
const Nodes& nodes = cfg.getNodes();
for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) {
Node* node = *it;
if (node->isBlockNode() && node!=cfg.getReturnNode()) {
CFGInst* inst = node->getFirstInst();
assert(inst!=NULL && inst->isLabel());
if (inst->getBCOffset()==ILLEGAL_BC_MAPPING_VALUE) {
if (Log::isEnabled()) {
Log::out()<<"Illegal BC-Map for node:";FlowGraph::printLabel(Log::out(), node);
}
assert(inst->getBCOffset()!=ILLEGAL_BC_MAPPING_VALUE);
}
}
}
#endif
}
} //namespace