co.turnus.analysis.pipelining.SimplePipelining.java Source code

Java tutorial

Introduction

Here is the source code for co.turnus.analysis.pipelining.SimplePipelining.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.pipelining;

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.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.configuration.BaseConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;

import co.turnus.analysis.Analysis;
import co.turnus.analysis.data.pipelining.PipeliningFactory;
import co.turnus.analysis.data.pipelining.SimpleActionPipeliningData;
import co.turnus.analysis.data.pipelining.SimplePipelingData;
import co.turnus.common.util.CommonDataUtil;
import co.turnus.dataflow.Action;
import co.turnus.dataflow.Actor;
import co.turnus.dataflow.Network;
import co.turnus.generic.Pair;
import co.turnus.trace.Dependency;
import co.turnus.trace.Dependency.Direction;
import co.turnus.trace.Dependency.Kind;
import co.turnus.trace.Step;
import co.turnus.trace.Trace;
import co.turnus.trace.TraceDecorator;
import co.turnus.trace.TraceProject;
import co.turnus.util.ProgressTheadPrinter;
import co.turnus.util.TurnusLogger;

public class SimplePipelining extends Analysis {

    private class ActorData {

        private class ActionData {

            long firings;
            Map<Action, Boolean> splittable;
            SummaryStatistics statsUnconstrained;
            SummaryStatistics statsPipelinabled;

            ActionData() {
                splittable = new HashMap<>();
                statsPipelinabled = new SummaryStatistics();
                statsUnconstrained = new SummaryStatistics();
                firings = 0;
            }

            void addFiring(Iterable<Dependency> incomings) {
                firings++;

                for (Dependency d : incomings) {
                    Pair<Actor, Action> pair = traceDecorator.getActorActionPair(d.getSource());
                    if (pair.a == actor) {
                        Action action = pair.b;
                        if (d.getKind() != Kind.STATEVAR) {
                            if (!splittable.containsKey(action)) {
                                splittable.put(action, true);
                            } else {
                                boolean val = splittable.get(action) & true;
                                splittable.put(action, val);
                            }
                        } else {
                            if (d.getDirection() == Direction.READ_READ) {
                                if (!splittable.containsKey(action)) {
                                    splittable.put(action, true);
                                } else {
                                    boolean val = splittable.get(action) & true;
                                    splittable.put(action, val);
                                }
                            } else {
                                splittable.put(action, false);
                            }
                        }
                    }
                }
            }

            void addStatistics(long unconstrained, long pipelinable) {
                statsUnconstrained.addValue(unconstrained);
                statsPipelinabled.addValue(pipelinable);
            }

            SimpleActionPipeliningData collectResults() {
                SimpleActionPipeliningData data = PipeliningFactory.eINSTANCE.createSimpleActionPipeliningData();
                data.setFirings(firings);
                data.setPipelinableRepetitions(CommonDataUtil.createFrom(statsPipelinabled));
                data.setUnconstrainedRepetitions(CommonDataUtil.createFrom(statsUnconstrained));
                for (Entry<Action, Boolean> entry : splittable.entrySet()) {
                    if (entry.getValue().booleanValue()) {
                        data.getSplittableActions().add(entry.getKey());
                    }
                }
                return data;
            }
        }

        final Actor actor;
        Map<Action, ActionData> actionsData;
        Action lastFiredAction;
        long uncostrainedConsecFirinings;
        long pipelinableConsecFirinings;

        ActorData(Actor actor) {
            this.actor = actor;
        }

        void addFiring(Pair<Actor, Action> pair, Iterable<Dependency> incomings) {
            // update the last firings
            Action action = pair.getB();
            if (lastFiredAction != action) {
                if (lastFiredAction != null) {
                    actionsData.get(lastFiredAction).addStatistics(uncostrainedConsecFirinings,
                            pipelinableConsecFirinings);
                }
                lastFiredAction = action;
                uncostrainedConsecFirinings = 1;
                pipelinableConsecFirinings = 0;
            } else {
                boolean pipelieable = true;
                for (Dependency d : incomings) {
                    if ((d.getKind() == Kind.STATEVAR) && (d.getDirection() != Direction.READ_READ)) {
                        pipelieable = false;
                        break;
                    }
                }

                // update counters
                uncostrainedConsecFirinings++;
                if (pipelieable) {
                    pipelinableConsecFirinings++;
                } else {
                    pipelinableConsecFirinings = 0;
                }
            }

            // update action data
            actionsData.get(action).addFiring(incomings);
        }

