/*
* This file is part of JOP, the Java Optimized Processor
* see <http://www.jopdesign.com/>
*
* Copyright (C) 2010, Benedikt Huber (benedikt.huber@gmail.com)
*
* 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.wcet.analysis;
import java.io.File;
import java.io.IOException;
import org.apache.log4j.Logger;
import com.jopdesign.common.MethodInfo;
import com.jopdesign.common.code.CallString;
import com.jopdesign.common.code.ControlFlowGraph;
import com.jopdesign.wcet.WCETTool;
import com.jopdesign.wcet.analysis.RecursiveAnalysis.RecursiveStrategy;
import com.jopdesign.wcet.analysis.cache.MethodCacheAnalysis;
import com.jopdesign.wcet.uppaal.AnalysisContextUppaal;
import com.jopdesign.wcet.uppaal.Translator;
import com.jopdesign.wcet.uppaal.UppAalConfig;
import com.jopdesign.wcet.uppaal.UppAalConfig.UppaalCacheApproximation;
import com.jopdesign.wcet.uppaal.WcetSearch;
import com.jopdesign.wcet.uppaal.model.DuplicateKeyException;
import com.jopdesign.wcet.uppaal.model.XmlSerializationException;
public class UppaalAnalysis {
private Logger logger;
private WCETTool project;
private double searchtime = 0.0;
private double solvertimemax = 0.0;
private UppAalConfig uppaalConfig;
public UppaalAnalysis(Logger logger, WCETTool project, File outDir) {
if (project.getCallstringLength() > 0) {
throw new AssertionError("Callstrings for UPPAAL analysis are not supported");
}
this.uppaalConfig = new UppAalConfig(project.getConfig(), outDir);
this.logger = logger;
this.project = project;
}
public WcetCost computeWCET(MethodInfo targetMethod, long upperBound) throws IOException, DuplicateKeyException, XmlSerializationException {
if (uppaalConfig.hasComplexityTreshold()) {
int cc = project.computeCyclomaticComplexity(targetMethod);
long treshold = uppaalConfig.getComplexityTreshold();
if (cc > treshold) {
return computeWCETWithTreshold(targetMethod, treshold);
}
}
return calculateWCET(targetMethod, upperBound);
}
public WcetCost computeWCETWithTreshold(MethodInfo targetMethod, long complexityTreshold) {
RecursiveWcetAnalysis<AnalysisContextUppaal> sa =
new RecursiveWcetAnalysis<AnalysisContextUppaal>(
project, new UppaalTresholdStrategy(this, complexityTreshold));
return sa.computeCost(targetMethod,
new AnalysisContextUppaal(uppaalConfig.getCacheApproximation()));
}
public WcetCost calculateWCET(MethodInfo m) throws IOException, DuplicateKeyException, XmlSerializationException {
return calculateWCET(m, -1);
}
public WcetCost calculateWCET(MethodInfo m, long ub) throws IOException, DuplicateKeyException, XmlSerializationException {
Long upperBound = null;
if (ub > 0) upperBound = ub + 20;
logger.info("Starting UppAal translation of " + m.getFQMethodName());
Translator translator = new Translator(uppaalConfig, project);
translator.translateProgram(m);
translator.writeOutput();
logger.info("model and query can be found in " + uppaalConfig.outDir);
logger.info("model file: " + translator.getModelFile());
if (uppaalConfig.hasVerifier()) {
logger.info("Starting verification");
WcetSearch search = new WcetSearch(project.getConfig(), translator.getModelFile());
long start = System.nanoTime();
long wcet = search.searchWCET(upperBound);
long end = System.nanoTime();
searchtime += (end - start) / 1E9;
solvertimemax = Math.max(solvertimemax, search.getMaxSolverTime());
return WcetCost.totalCost(wcet);
} else {
throw new IOException("No verifier binary available. Skipping search");
}
}
public double getSearchtime() {
return searchtime;
}
public double getSolvertimemax() {
return solvertimemax;
}
static class UppaalTresholdStrategy
implements RecursiveStrategy<AnalysisContextUppaal, WcetCost> {
private UppaalAnalysis uppaalAnalysis;
private long treshold;
public UppaalTresholdStrategy(UppaalAnalysis uppaalAnalysis, long treshold) {
this.uppaalAnalysis = uppaalAnalysis;
this.treshold = treshold;
}
/* FIXME: Some code duplication with GlobalAnalysis / LocalAnalysis */
public WcetCost recursiveCost(
RecursiveAnalysis<AnalysisContextUppaal, WcetCost> stagedAnalysis,
ControlFlowGraph.InvokeNode n,
AnalysisContextUppaal ctx) {
WCETTool project = stagedAnalysis.getWCETTool();
MethodInfo invoked = n.getImplementingMethod();
MethodCacheAnalysis mca = new MethodCacheAnalysis(project);
int cc = project.computeCyclomaticComplexity(invoked);
long invokeReturnCost = mca.getInvokeReturnMissCost(n.getInvokeSite(), CallString.EMPTY);
long cacheCost, nonLocalExecCost;
if (cc <= treshold
&& ctx.getCacheApprox() != UppaalCacheApproximation.ALWAYS_MISS
&& !project.getCallGraph().isLeafMethod(invoked)
&& !stagedAnalysis.isCached(invoked, ctx)
) {
WcetCost uppaalCost;
WcetCost ubCost = stagedAnalysis.computeCost(invoked, ctx.withCacheApprox(UppaalCacheApproximation.ALWAYS_MISS));
try {
uppaalAnalysis.logger.info("Complexity of " + invoked + " below treshold: " + cc);
uppaalCost = uppaalAnalysis.calculateWCET(invoked, ubCost.getCost());
} catch (Exception e) {
throw new AssertionError("Uppaal analysis failed: " + e);
}
stagedAnalysis.recordCost(invoked, ctx, uppaalCost);
// FIXME: uppaal getCacheCost() is 0 at the moment
cacheCost = invokeReturnCost + uppaalCost.getCacheCost();
nonLocalExecCost = uppaalCost.getNonCacheCost();
} else {
if (cc > treshold) {
uppaalAnalysis.logger.info("Complexity of " + invoked + " above treshold: " + cc);
}
WcetCost recCost = stagedAnalysis.computeCost(invoked, ctx);
cacheCost = recCost.getCacheCost() + invokeReturnCost;
nonLocalExecCost = recCost.getCost() - recCost.getCacheCost();
}
WcetCost cost = new WcetCost();
cost.addNonLocalCost(nonLocalExecCost);
cost.addCacheCost(cacheCost);
WCETTool.logger.debug("Recursive WCET computation [GLOBAL IPET]: " + invoked +
". cummulative cache cost: " + cacheCost +
" non local execution cost: " + nonLocalExecCost);
return cost;
}
}
}