/*
* This file is part of JOP, the Java Optimized Processor
* see <http://www.jopdesign.com/>
*
* Copyright (C) 2011, Stefan Hepp (stefan@stefant.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jopdesign.jcopter.analysis;
import com.jopdesign.common.AppInfo;
import com.jopdesign.common.MethodInfo;
import com.jopdesign.common.code.CallGraph;
import com.jopdesign.common.code.CallGraph.DUMPTYPE;
import com.jopdesign.common.code.DefaultCallgraphBuilder;
import com.jopdesign.common.config.Config.BadConfigurationError;
import com.jopdesign.common.config.Config.BadConfigurationException;
import com.jopdesign.jcopter.JCopter;
import com.jopdesign.jcopter.analysis.MethodCacheAnalysis.AnalysisType;
import com.jopdesign.wcet.ipet.IPETConfig.CacheCostCalculationMethod;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
/**
* Container for various analyses, provide some methods to invalidate/.. all analyses.
*
* @author Stefan Hepp (stefan@stefant.org)
*/
public class AnalysisManager {
private static final Logger logger = Logger.getLogger(JCopter.LOG_ANALYSIS+".AnalysisManager");
private final JCopter jcopter;
private WCAInvoker wcaInvoker;
private ExecFrequencyAnalysis execFreqAnalysis;
private MethodCacheAnalysis methodCacheAnalysis;
private Map<MethodInfo,StacksizeAnalysis> stacksizeMap;
private CallGraph targetCallGraph;
public AnalysisManager(JCopter jcopter) {
this.jcopter = jcopter;
stacksizeMap = new LinkedHashMap<MethodInfo, StacksizeAnalysis>();
}
public JCopter getJCopter() {
return jcopter;
}
/**
* Quick'n'dirty initialization of all analyses.
* If the analyses get more options or get more complex in the future, this will need some work.
*
* @param targets the root methods to use for all analyses and the callgraph.
* @param cacheAnalysisType cache analysis type
* @param wcaRoots if not null, initialize the WCA invoker with these roots.
* @param updateWCEP if true, let the wcaInvoker provide a global WCET path and keep it up-to-date
*/
public void initAnalyses(Set<MethodInfo> targets, AnalysisType cacheAnalysisType,
CacheCostCalculationMethod cacheApproximation, boolean useMethodCacheStrategy,
Set<MethodInfo> wcaRoots, boolean updateWCEP)
{
logger.info("Initializing analyses..");
Set<MethodInfo> allTargets = new LinkedHashSet<MethodInfo>(targets);
if (wcaRoots != null) {
// Just make sure the WCA callgraph is contained in the target graph..
allTargets.addAll(wcaRoots);
wcaInvoker = new WCAInvoker(this, wcaRoots, cacheApproximation);
wcaInvoker.setProvideWCAExecCount(updateWCEP);
try {
// need to initialize the WCA Tool before the other analyses since we need the WCA callgraph
wcaInvoker.initTool();
} catch (BadConfigurationException e) {
// TODO or maybe just throw the exception up a few levels more?
throw new BadConfigurationError(e.getMessage(), e);
}
}
if (wcaRoots != null && wcaRoots.equals(allTargets) && wcaInvoker.getWCACallGraphs().size() == 1) {
targetCallGraph = wcaInvoker.getWCACallGraphs().iterator().next();
} else {
logger.info("Initializing Target Callgraph");
targetCallGraph = CallGraph.buildCallGraph(allTargets,
new DefaultCallgraphBuilder(AppInfo.getSingleton().getCallstringLength()));
}
// TODO we might want to classify methods depending on whether they are reachable from the wcaRoots
// for all non-wca-methods we might want to use different initial analysis data, e.g.
// if we use the WCA, we might want to use the IPET WCA to initialize the execCountAnalysis for
// wca-methods
// We can do this as first step (after the callgraph has been created) since it does not use the ExecFrequencyAnalysis
logger.info("Initializing MethodCacheAnalysis");
methodCacheAnalysis = new MethodCacheAnalysis(jcopter, cacheAnalysisType, targetCallGraph);
methodCacheAnalysis.initialize();
if (wcaRoots != null) {
logger.info("Initializing WCAInvoker");
wcaInvoker.initAnalysis(useMethodCacheStrategy);
}
// TODO in fact, we might not even need this if we only use the wcaInvoker as provider or some other provider
logger.info("Initializing ExecFrequencyAnalysis");
execFreqAnalysis = new ExecFrequencyAnalysis(this, targetCallGraph);
execFreqAnalysis.initialize();
}
public boolean hasWCATargetsOnly() {
if (wcaInvoker == null) return false;
return targetCallGraph.getRootMethods().equals(wcaInvoker.getWcaTargets());
}
public boolean useWCAInvoker() {
return wcaInvoker != null;
}
public CallGraph getTargetCallGraph() {
return targetCallGraph;
}
public CallGraph getAppInfoCallGraph() {
return AppInfo.getSingleton().getCallGraph();
}
public Set<MethodInfo> getWCAMethods() {
if (wcaInvoker == null) return Collections.emptySet();
Set<MethodInfo> methods = new LinkedHashSet<MethodInfo>();
for (MethodInfo root : wcaInvoker.getWcaTargets()) {
methods.addAll( targetCallGraph.getReachableImplementationsSet(root) );
}
return methods;
}
public boolean isWCAMethod(MethodInfo method) {
if (wcaInvoker == null) return false;
return wcaInvoker.isWCAMethod(method);
}
public Collection<CallGraph> getWCACallGraphs() {
return wcaInvoker != null ? wcaInvoker.getWCACallGraphs() : Collections.<CallGraph>emptySet();
}
/**
* @return all callgraphs used by the analyses (including the AppInfo callgraph) which are not backed by other callgraphs.
*/
public Set<CallGraph> getCallGraphs() {
Set<CallGraph> graphs = new LinkedHashSet<CallGraph>(4);
graphs.add(getAppInfoCallGraph());
graphs.add(getTargetCallGraph());
graphs.addAll(getWCACallGraphs());
return graphs;
}
public void dumpTargetCallgraph(String name, boolean full) {
try {
targetCallGraph.dumpCallgraph(jcopter.getJConfig().getConfig(), name, full ? "full" : "merged",
targetCallGraph.getRootNodes(), full ? DUMPTYPE.full : DUMPTYPE.merged, false);
} catch (IOException e) {
logger.warn(e);
}
}
public ExecFrequencyAnalysis getExecFrequencyAnalysis() {
return execFreqAnalysis;
}
public MethodCacheAnalysis getMethodCacheAnalysis() {
return methodCacheAnalysis;
}
public StacksizeAnalysis getStacksizeAnalysis(MethodInfo methodInfo) {
StacksizeAnalysis stacksize = stacksizeMap.get(methodInfo);
if (stacksize == null) {
stacksize = new StacksizeAnalysis(methodInfo);
stacksize.analyze();
stacksizeMap.put(methodInfo, stacksize);
}
return stacksize;
}
public void clearChangeSets() {
if (execFreqAnalysis != null) execFreqAnalysis.clearChangeSet();
if (methodCacheAnalysis != null) methodCacheAnalysis.clearChangeSet();
}
public WCAInvoker getWCAInvoker() {
return wcaInvoker;
}
}