        Collection<SimpleActionPipeliningData> collectResults() {
            Collection<SimpleActionPipeliningData> dataSet = new HashSet<>();
            for (Entry<Action, ActionData> entry : actionsData.entrySet()) {
                SimpleActionPipeliningData data = entry.getValue().collectResults();
                data.setActor(actor);
                data.setAction(entry.getKey());
                dataSet.add(data);
            }
            return dataSet;
        }

        void endAnalysis() {
            if (lastFiredAction != null) {
                actionsData.get(lastFiredAction).addStatistics(uncostrainedConsecFirinings,
                        pipelinableConsecFirinings);
            }

            lastFiredAction = null;
            uncostrainedConsecFirinings = 0;
            uncostrainedConsecFirinings = 0;
        }

        void initData() {
            uncostrainedConsecFirinings = 0;
            pipelinableConsecFirinings = 0;

            lastFiredAction = null;
            actionsData = new HashMap<>();
            for (Action a : actor.getActorClass().getActions()) {
                actionsData.put(a, new ActionData());
            }
        }

    }

    private TraceProject traceProject;
    private TraceDecorator traceDecorator;
    private Map<Actor, ActorData> actorsData;
    private Network network;

    public SimplePipelining(TraceProject traceProject) {
        this.traceProject = traceProject;
        network = traceProject.getNetwork();
        traceDecorator = traceProject.getTraceDecorator();

        actorsData = new HashMap<>();
        for (Actor a : network.getActors()) {
            actorsData.put(a, new ActorData(a));
        }
    }

    private SimplePipelingData collectResults() {
        SimplePipelingData report = PipeliningFactory.eINSTANCE.createSimplePipelingData();
        report.setNetwork(network);
        report.setName("Simple Pipelining Analysis Report Data");
        report.setAlgorithm(SimplePipelining.class.getName());

        for (ActorData data : actorsData.values()) {
            report.getActionsData().addAll(data.collectResults());
        }

        // FIXME should be replaced with report.toString() ?
        TurnusLogger.debug("Simple Pipelining Analysis Report Data:");
        for (SimpleActionPipeliningData data : report.getActionsData()) {
            TurnusLogger.debug("Actor: " + data.getActor().getId() + ", action: " + data.getAction().getId());
            TurnusLogger.debug("-> firings: " + data.getFirings() + ", consec (p, u): "
                    + data.getPipelinableRepetitions().getMean() + ", "
                    + data.getUnconstrainedRepetitions().getMean());
            TurnusLogger.debug("-> splittable actions: ");
            for (Action a : data.getSplittableActions()) {
                TurnusLogger.debug("  " + a.getId());
            }
        }

        return report;
    }

    private void initTrace() {
        if (!traceProject.isTraceLoaded()) {
            Configuration config = new BaseConfiguration();
            config.setProperty(SENS_STATEVAR, true);
            config.setProperty(SENS_FSM, false);
            config.setProperty(SENS_PORT, false);
            config.setProperty(SENS_GUARD, false);
            config.setProperty(SENS_TOKENS, false);
            traceProject.loadTrace(config);
        }
    }

    @Override
    public SimplePipelingData run() {
        // check if the trace should be loaded
        initTrace();

        Trace trace = traceProject.getTrace();
        long traceSize = trace.getLength();

        // launch the thread status printer
        ProgressTheadPrinter progressPrinter = new ProgressTheadPrinter("Trace Graph post-processing", traceSize);
        progressPrinter.start();

        // init the actors data
        for (ActorData d : actorsData.values()) {
            d.initData();
        }

        // start the trace analysis
        for (long stepId = 0; stepId < traceSize; stepId++) {
            Step step = trace.getStep(stepId);
            Pair<Actor, Action> pair = traceDecorator.getActorActionPair(step);
            actorsData.get(pair.getA()).addFiring(pair, step.getIncomings());
            progressPrinter.increment();
        }

        // end the analysis
        for (ActorData d : actorsData.values()) {
            d.endAnalysis();
        }

        // stop the progress monitor
        try {
            progressPrinter.finish();
            progressPrinter.join();
        } catch (InterruptedException e) {
            TurnusLogger.warning("Progress monitor stopping error: " + e.getMessage());
        }

        return collectResults();
    }

}