Java tutorial
/* * TURNUS, the co-exploration framework * * Copyright (C) 2014 EPFL SCI STI MM * * This file is part of TURNUS. * * TURNUS 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. * * TURNUS 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 TURNUS. If not, see <http://www.gnu.org/licenses/>. * * Additional permission under GNU GPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or combining it * with Eclipse (or a modified version of Eclipse or an Eclipse plugin or * an Eclipse library), containing parts covered by the terms of the * Eclipse Public License (EPL), the licensors of this Program grant you * additional permission to convey the resulting work. Corresponding Source * for a non-source form of such a combination shall include the source code * for the parts of Eclipse libraries used as well as that of the covered work. * */ package co.turnus.analysis.bottlenecks; import static co.turnus.analysis.bottlenecks.AlgorithmicBottlenecksOptions.IMPACT_ANALYSIS_ACTIONS; import static co.turnus.analysis.bottlenecks.AlgorithmicBottlenecksOptions.IMPACT_ANALYSIS_ACTORLEVEL; import static co.turnus.analysis.bottlenecks.AlgorithmicBottlenecksOptions.IMPACT_ANALYSIS_POINTS; import static co.turnus.analysis.bottlenecks.AlgorithmicBottlenecksOptions.IMPACT_ANALYSIS_RUN; import static co.turnus.trace.weighter.TraceWeighter.MEAN; import static co.turnus.trace.weighter.TraceWeighter.VARIANCE; import static co.turnus.trace.TraceOptions.SENS_FSM; import static co.turnus.trace.TraceOptions.SENS_GUARD; import static co.turnus.trace.TraceOptions.SENS_PORT; import static co.turnus.trace.TraceOptions.SENS_STATEVAR; import static co.turnus.trace.TraceOptions.SENS_TOKENS; import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.apache.commons.configuration.BaseConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.math3.util.FastMath; import co.turnus.analysis.Analysis; import co.turnus.analysis.bottlenecks.util.HotSpotsDataCollector; import co.turnus.analysis.bottlenecks.util.HotspotsDataAnalyser; import co.turnus.analysis.bottlenecks.util.HotspotsDataAnalyser.Key; import co.turnus.analysis.bottlenecks.util.HotspotsDataAnalyser.Order; import co.turnus.analysis.data.bottlenecks.ActionImpactData; import co.turnus.analysis.data.bottlenecks.AlgoBottlenecksData; import co.turnus.analysis.data.bottlenecks.BottlenecksFactory; import co.turnus.analysis.data.bottlenecks.ExtendExecData; import co.turnus.analysis.data.bottlenecks.HotspotsData; import co.turnus.analysis.data.bottlenecks.ImpactData; import co.turnus.trace.weighter.TraceWeighter; import co.turnus.analysis.util.AnalysisUtil; import co.turnus.dataflow.Action; import co.turnus.dataflow.Actor; import co.turnus.dataflow.ActorClass; import co.turnus.dataflow.Network; import co.turnus.trace.Dependency; import co.turnus.trace.Step; import co.turnus.trace.Trace; import co.turnus.trace.TraceProject; import co.turnus.util.TurnusLogger; import com.google.common.collect.HashBasedTable; import com.google.common.collect.Sets; import com.google.common.collect.Table; import com.google.common.collect.Table.Cell; public class AlgorithmicBottlenecks extends Analysis { protected static final Table<String, String, Double> NULL_RATIO_TABLE = null; public static String EARLY_START = "pba.algorithmicBottlenecks.earlyStart"; public static String EARLY_FINISH = "pba.algorithmicBottlenecks.earlyFinish"; public static String LATEST_START = "pba.algorithmicBottlenecks.latestStart"; public static String LATEST_FINISH = "pba.algorithmicBottlenecks.latestFinish"; public static String SLACK = "pba.algorithmicBottlenecks.slack"; public static String PARTIAL_CP = "pba.algorithmicBottlenecks.partialCP"; protected TraceProject project; protected TraceWeighter tweighter; protected int iterationId; public AlgorithmicBottlenecks(TraceProject project, TraceWeighter tweighter) { this.project = project; this.tweighter = tweighter; iterationId = 0; } protected HotspotsData find(Table<String, String, Double> ratiosTable) { // check if the trace should be initialised initTrace(); Trace trace = project.getTrace(); Network network = project.getNetwork(); HotSpotsDataCollector collector = new HotSpotsDataCollector(network); iterationId++; Step tStep = null; double cpValue = Double.MIN_VALUE; for (long stepId = 0; stepId < trace.getLength(); stepId++) { Step step = trace.getStep(stepId); double es = 0.0; for (Dependency in : step.getIncomings()) { double tmp = in.getSource().getAttribute(EARLY_FINISH + iterationId); es = FastMath.max(tmp, es); } // evaluate early start and finish time double[] cl = getWeight(step, ratiosTable); double ef = es + cl[MEAN]; step.setAttribute(EARLY_START + iterationId, es); step.setAttribute(EARLY_FINISH + iterationId, ef); if (ef > cpValue) { cpValue = ef; tStep = step; } } for (long stepId = trace.getLength() - 1; stepId >= 0; stepId--) { Step step = trace.getStep(stepId); double lf = cpValue; for (Dependency out : step.getOutgoings()) { double tmp = out.getTarget().getAttribute(LATEST_START + iterationId); lf = FastMath.min(tmp, lf); } double[] cl = getWeight(step, ratiosTable); double ls = lf - cl[MEAN]; step.setAttribute(LATEST_FINISH + iterationId, lf); step.setAttribute(LATEST_START + iterationId, ls); double ef = step.getAttribute(EARLY_FINISH + iterationId); double slack = lf - ef; step.setAttribute(SLACK + iterationId, slack); // log computational load with the slack collector.addExecution(step, cl, slack); } // Walk back the critical path following the early finish gradient Step next = tStep; Set<Step> predecessors = new HashSet<>(); while (next != null) { collector.addCriticalExecution(next, getWeight(next, ratiosTable)); predecessors.clear(); for (Dependency in : next.getIncomings()) { predecessors.add(in.getSource()); } next = null; double efMax = Double.MIN_VALUE; for (Step s : predecessors) { // it's the same as the partial critical path double ef = s.getAttribute(EARLY_FINISH + iterationId); if (ef > efMax) { efMax = ef; next = s; } } } return collector.getResults(); } private double[] getWeight(Step step, Table<String, String, Double> ratiosTable) { double[] cl = tweighter.getWeight(step); if (ratiosTable != NULL_RATIO_TABLE && ratiosTable.contains(step.getActor(), step.getAction())) { double r = ratiosTable.get(step.getActor(), step.getAction()); cl = cl.clone(); cl[MEAN] = r * cl[MEAN]; cl[VARIANCE] = r * cl[VARIANCE]; } return cl; } private ImpactData impactAnalysis(HotspotsDataAnalyser hsdAnalyzer) { BottlenecksFactory f = BottlenecksFactory.eINSTANCE; ImpactData impactData = f.createImpactData(); boolean actorLevel = getOption(IMPACT_ANALYSIS_ACTORLEVEL, false); impactData.setActorsLevel(actorLevel); int actions = getOption(IMPACT_ANALYSIS_ACTIONS, 4); int grid = getOption(IMPACT_ANALYSIS_POINTS, 10); int points[] = AnalysisUtil.linspacei(0, 100, grid + 1); int iterations = actions * grid; int iteration = 1; double cpVal = hsdAnalyzer.getSumData().getCriticalExec().getClockCyclesMean(); Table<String, String, Double> rtTable = HashBasedTable.create(); if (actorLevel) { TurnusLogger.info("Actor Level, for " + actions + " actions. Required Iterations: " + iterations); Table<Actor, Action, ExtendExecData> table = hsdAnalyzer.getSumDataTable(Actor.class, Key.CRITICAL_CLOCKCYCLES, Order.DECREASING); int analysedActions = 0; for (Cell<Actor, Action, ExtendExecData> entry : table.cellSet()) { Actor actor = entry.getRowKey(); Action action = entry.getColumnKey(); ActionImpactData impactStep = f.createActionImpactData(); impactStep.setAction(action); impactStep.getActors().add(actor); for (int i = 1; i < points.length; i++) { double ratio = (100.0 - points[i]) / 100.0; rtTable.clear(); rtTable.put(actor.getId(), action.getId(), ratio); TurnusLogger.info("iteration " + iteration++ + " of " + iterations); TurnusLogger.debug( "analysisng actor: " + actor.getId() + ", " + action.getId() + ", ratio " + ratio); double[] cp = measure(rtTable); double cplr = (1 - cp[MEAN] / (cpVal)) * 100; double wlr = (1 - ratio) * 100; TurnusLogger.debug("Reduction: " + cplr + ", at " + wlr); impactStep.getWlReduction().add(wlr); impactStep.getCplReduction().add(cplr); } impactData.getActionsData().add(impactStep); analysedActions++; if (analysedActions == actions) { break; } } } else { TurnusLogger.info("Actor Level, for " + actions + " actions. Required Iterations: " + iterations); Table<ActorClass, Action, ExtendExecData> table = hsdAnalyzer.getSumDataTable(ActorClass.class, Key.CRITICAL_CLOCKCYCLES, Order.DECREASING); int analysedActions = 0; for (Cell<ActorClass, Action, ExtendExecData> entry : table.cellSet()) { Action action = entry.getColumnKey(); Collection<Actor> actors = action.getOwner().getActors(); ActionImpactData impactStep = f.createActionImpactData(); impactStep.setAction(action); impactStep.getActors().addAll(actors); for (int i = 1; i < points.length; i++) { double ratio = (100.0 - points[i]) / 100.0; rtTable.clear(); for (Actor actor : actors) { rtTable.put(actor.getId(), action.getId(), ratio); } TurnusLogger.info("iteration " + iteration++ + " of " + iterations); TurnusLogger.debug( "analysisng actor-class: " + action.getOwner().getName() + ", " + action.getId()); double[] cp = measure(rtTable); double cplr = (1 - cp[MEAN] / (cpVal)) * 100; double wlr = (1 - ratio) * 100; TurnusLogger.debug("Reduction: " + cplr + ", at " + wlr); impactStep.getWlReduction().add(wlr); impactStep.getCplReduction().add(cplr); } impactData.getActionsData().add(impactStep); analysedActions++; if (analysedActions == actions) { break; } } } return impactData; } private void initTrace() { if (!project.isTraceLoaded()) { Configuration config = new BaseConfiguration(); config.setProperty(SENS_STATEVAR, false); config.setProperty(SENS_FSM, false); config.setProperty(SENS_PORT, false); config.setProperty(SENS_GUARD, false); config.setProperty(SENS_TOKENS, false); project.loadTrace(config); } } protected double[] measure(Table<String, String, Double> ratiosTable) { // check if the trace should be initialised initTrace(); Trace trace = project.getTrace(); double[] cp = { 0, 0 }; iterationId++; Collection<Step> predecessors = Sets.newHashSet(); for (long stepId = 0; stepId < trace.getLength(); stepId++) { Step step = trace.getStep(stepId); double[] cl = getWeight(step, ratiosTable); predecessors.clear(); for (Dependency in : step.getIncomings()) { predecessors.add(in.getSource()); } double[] pcp = { 0, 0 }; for (Step pred : predecessors) { double[] tmpPcp = pred.getAttribute(PARTIAL_CP + iterationId); if (tmpPcp[MEAN] > pcp[MEAN]) { pcp[MEAN] = tmpPcp[MEAN]; pcp[VARIANCE] = tmpPcp[VARIANCE]; } } pcp[MEAN] += cl[MEAN]; pcp[VARIANCE] += cl[VARIANCE]; step.setAttribute(PARTIAL_CP + iterationId, pcp); // update the global one if (pcp[MEAN] > cp[MEAN]) { cp = pcp; } } return cp; } @Override public AlgoBottlenecksData run() { AlgoBottlenecksData report = BottlenecksFactory.eINSTANCE.createAlgoBottlenecksData(); report.setNetwork(project.getNetwork()); report.setName("Algorithmic Bottlenecks Report Data"); report.setAlgorithm(AlgorithmicBottlenecks.class.getName()); // hotspots analysis TurnusLogger.info("{HOTSPOTS ANALYSIS} start..."); HotspotsData hsData = find(NULL_RATIO_TABLE); report.setHotspotsData(hsData); TurnusLogger.info("{HOTSPOTS ANALYSIS} done!"); // impact analysis if (getOption(IMPACT_ANALYSIS_RUN, false)) { TurnusLogger.info("{IMPACT ANALYSIS} start..."); HotspotsDataAnalyser hsdAnalyzer = new HotspotsDataAnalyser(report); ImpactData results = impactAnalysis(hsdAnalyzer); report.setImpactData(results); TurnusLogger.info("{IMPACT ANALYSIS} done!"); } return report; } }