fr.tpt.aadl.launch.AADLInspectorSchedulingAnalysis.java Source code

Java tutorial

Introduction

Here is the source code for fr.tpt.aadl.launch.AADLInspectorSchedulingAnalysis.java

Source

/**
 * AADL-RAMSES
 * 
 * Copyright  2014 TELECOM ParisTech and CNRS
 * 
 * TELECOM ParisTech/LTCI
 * 
 * Authors: see AUTHORS
 * 
 * This program is free software: you can redistribute it and/or modify 
 * it under the terms of the Eclipse Public License as published by Eclipse,
 * either version 1.0 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
 * Eclipse Public License for more details.
 * You should have received a copy of the Eclipse Public License
 * along with this program.  If not, see 
 * http://www.eclipse.org/org/documents/epl-v10.php
 */

package fr.tpt.aadl.launch;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.m2m.atl.emftvm.util.VMException;
import org.eclipse.xtext.EcoreUtil2;
import org.osate.aadl2.AadlPackage;
import org.osate.aadl2.ComponentCategory;
import org.osate.aadl2.SystemImplementation;
import org.osate.aadl2.instance.ComponentInstance;
import org.osate.aadl2.instance.SystemInstance;
import org.osate.aadl2.modelsupport.errorreporting.AnalysisErrorReporterManager;
import org.osate.aadl2.util.Aadl2Util;
import org.osate.xtext.aadl2.properties.linking.PropertiesLinkingService;

import com.google.common.collect.Sets;

import fr.tpt.aadl.ramses.analysis.AnalysisResultFactory;
import fr.tpt.aadl.ramses.analysis.eg.EG2ResultModel;
import fr.tpt.aadl.ramses.analysis.eg.EGAnalyzer;
import fr.tpt.aadl.ramses.analysis.eg.model.EGModels;
import fr.tpt.aadl.ramses.analysis.eg.model.EGNode;
import fr.tpt.aadl.ramses.control.atl.AtlTransfoLauncher;
import fr.tpt.aadl.ramses.control.support.analysis.AbstractAnalyzer;
import fr.tpt.aadl.ramses.control.support.analysis.AnalysisException;
import fr.tpt.aadl.ramses.control.support.config.RamsesConfiguration;
import fr.tpt.aadl.ramses.control.support.instantiation.AadlModelInstantiatior;
import fr.tpt.aadl.ramses.control.support.instantiation.PredefinedAadlModelManager;
import fr.tpt.aadl.ramses.control.support.services.ServiceProvider;
import fr.tpt.aadl.ramses.control.support.utils.Command;
import fr.tpt.aadl.ramses.control.support.utils.Names;
import fr.tpt.aadl.ramses.control.support.utils.WaitMonitor;
import fr.tpt.aadl.sched.aadlinspector.AADLInspectorLauncher;
import fr.tpt.aadl.sched.aadlinspector.output.AnalysisResult;
import fr.tpt.aadl.sched.aadlinspector.output.ResponseTimeResult;
import fr.tpt.aadl.sched.aadlinspector.output.ResponseTimeResult.TaskResponseTimeResult;
import fr.tpt.aadl.sched.wcetanalysis.result.reducedba.AnalysisModel;

public class AADLInspectorSchedulingAnalysis extends AbstractAnalyzer {

    private final static String ANALYZER_NAME = Names.TIMING_ANALYSIS_PLUGIN_NAME;
    public final static String PLUGIN_NAME = Names.TIMING_ANALYSIS_PLUGIN_NAME;
    private final static String PLUGIN_ID = Names.TIMING_ANALYSIS_PLUGIN_NAME;
    private AadlModelInstantiatior _instantiator;
    private PredefinedAadlModelManager _predefinedResourcesManager;
    private String outputModelIdentifier;
    private Logger _logger = Logger.getLogger(AADLInspectorSchedulingAnalysis.class);
    private Map<ComponentInstance, List<ResponseTimeResult>> responseTimeResultList = new HashMap<ComponentInstance, List<ResponseTimeResult>>();
    private ResourceSet resourceSet = new ResourceSetImpl();

