co.turnus.analysis.bottlenecks.AlgorithmicBottlenecks.java Source code

Java tutorial

Introduction

Here is the source code for co.turnus.analysis.bottlenecks.AlgorithmicBottlenecks.java

Source

/* 
 * 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;

    }
}