/* * 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 com.jopdesign.common.MethodInfo; import com.jopdesign.common.code.CallString; import com.jopdesign.common.code.ControlFlowGraph; import com.jopdesign.common.code.ExecutionContext; import com.jopdesign.common.code.ControlFlowGraph.BasicBlockNode; import com.jopdesign.common.code.ControlFlowGraph.CFGEdge; import com.jopdesign.common.code.ControlFlowGraph.CFGNode; import com.jopdesign.common.code.ControlFlowGraph.CfgVisitor; import com.jopdesign.common.code.ControlFlowGraph.ReturnNode; import com.jopdesign.common.code.LoopBound; import com.jopdesign.common.graphutils.ProgressMeasure; import com.jopdesign.common.graphutils.ProgressMeasure.RelativeProgress; import com.jopdesign.wcet.WCETTool; import com.jopdesign.wcet.analysis.cache.MethodCacheAnalysis; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; /** * While implementing progress measure, I found that they can be used for tree based * WCET analysis. Why not ? * This can be implemented in almost linear (graph size) time, * but our suboptimal implementation depends the depth of the loop nest tree. * * @author Benedikt Huber <benedikt.huber@gmail.com> */ public class TreeAnalysis { private class LocalCostVisitor extends WcetVisitor { private AnalysisContext ctx; private MethodCacheAnalysis mca; public LocalCostVisitor(AnalysisContext c, WCETTool p) { super(p); mca = new MethodCacheAnalysis(p); ctx = c; } @Override public void visitInvokeNode(ControlFlowGraph.InvokeNode n) { MethodInfo method = n.getImplementingMethod(); /* deal with pruned (infeasible) receivers */ if(! methodWCET.containsKey(method)) { WCETTool.logger.info("Pruned InvokeNode: "+n.getImplementingMethod()); cost.addNonLocalCost(Long.MIN_VALUE); return; } visitBasicBlockNode(n); cost.addCacheCost(mca.getInvokeReturnMissCost(n.getInvokeSite(), ctx.getCallString())); cost.addNonLocalCost(methodWCET.get(method)); } @Override public void visitBasicBlockNode(BasicBlockNode n) { cost.addLocalCost(project.getWCETProcessorModel().basicBlockWCET(ctx.getExecutionContext(n), n.getBasicBlock())); } @Override public void visitReturnNode(ReturnNode n) { } } private class ProgressVisitor implements CfgVisitor { private Map<MethodInfo, Long> subProgress; public ProgressVisitor(Map<MethodInfo, Long> subProgress) { this.subProgress = subProgress; } private long progress; public void visitBasicBlockNode(BasicBlockNode n) { progress = 1; } public void visitInvokeNode(ControlFlowGraph.InvokeNode n) { /* deal with pruned (infeasible) receivers */ if(! subProgress.containsKey(n.getImplementingMethod())) { WCETTool.logger.info("Pruned InvokeNode: "+n.getImplementingMethod()); progress = Long.MIN_VALUE; /* not possible */ return; } Long aLong = subProgress.get(n.getImplementingMethod()); long invokedProgress = aLong; progress = 1 + invokedProgress; } public void visitVirtualNode(ControlFlowGraph.VirtualNode n) { progress = 1; } public void visitReturnNode(ControlFlowGraph.ReturnNode n) { visitVirtualNode(n); } public void visitSummaryNode(ControlFlowGraph.SummaryNode n) { progress = 1; } public long getProgress(CFGNode n) { n.accept(this); return progress; } } private WCETTool project; private HashMap<MethodInfo, Long> methodWCET; private Map<MethodInfo, Map<ControlFlowGraph.CFGEdge, RelativeProgress<CFGNode>>> relativeProgress = new HashMap<MethodInfo, Map<ControlFlowGraph.CFGEdge, RelativeProgress<CFGNode>>>(); private HashMap<MethodInfo, Long> maxProgress = new HashMap<MethodInfo, Long>(); private boolean filterLeafMethods; public TreeAnalysis(WCETTool p, boolean filterLeafMethods) { this.project = p; this.filterLeafMethods = filterLeafMethods; computeProgress(p.getTargetMethod(), CallString.EMPTY); } /* FIXME: filter leaf methods is really a ugly hack, * but needs some work to play nice with uppaal eliminate-leaf-methods optimizations */ public void computeProgress(MethodInfo targetMethod, CallString cs) { List<MethodInfo> reachable = project.getCallGraph().getReachableImplementations(targetMethod,cs); Collections.reverse(reachable); for (MethodInfo mi : reachable) { ControlFlowGraph cfg = project.getFlowGraph(mi); Map<CFGNode, Long> localProgress = new HashMap<CFGNode, Long>(); ProgressVisitor progressVisitor = new ProgressVisitor(maxProgress); for (CFGNode n : cfg.vertexSet()) { localProgress.put(n, progressVisitor.getProgress(n)); } ProgressMeasure<CFGNode, CFGEdge> pm = new ProgressMeasure<CFGNode, ControlFlowGraph.CFGEdge>(cfg.getGraph(), cfg.getLoopColoring(), extractUBs(cfg.buildLoopBoundMap()), localProgress); long progress = pm.getMaxProgress().get(cfg.getExit()); /* FIXME: _UGLY_ hack */ if (filterLeafMethods && cfg.isLeafMethod()) { maxProgress.put(mi, 0L); } else { maxProgress.put(mi, progress); } relativeProgress.put(mi, pm.computeRelativeProgress()); } System.out.println("Progress Measure (max): " + maxProgress.get(targetMethod)); } public Map<MethodInfo, Map<ControlFlowGraph.CFGEdge, RelativeProgress<CFGNode>>> getRelativeProgressMap() { return this.relativeProgress; } public Long getMaxProgress(MethodInfo mi) { return this.maxProgress.get(mi); } private Map<CFGNode, Long> extractUBs(Map<CFGNode, LoopBound> loopBounds) { Map<CFGNode, Long> ubMap = new HashMap<CFGNode, Long>(); for (Entry<CFGNode, LoopBound> entry : loopBounds.entrySet()) { MethodInfo mi = entry.getKey().getControlFlowGraph().getMethodInfo(); ExecutionContext eCtx = new ExecutionContext(mi); ubMap.put(entry.getKey(), entry.getValue().getUpperBound(eCtx)); } return ubMap; } public long computeWCET(MethodInfo targetMethod) { this.methodWCET = new HashMap<MethodInfo, Long>(); List<MethodInfo> reachable = project.getCallGraph().getReachableImplementations(targetMethod); Collections.reverse(reachable); for (MethodInfo mi : reachable) { ControlFlowGraph cfg = project.getFlowGraph(mi); Map<CFGNode, Long> localCost = new HashMap<CFGNode, Long>(); LocalCostVisitor lcv = new LocalCostVisitor(new AnalysisContextCallString(CallString.EMPTY), project); for (CFGNode n : cfg.vertexSet()) { localCost.put(n, lcv.computeCost(n).getCost()); } ProgressMeasure<CFGNode, ControlFlowGraph.CFGEdge> pm = new ProgressMeasure<CFGNode, ControlFlowGraph.CFGEdge>(cfg.getGraph(), cfg.getLoopColoring(), extractUBs(cfg.buildLoopBoundMap()), localCost); long wcet = pm.getMaxProgress().get(cfg.getExit()); methodWCET.put(mi, wcet); } return methodWCET.get(targetMethod); } }