    public AADLInspectorSchedulingAnalysis(AadlModelInstantiatior instantiator,
            PredefinedAadlModelManager predefinedResourcesManager) {
        _instantiator = instantiator;
        _predefinedResourcesManager = predefinedResourcesManager;
    }

    @Override
    public String getRegistryName() {
        return ANALYZER_NAME;
    }

    @Override
    public String getPluginName() {
        return PLUGIN_NAME;
    }

    @Override
    public String getPluginId() {
        return PLUGIN_ID;
    }

    boolean first = true;
    public int cpt;
    public int cpt_failed = 0;
    public int size;
    private Map<ResponseTimeResult, List<EGNode>> analysisResult = new HashMap<ResponseTimeResult, List<EGNode>>();
    private IProgressMonitor _monitor;
    private RamsesConfiguration _config;

    @Override
    public void setParameters(Map<String, Object> parameters) {
        if (first) {
            mode = (String) parameters.get("Mode");
            AnalysisResultFactory f = AnalysisResultFactory.eINSTANCE;
            currentResult = f.createAnalysisArtifact();
            parameters.put("AnalysisResult", currentResult);
            outputModelIdentifier = (String) parameters.get("OutputModelIdentifier");
            first = false;
        }
    }

    public List<EGNode> performAnalysis(ComponentInstance cpu, RamsesConfiguration config,
            AnalysisErrorReporterManager errorReporter, final IProgressMonitor monitor) throws AnalysisException {

        this._config = config;
        this._monitor = monitor;

        /* XXX: test avec plusieurs cpu
         * cpu per cpu
         * Modify transformation to copy only selected CPU instances into subcomponent; 
         *       propagate to properties. Use EMFUtils.allInsta... to filter out.
         *       propagate to connections (bus, etc...)
         * Extract one configuration per CPU.
         * model to exhibit = merge des listes de EGNode  slectionner.
        */

        EGAnalyzer ega = new EGAnalyzer(_instantiator, _predefinedResourcesManager);
        Map<ComponentInstance, List<EGNode>> wcetMap = ega.extractWCETModelsMap(cpu);

        List<Set<EGNode>> listForProduct = new ArrayList<Set<EGNode>>();
        for (ComponentInstance thread : wcetMap.keySet()) {
            Set<EGNode> tmp = new LinkedHashSet<EGNode>(wcetMap.get(thread));
            List<EGNode> toRemove = new ArrayList<EGNode>();
            for (EGNode t : tmp)
                if (!t.hasCapacity())
                    toRemove.add(t);
            tmp.removeAll(toRemove);
            listForProduct.add(tmp);
        }

        Set<List<EGNode>> res = Sets.cartesianProduct(listForProduct);
        size = res.size();
        String message = "INFO: " + size + " executions of AADLInspector schedulability"
                + "analysis will be executed.";
        _logger.trace(message);

        if (size == 0) {
            message = "At least one task has no worst case execution time defined in the " + "analysis model";
            _logger.error(message);
            ServiceProvider.SYS_ERR_REP.error(message, false);
            return null;
        }
        // Launch analysis for each configuration
        // If one is not schedulable, exhibit this one
        // otherwise exhibit one that maximizes CPU usage

        int iter = 0;
        final Thread[] aadlInspectorThreads = new Thread[size];

        final AADLInspectorSchedulingAnalysis app = this;
        for (List<EGNode> egNodeList : res) {
            String outputPath;
            if (config.getAadlInspectorOutputDir() != null)
                outputPath = config.getAadlInspectorOutputDir().getAbsolutePath();
            else
                outputPath = config.getRamsesOutputDir().getAbsolutePath();
            File tmpDir = new File(outputPath + "/wcet_" + iter);
            if (!tmpDir.exists())
                tmpDir.mkdir();
            // Execute analysis in several threads
            aadlInspectorThreads[iter] = new AADLInspectorAnalysisThread(app, egNodeList, tmpDir, cpu,
                    "wcet_" + iter, "automatic");
            iter++;
        }

        Command cmd = new Command() {
            int status = Command.UNSET;

            @Override
            public int run() throws Exception {
                for (Thread t : aadlInspectorThreads) {
                    t.start();
                }

                // Wait all the thread end.
                synchronized (app) {
                    app.wait();
                }
                status = Command.OK;
                return Command.OK;
            }

            @Override
            public boolean isCanceled() {
                return monitor.isCanceled();
            }

            @Override
            public String getLabel() {
                return null;
            }

            @Override
            public int getStatus() {
                return status;
            }

            @Override
            public Process getProcess() {
                // TODO Auto-generated method stub
                return null;
            }
        };

        int exitStatus;
        WaitMonitor wm = new WaitMonitor(cmd);
        wm.start();
        try {
            exitStatus = wm.waitAndCheck(500);
        } catch (Exception e) {
            killThreads(aadlInspectorThreads);
            String msg = "AADL inspector monitoring has been interrupted";
            _logger.fatal(msg, e);
            throw new RuntimeException(msg, e);
        }

        switch (exitStatus) {
        case Command.FATAL: {
            Exception e = wm.getCaughtException();
            String msg = "AADL Inspector has failed";
            _logger.fatal(msg, e);
            killThreads(aadlInspectorThreads);
            throw new RuntimeException(msg, e);
        }

        case Command.ERROR: {
            // TODO
        }

        case Command.CANCEL: {
            killThreads(aadlInspectorThreads);
            String msg = "AADL Inspector has been canceled";
            _logger.trace(msg);
            throw new OperationCanceledException(msg);
        }

        case Command.OK: {
            String msg = "AADL Inspector process done";
            _logger.trace(msg);
            break;
        }

        default: {
            String errMsg = "AADL Inspector error: unknown exit code";
            _logger.error(errMsg);
            ServiceProvider.SYS_ERR_REP.error(errMsg, true);
        }
        }

        int i = 0;
        String outputModelId = "";
        List<EGNode> resultingEGNodeList = new ArrayList<EGNode>();

        for (ComponentInstance ci : responseTimeResultList.keySet()) {
            List<EGNode> tmp = null;
            for (ResponseTimeResult ufr : responseTimeResultList.get(ci)) {
                double maxResponseTime = 0.0;
                boolean schedulable = true;

                double responseTimeSum = 0;
                if (ufr.isResult() == false) {
                    tmp = new ArrayList<EGNode>();
                    tmp.addAll(this.analysisResult.get(ufr));
                    outputModelId = "wcet_" + (i + 1);
                    schedulable = false;
                    break;
                }
                for (TaskResponseTimeResult rt : ufr.getResponseTimes().values())
                    responseTimeSum += rt.worst;
                if (responseTimeSum >= maxResponseTime && schedulable) {
                    tmp = new ArrayList<EGNode>();
                    tmp.addAll(this.analysisResult.get(ufr));
                    maxResponseTime = responseTimeSum;
                    outputModelId = "wcet_" + (i + 1);
                }
                i++;
            }
            if (tmp != null)
                resultingEGNodeList.addAll(tmp);
            else {
                String errMsg = "AADL Inspector error: results show a schedulable"
                        + " task set, tasks have execution time, but the sum of tasks response time is null";
                _logger.error(errMsg);
                ServiceProvider.SYS_ERR_REP.error(errMsg, true);
            }
        }

        return resultingEGNodeList;

    }

