/*
This file is part of JOP, the Java Optimized Processor
see <http://www.jopdesign.com/>
Copyright (C) 2010, Benedikt Huber (benedikt@vmars.tuwien.ac.at)
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.ipet;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import com.jopdesign.common.code.CallString;
import com.jopdesign.common.code.CallStringProvider;
import com.jopdesign.common.code.ControlFlowGraph;
import com.jopdesign.common.code.ExecutionContext;
import com.jopdesign.common.code.LoopBound;
import com.jopdesign.common.code.SymbolicMarker;
import com.jopdesign.common.code.ControlFlowGraph.CFGEdge;
import com.jopdesign.common.code.ControlFlowGraph.CFGNode;
import com.jopdesign.common.code.SymbolicMarker.SymbolicMarkerType;
import com.jopdesign.common.graphutils.FlowGraph;
import com.jopdesign.common.graphutils.LoopColoring;
import com.jopdesign.common.misc.AppInfoError;
import com.jopdesign.wcet.WCETTool;
import com.jopdesign.wcet.annotations.LoopBoundExpr;
import com.jopdesign.wcet.ipet.IPETBuilder.ExecutionEdge;
import com.jopdesign.wcet.ipet.LinearConstraint.ConstraintType;
/**
* Purpose: This class provides utility functions to build +IPET models
*
* @author Benedikt Huber (benedikt@vmars.tuwien.ac.at)
*/
public class IPETUtils {
/**
* [NEW-GLOBAL-ANALYSIS]
* Build a constraint <pre>sum edges = C</pre>
* @param edges
* @param rhs
* @return
*/
public static <E>
LinearConstraint<E>
constantFlow(Iterable<E> edges, int rhs) {
LinearConstraint<E> eq = new LinearConstraint<E>(ConstraintType.Equal);
eq.addRHS(rhs);
for (E ingoing : edges) {
eq.addLHS(ingoing);
}
return eq;
}
/**
* [NEW-GLOBAL-ANALYSIS]
* Build a constraint <pre>sum es1 = sum es2</pre>
* @param es1
* @param es2
* @return
*/
public static <E>
LinearConstraint<E>
flowPreservation(Iterable<E> es1, Iterable<E> es2) {
LinearConstraint<E> eq = new LinearConstraint<E>(ConstraintType.Equal);
for (E lhs : es1) {
eq.addLHS(lhs);
}
for (E rhs : es2) {
eq.addRHS(rhs);
}
return eq;
}
/**
* [NEW-GLOBAL-ANALYSIS]
* Build a constraint <pre>sum es1 <= sum es2 * k</pre>
* @param es1 lhs
* @param es2 rhs
* @param k multiplier for the right hand side
* @return a constraint that sum(es1) is less than or equal to sum(es2) * k
*/
public static <E>
LinearConstraint<E>
relativeBound(Iterable<E> es1, Iterable<E> es2, long k) {
LinearConstraint<E> eq = new LinearConstraint<E>(ConstraintType.LessEqual);
for (E lhs : es1) {
eq.addLHS(lhs);
}
for (E rhs : es2) {
eq.addRHS(rhs, k);
}
return eq;
}
/**
* Top level flow constraints: flow out of entry and flow into exit must be one.
* <pre>sum (e_Entry_x) = 1</pre>
* <pre>sum (e_y_Exit) = 1</pre>
*/
@Deprecated
public static <V, E, C extends CallStringProvider>
List<LinearConstraint<IPETBuilder.ExecutionEdge>>
structuralFlowConstraintsRoot(FlowGraph<V, E> g, IPETBuilder<C> ctx) {
LinearConstraint<IPETBuilder.ExecutionEdge> entryLhsProto = new LinearConstraint<IPETBuilder.ExecutionEdge>(ConstraintType.Equal);
entryLhsProto.addLHS(1);
LinearConstraint<IPETBuilder.ExecutionEdge> exitRhsProto = new LinearConstraint<IPETBuilder.ExecutionEdge>(ConstraintType.Equal);
exitRhsProto.addRHS(1);
return structuralFlowConstraints(g, entryLhsProto, exitRhsProto, ctx);
}
/**
* Structural Flow Constraints:<ul>
* <li/> The flow of entry and exit is constrained by the given left-hand resp. right-hand sides
* <li/> For all other nodes, the incoming flow (left-hand) is equal to the outgoing flow (rhs)
* </ul>
*
* @param <V> node type
* @param <E> edge type
* @param <C> context type
* @param graph the flow graph to generate constraints for
* @param entryLhsProto the left-hand side of the constraint for the entry node
* @param exitRhsProto the right-hand side of the constraint for the exit node
* @param ctx the execution context
* @return the set of structural linear constraints
*/
public static <V, E, C extends CallStringProvider>
List<LinearConstraint<IPETBuilder.ExecutionEdge>>
structuralFlowConstraints(FlowGraph<V, E> graph,
LinearConstraint<IPETBuilder.ExecutionEdge> entryLhsProto,
LinearConstraint<IPETBuilder.ExecutionEdge> exitRhsProto,
IPETBuilder<C> ctx) {
List<LinearConstraint<IPETBuilder.ExecutionEdge>> constraints = new ArrayList<LinearConstraint<IPETBuilder.ExecutionEdge>>();
for (V node : graph.vertexSet()) {
LinearConstraint<IPETBuilder.ExecutionEdge> flowConstraint;
if (node.equals(graph.getEntry())) {
flowConstraint = entryLhsProto.clone();
} else if (node.equals(graph.getExit())) {
flowConstraint = exitRhsProto.clone();
} else {
flowConstraint = new LinearConstraint<IPETBuilder.ExecutionEdge>(ConstraintType.Equal);
}
for (E ingoing : graph.incomingEdgesOf(node)) {
flowConstraint.addLHS(ctx.newEdge(ingoing));
}
for (E outgoing : graph.outgoingEdgesOf(node)) {
flowConstraint.addRHS(ctx.newEdge(outgoing));
}
constraints.add(flowConstraint);
}
return constraints;
}
/**
* Compute flow constraints: Loop Bound constraints (Control Flow Graph only)
*
* @param g the flow graph
* @param ctx the invocation context
* @return A list of flow constraints
*/
public static <C extends CallStringProvider>
List<LinearConstraint<IPETBuilder.ExecutionEdge>>
loopBoundConstraints(ControlFlowGraph g, IPETBuilder<C> ctx) {
List<LinearConstraint<IPETBuilder.ExecutionEdge>> constraints = new ArrayList<LinearConstraint<IPETBuilder.ExecutionEdge>>();
// - for each loop with bound B
// -- sum(exit_loop_edges) * B <= sum(continue_loop_edges)
LoopColoring<CFGNode, ControlFlowGraph.CFGEdge> loops = g.getLoopColoring();
for (CFGNode hol : loops.getHeadOfLoops()) {
//LoopBound loopBound = g.getLoopBound(hol, ctx.getCallString());
LoopBound loopBound = ctx.getWCETTool().getLoopBound(hol, ctx.getCallString());
if (loopBound == null) {
throw new AppInfoError("No loop bound record for head of loop: " + hol + " : " + g.buildLoopBoundMap());
}
for (LinearConstraint<IPETBuilder.ExecutionEdge> loopConstraint :
constraintsForLoop(loops, hol, loopBound, ctx)) {
constraints.add(loopConstraint);
}
}
return constraints;
}
/**
* Generate Loop Constraints
*/
public static <C extends CallStringProvider>
List<LinearConstraint<IPETBuilder.ExecutionEdge>>
constraintsForLoop(LoopColoring<CFGNode, ControlFlowGraph.CFGEdge> loops,
CFGNode hol,
LoopBound loopBound,
IPETBuilder<C> ctx)
{
ExecutionContext eCtx = new ExecutionContext(hol.getControlFlowGraph().getMethodInfo(), ctx.getCallString());
List<LinearConstraint<IPETBuilder.ExecutionEdge>> loopConstraints = new ArrayList<LinearConstraint<IPETBuilder.ExecutionEdge>>();
/* marker loop constraints */
for (Entry<SymbolicMarker, LoopBoundExpr> markerBound : loopBound.getLoopBounds()) {
/* loop constraint */
LinearConstraint<IPETBuilder.ExecutionEdge> loopConstraint = new LinearConstraint<IPETBuilder.ExecutionEdge>(ConstraintType.GreaterEqual);
for (ControlFlowGraph.CFGEdge continueEdge : loops.getBackEdgesTo(hol)) {
loopConstraint.addRHS(ctx.newEdge(continueEdge));
}
/* Multiplicities */
long lhsMultiplicity = markerBound.getValue().upperBound(eCtx);
SymbolicMarker marker = markerBound.getKey();
if (marker.getMarkerType() == SymbolicMarkerType.OUTER_LOOP_MARKER) {
CFGNode outerLoopHol;
outerLoopHol = loops.getLoopAncestor(hol, marker.getOuterLoopDistance());
if (outerLoopHol == null) {
// FIXME: [annotations] This is a user error, not an assertion error
throw new AssertionError("Invalid Loop Nest Level");
}
for (ControlFlowGraph.CFGEdge exitEdge : loops.getExitEdgesOf(outerLoopHol)) {
loopConstraint.addLHS(ctx.newEdge(exitEdge), lhsMultiplicity);
}
} else {
assert (marker.getMarkerType() == SymbolicMarkerType.METHOD_MARKER);
throw new AssertionError("ILPModelBuilder: method markers not yet supported, sorry");
}
loopConstraints.add(loopConstraint);
}
return loopConstraints;
}
/**
* Compute flow constraints: Infeasible edge constraints
*
* @param g the flow graph
* @param ctx the invocation context
* @return A list of flow constraints
*/
public static <C extends CallStringProvider>
List<LinearConstraint<ExecutionEdge>>
infeasibleEdgeConstraints(ControlFlowGraph g, IPETBuilder<C> ctx) {
List<LinearConstraint<ExecutionEdge>> constraints = new ArrayList<LinearConstraint<ExecutionEdge>>();
// - for each infeasible edge
// -- edge = 0
for (CFGEdge edge : ctx.getWCETTool().getInfeasibleEdges(g, ctx.getCallString())) {
LinearConstraint<ExecutionEdge> infeasibleConstraint = new LinearConstraint<ExecutionEdge>(ConstraintType.Equal);
infeasibleConstraint.addLHS(ctx.newEdge(edge));
infeasibleConstraint.addRHS(0);
constraints.add(infeasibleConstraint);
}
return constraints;
}
/**
* Split an edge into a list of edges modeling low-level hardware decisions
*
* @param parentEdge the high-level edge to be split
* @param childEdges low-level edges
* @return constraint asserting sum f(childEdges) = f(parentEdge)
*/
public static<E> LinearConstraint<E> lowLevelEdgeSplit(E parentEdge, E... childEdges) {
LinearConstraint<E> lc = new LinearConstraint<E>(ConstraintType.Equal);
lc.addLHS(parentEdge);
for (E childEdge : childEdges) {
lc.addRHS(childEdge);
}
return lc;
}
/**
* Create a max-cost maxflow problem for the given flow graph graph, based on a
* given node to cost mapping.
*
* @param wcetTool A reference to the WCETTool
* @param problemName a unique identifier for the problem (for reporting)
* @param cs context of the method invocation
* @param cfg the graph
* @param nodeWCET cost of nodes
* @return The max-cost maxflow problem
*/
public static IPETSolver buildLocalILPModel(WCETTool wcetTool, String problemName, CallString cs,
ControlFlowGraph cfg, CostProvider<CFGNode> nodeWCET,
IPETConfig ipetConfig) {
IPETSolver ipetSolver = new IPETSolver(problemName, ipetConfig);
IPETBuilder<CallString> builder = new IPETBuilder<CallString>(wcetTool, cs);
ipetSolver.addConstraints(IPETUtils.structuralFlowConstraintsRoot(cfg.getGraph(), builder));
ipetSolver.addConstraints(IPETUtils.loopBoundConstraints(cfg, builder));
ipetSolver.addConstraints(IPETUtils.infeasibleEdgeConstraints(cfg, builder));
for (CFGNode n : cfg.vertexSet()) {
long nodeCost = nodeWCET.getCost(n);
for (ControlFlowGraph.CFGEdge e : cfg.outgoingEdgesOf(n)) {
ipetSolver.addEdgeCost(builder.newEdge(e), nodeCost);
}
}
return ipetSolver;
}
}