    private void killThreads(Thread[] aadlInspectorThreads) {
        for (Thread t : aadlInspectorThreads)
            t.interrupt();
    }

    public void performAnalysis(SystemInstance root, RamsesConfiguration config,
            AnalysisErrorReporterManager errorReporter, IProgressMonitor monitor) throws AnalysisException {

        List<EGNode> resultingEGNodeList = new ArrayList<EGNode>();
        for (ComponentInstance ci : EcoreUtil2.getAllContentsOfType(root, ComponentInstance.class)) {
            if (ci.getCategory().equals(ComponentCategory.PROCESSOR)) {
                List<EGNode> executionGraphNodeList = this.performAnalysis(ci, config, errorReporter, monitor);
                if (executionGraphNodeList != null)
                    resultingEGNodeList.addAll(executionGraphNodeList);
                else
                    return;
            }
        }

        this.size = 1;
        String resultPath;
        if (config.getAadlInspectorOutputDir() != null)
            resultPath = config.getAadlInspectorOutputDir().getAbsolutePath();
        else
            resultPath = config.getRamsesOutputDir().getAbsolutePath();
        File resultDir = new File(resultPath + "/" + outputModelIdentifier);
        if (!resultDir.exists())
            resultDir.mkdir();
        AADLInspectorAnalysisThread last = new AADLInspectorAnalysisThread(this, resultingEGNodeList, resultDir,
                root, outputModelIdentifier, mode);
        Thread t = new Thread(last);
        t.start();
        try {
            synchronized (this) {
                wait();
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return;
    }

    synchronized private void addAnalysisResult(ComponentInstance ci, ResponseTimeResult rtr, List<EGNode> nodes) {
        this.analysisResult.put(rtr, nodes);

        if (this.responseTimeResultList.containsKey(ci)) {
            this.responseTimeResultList.get(ci).add(rtr);
        } else {
            List<ResponseTimeResult> l = new ArrayList<ResponseTimeResult>();
            l.add(rtr);
            this.responseTimeResultList.put(ci, l);
        }
    }

    private Resource produceAnalysisAADLModel(ResourceSet rs, AnalysisModel m, File outputDir,
            SystemInstance systemInstance, String outputModelId, List<ComponentInstance> cpuList,
            IProgressMonitor monitor) {
        Wcet2AadlEMFTVMLauncher launcher = new Wcet2AadlEMFTVMLauncher(m, _instantiator,
                _predefinedResourcesManager, cpuList);

        Aadl2Util.setUseTunedEqualsMethods(false);

        launcher.setOutputPackageName(outputModelId);
        File aadlWithWcetFile = new File(
                outputDir.getAbsolutePath() + File.separator + outputModelIdentifier + ".aadl2");
        Resource rootResource = systemInstance.eResource();
        Resource aadlModelWithWcet = launcher.doTransformation(rs, rootResource, outputDir.getAbsolutePath(),
                "_" + outputModelId, monitor);

        aadlModelWithWcet.setURI(URI.createFileURI(aadlWithWcetFile.getAbsolutePath()));
        _instantiator.serialize(aadlModelWithWcet, aadlWithWcetFile.getAbsolutePath());
        Aadl2Util.setUseTunedEqualsMethods(false);
        return aadlModelWithWcet;
    }

    static class AADLInspectorAnalysisThread extends Thread {
        private List<EGNode> egNodeList;
        private File outputDir;
        private SystemInstance root;
        private final AADLInspectorSchedulingAnalysis initiator;
        private String outputModelId;
        private String mode;
        private List<ComponentInstance> cpuToIgnore = new ArrayList<ComponentInstance>();

        public AnalysisResult analysisResult;

        private static Logger _LOGGER = Logger.getLogger(AADLInspectorAnalysisThread.class);

        public AADLInspectorAnalysisThread(AADLInspectorSchedulingAnalysis aadlInspectorSchedulingAnalysis,
                List<EGNode> egNodeList, File outputDir, ComponentInstance cpu, String outputModelId, String mode) {
            this.initiator = aadlInspectorSchedulingAnalysis;
            this.egNodeList = egNodeList;
            this.outputDir = outputDir;
            this.root = cpu.getSystemInstance();
            this.outputModelId = outputModelId;
            this.mode = mode;
            for (ComponentInstance ci : EcoreUtil2.getAllContentsOfType(root, ComponentInstance.class)) {
                if (ci.getCategory().equals(ComponentCategory.PROCESSOR) && !ci.equals(cpu)) {
                    this.cpuToIgnore.add(ci);
                }
            }
        }

        public AADLInspectorAnalysisThread(final AADLInspectorSchedulingAnalysis aadlInspectorSchedulingAnalysis,
                List<EGNode> egNodeList, File outputDir, SystemInstance root, String outputModelId, String mode) {
            this.initiator = aadlInspectorSchedulingAnalysis;
            this.egNodeList = egNodeList;
            this.outputDir = outputDir;
            this.root = root;
            this.outputModelId = outputModelId;
            this.mode = mode;
        }

        public void run() {
            Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

            EGModels models = new EGModels();
            for (EGNode node : egNodeList) {
                models.put((ComponentInstance) node.getThread(), node);
            }
            try {
                EG2ResultModel eg2resultModel = new EG2ResultModel(models);
                AnalysisModel result = eg2resultModel.getAnalysisModel();

                if (initiator._monitor.isCanceled()) {
                    String msg = "analysis has been canceled before analysis";
                    _LOGGER.trace(msg);
                    return;
                }

                Resource aadlModel = initiator.produceAnalysisAADLModel(initiator.resourceSet, result, outputDir,
                        root, outputModelId, cpuToIgnore, initiator._monitor);

                PropertiesLinkingService pls = new PropertiesLinkingService();
                AadlPackage pkg = (AadlPackage) aadlModel.getContents().get(0);
                SystemImplementation si = (SystemImplementation) pls
                        .findNamedElementInsideAadlPackage(outputModelId + ".impl", pkg.getOwnedPublicSection());
                SystemInstance sinst = initiator._instantiator.instantiate(si);

                AADLInspectorLauncher launcher = new AADLInspectorLauncher(
                        initiator._config.getAadlInspectorInstallDir());
                analysisResult = launcher.launchAnalysis(sinst, outputDir, mode, initiator._monitor);
                if (initiator._monitor.isCanceled()) {
                    String msg = "analysis has been canceled after analysis";
                    _LOGGER.trace(msg);
                    return;
                }

                for (ComponentInstance ci : EcoreUtil2.getAllContentsOfType(sinst, ComponentInstance.class)) {
                    if (ci.getCategory().equals(ComponentCategory.PROCESSOR)) {
                        ResponseTimeResult ufr = analysisResult.getResponseTimeResults("root." + ci.getName());
                        initiator.addAnalysisResult(ci, ufr, egNodeList);
                    }
                }
                synchronized (this.initiator.currentResult) {
                    analysisResult.setIterationNb(this.initiator.iterationCounter);
                    analysisResult.normalize(this.initiator.currentResult);
                }
            } catch (InterruptedException e) {
                // Analysis has been canceled by the user. Stop the analysis.
                String msg = "Intermediate AADLInspector has been interrupted";
                _LOGGER.trace(msg);
                return;
            } catch (OperationCanceledException e) {
                // Analysis has been canceled by the user. Stop the analysis.
                _LOGGER.trace(cancelMsg());
                return;
            } catch (VMException e) {
                if (e.getCause() instanceof OperationCanceledException) {
                    // Analysis has been canceled by the user. Stop the analysis.
                    _LOGGER.trace(cancelMsg());
                    return;
                } else {
                    e.printStackTrace();
                    _LOGGER.fatal(fatalMsg(), e);
                    fatal();
                }
            } catch (Exception e) {
                e.printStackTrace();
                _LOGGER.fatal(fatalMsg(), e);
                fatal();
            }

            synchronized (root) {
                initiator.cpt++;
                String message = initiator.cpt + " execution(s) of AADLInspector schedulability" + " done.";
                initiator._monitor.subTask(message);
                _LOGGER.trace(message);
                evaluateIfFinished();
            }

            return;
        }

        private String fatalMsg() {
            return initiator.cpt_failed + " execution(s) of AADLInspector schedulability" + " failed.";
        }

        private void fatal() {
            synchronized (root) {
                initiator.cpt++;
                initiator.cpt_failed++;
                evaluateIfFinished();
            }
        }

        private String cancelMsg() {
            return "Intermediate AADLInspector has been canceled";
        }

        void evaluateIfFinished() {
            if (initiator.cpt == initiator.size)
                synchronized (initiator) {
                    initiator.notify();
                    initiator.cpt = 0;
                }
        }

    }

    List<String> _ransformationModuleList = null;
    private int iterationCounter;

    @Override
    public List<String> getTransformationModuleList() {
        if (_ransformationModuleList == null) {
            _ransformationModuleList = AtlTransfoLauncher.getUninstanciateTransformationModuleList();
            _ransformationModuleList.add("/WcetAnalysis/ReducedBA");
        }
        return _ransformationModuleList;
    }

    @Override
    public void setIterationCounter(int iterationCounter) {
        this.iterationCounter = iterationCounter;
    }
}