Analysis: Add the active path module
authorFrancis Giraldeau <francis.giraldeau@gmail.com>
Tue, 30 Jun 2015 01:52:14 +0000 (21:52 -0400)
committerGenevieve Bastien <gbastien+lttng@versatic.net>
Fri, 16 Oct 2015 17:44:37 +0000 (13:44 -0400)
This module computes the active path from a execution graph. The active
path of a given task has all the blockings replaced recursively by the
edges representing the cause of the wait at the system level.

Change-Id: Ie19b461ebe5ad595bca43b55f380ce28db416445
Signed-off-by: Geneviève Bastien <gbastien+lttng@versatic.net>
Signed-off-by: Francis Giraldeau <francis.giraldeau@gmail.com>
Reviewed-on: https://git.eclipse.org/r/51081
Reviewed-by: Hudson CI
Reviewed-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Tested-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
12 files changed:
analysis/org.eclipse.tracecompass.analysis.graph.core/META-INF/MANIFEST.MF
analysis/org.eclipse.tracecompass.analysis.graph.core/build.properties
analysis/org.eclipse.tracecompass.analysis.graph.core/plugin.xml [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/analysis/graph/core/criticalpath/CriticalPathModule.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/analysis/graph/core/criticalpath/ICriticalPathAlgorithm.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/analysis/graph/core/criticalpath/package-info.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/AbstractCriticalPathAlgorithm.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/AlgorithmManager.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/CriticalPathAlgorithmBounded.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/Messages.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/messages.properties [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/package-info.java [new file with mode: 0644]

index 1a8a243c73e7ae54b8030db8c56c36e741c68b2b..77f2ab0bd108716580cace4b9e3fa6e61f274931 100644 (file)
@@ -15,7 +15,9 @@ Require-Bundle: org.eclipse.ui,
  org.eclipse.tracecompass.tmf.core
 Export-Package: org.eclipse.tracecompass.analysis.graph.core.base,
  org.eclipse.tracecompass.analysis.graph.core.building,
+ org.eclipse.tracecompass.analysis.graph.core.criticalpath,
  org.eclipse.tracecompass.internal.analysis.graph.core;x-internal=true;uses:="org.eclipse.tracecompass.common.core",
- org.eclipse.tracecompass.internal.analysis.graph.core.base;x-friends:="org.eclipse.tracecompass.analysis.graph.ui,org.eclipse.tracecompass.analysis.graph.core.tests"
+ org.eclipse.tracecompass.internal.analysis.graph.core.base;x-friends:="org.eclipse.tracecompass.analysis.graph.ui,org.eclipse.tracecompass.analysis.graph.core.tests",
+ org.eclipse.tracecompass.internal.analysis.graph.core.criticalpath;x-friends:="org.eclipse.tracecompass.analysis.graph.core.tests"
 Import-Package: com.google.common.collect,
  com.google.common.hash
index 98fef14eb01442dd2fea328e330ae561d99d39bf..56580e770e169f159631ceaa5ba6e38f912abd41 100644 (file)
@@ -14,6 +14,7 @@ source.. = src/
 output.. = bin/
 bin.includes = META-INF/,\
                plugin.properties,\
-               .
+               .,\
+               plugin.xml
 additional.bundles = org.eclipse.jdt.annotation
 jars.extra.classpath = platform:/plugin/org.eclipse.jdt.annotation
diff --git a/analysis/org.eclipse.tracecompass.analysis.graph.core/plugin.xml b/analysis/org.eclipse.tracecompass.analysis.graph.core/plugin.xml
new file mode 100644 (file)
index 0000000..8c7a040
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+   <extension
+         point="org.eclipse.linuxtools.tmf.core.analysis">
+      <module
+            analysis_module="org.eclipse.tracecompass.analysis.graph.core.criticalpath.CriticalPathModule"
+            id="org.eclipse.tracecompass.analysis.graph.core.criticalpath"
+            name="Critical Path">
+         <parameter
+               name="graph">
+         </parameter>
+         <parameter
+               name="workerid">
+         </parameter>
+         <parameter
+               name="algorithm">
+         </parameter>
+         <tracetype
+               class="org.eclipse.tracecompass.tmf.core.trace.TmfTrace">
+         </tracetype>
+      </module>
+   </extension>
+</plugin>
diff --git a/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/analysis/graph/core/criticalpath/CriticalPathModule.java b/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/analysis/graph/core/criticalpath/CriticalPathModule.java
new file mode 100644 (file)
index 0000000..549bc6c
--- /dev/null
@@ -0,0 +1,216 @@
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.analysis.graph.core.criticalpath;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.tracecompass.analysis.graph.core.base.IGraphWorker;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfGraph;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfVertex;
+import org.eclipse.tracecompass.analysis.graph.core.building.TmfGraphBuilderModule;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.internal.analysis.graph.core.Activator;
+import org.eclipse.tracecompass.internal.analysis.graph.core.criticalpath.CriticalPathAlgorithmBounded;
+import org.eclipse.tracecompass.internal.analysis.graph.core.criticalpath.Messages;
+import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
+import org.eclipse.tracecompass.tmf.core.analysis.TmfAbstractAnalysisModule;
+import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
+
+/**
+ * Class to implement the critical path analysis
+ *
+ * @author Francis Giraldeau
+ * @author Geneviève Bastien
+ */
+public class CriticalPathModule extends TmfAbstractAnalysisModule {
+
+    /**
+     * Analysis ID for this module
+     */
+    public static final String ANALYSIS_ID = "org.eclipse.tracecompass.analysis.graph.core.criticalpath"; //$NON-NLS-1$
+
+    /** Graph parameter name */
+    public static final String PARAM_GRAPH = "graph"; //$NON-NLS-1$
+
+    /** Worker_id parameter name */
+    public static final String PARAM_WORKER = "workerid"; //$NON-NLS-1$
+
+    private @Nullable TmfGraphBuilderModule fGraphModule;
+
+    private @Nullable TmfGraph fCriticalPath;
+
+    /**
+     * Default constructor
+     */
+    public CriticalPathModule() {
+        super();
+    }
+
+    @Override
+    protected boolean executeAnalysis(final IProgressMonitor monitor) throws TmfAnalysisException {
+        /* Get the graph */
+        TmfGraphBuilderModule graphModule = getGraph();
+        if (graphModule == null) {
+            Activator.getInstance().logWarning("No graph was found to execute the critical path on"); //$NON-NLS-1$
+            return true;
+        }
+        graphModule.schedule();
+
+        monitor.setTaskName(NLS.bind(Messages.CriticalPathModule_waitingForGraph, graphModule.getName()));
+        if (!graphModule.waitForCompletion(monitor)) {
+            Activator.getInstance().logInfo("Critical path execution: graph building was cancelled.  Results may not be accurate."); //$NON-NLS-1$
+            return false;
+        }
+        TmfGraph graph = graphModule.getGraph();
+        if (graph == null) {
+            throw new TmfAnalysisException("Critical Path analysis: graph " + graphModule.getName() + " is null"); //$NON-NLS-1$//$NON-NLS-2$
+        }
+
+        /* Get the worker id */
+        Object workerObj = getParameter(PARAM_WORKER);
+        if (workerObj == null) {
+            return false;
+        }
+        if (!(workerObj instanceof IGraphWorker)) {
+            throw new IllegalStateException();
+        }
+        IGraphWorker worker = (IGraphWorker) workerObj;
+
+        TmfVertex head = graph.getHead(worker);
+        if (head == null) {
+            /* Nothing happens with this worker, return an empty graph */
+            fCriticalPath = new TmfGraph();
+            return true;
+        }
+        TmfTimeRange tr = TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange();
+        TmfVertex start = graph.getVertexAt(tr.getStartTime(), worker);
+        if (start == null) {
+            /*
+             * Nothing happens with this worker after start, return an empty
+             * graph
+             */
+            fCriticalPath = new TmfGraph();
+            return true;
+        }
+        ICriticalPathAlgorithm cp = getAlgorithm(graph);
+        fCriticalPath = cp.compute(start, null);
+
+        return true;
+    }
+
+    @Override
+    protected void canceling() {
+
+    }
+
+    @Override
+    public @Nullable Object getParameter(String name) {
+        if (name.equals(PARAM_GRAPH)) {
+            return getGraph();
+        }
+        return super.getParameter(name);
+    }
+
+    @Override
+    public synchronized void setParameter(String name, @Nullable Object value) throws RuntimeException {
+        if (name.equals(PARAM_GRAPH) && (value instanceof String)) {
+            setGraph((String) value);
+        }
+        super.setParameter(name, value);
+    }
+
+    @Override
+    protected void parameterChanged(String name) {
+        cancel();
+        resetAnalysis();
+        schedule();
+    }
+
+    /**
+     * The value of graph should be the id of the analysis module that builds
+     * the required graph
+     *
+     * @param graphName
+     *            Id of the graph
+     */
+    private void setGraph(String graphName) {
+        ITmfTrace trace = getTrace();
+        if (trace == null) {
+            return;
+        }
+        IAnalysisModule module = trace.getAnalysisModule(graphName);
+        if (module instanceof TmfGraphBuilderModule) {
+            fGraphModule = (TmfGraphBuilderModule) module;
+        }
+    }
+
+    private @Nullable TmfGraphBuilderModule getGraph() {
+        /* The graph module is null, take the first available graph if any */
+        TmfGraphBuilderModule module = fGraphModule;
+        if (module == null) {
+            ITmfTrace trace = getTrace();
+            if (trace == null) {
+                return fGraphModule;
+            }
+            for (TmfGraphBuilderModule mod : TmfTraceUtils.getAnalysisModulesOfClass(trace, TmfGraphBuilderModule.class)) {
+                module = mod;
+                break;
+            }
+            if (module != null) {
+                fGraphModule = module;
+            }
+        }
+        return module;
+    }
+
+    private static ICriticalPathAlgorithm getAlgorithm(TmfGraph graph) {
+        return new CriticalPathAlgorithmBounded(graph);
+    }
+
+    @Override
+    public boolean canExecute(@NonNull ITmfTrace trace) {
+        /*
+         * TODO: The critical path executes on a graph, so at least a graph must
+         * be available for this trace
+         */
+        return true;
+    }
+
+    /**
+     * Gets the graph for the critical path
+     *
+     * @return The critical path graph
+     */
+    public @Nullable TmfGraph getCriticalPath() {
+        return fCriticalPath;
+    }
+
+    @Override
+    protected @NonNull String getFullHelpText() {
+        return NonNullUtils.nullToEmptyString(Messages.CriticalPathModule_fullHelpText);
+    }
+
+    @Override
+    protected @NonNull String getShortHelpText(ITmfTrace trace) {
+        return getFullHelpText();
+    }
+
+    @Override
+    protected @NonNull String getTraceCannotExecuteHelpText(@NonNull ITmfTrace trace) {
+        return NonNullUtils.nullToEmptyString(Messages.CriticalPathModule_cantExecute);
+    }
+
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/analysis/graph/core/criticalpath/ICriticalPathAlgorithm.java b/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/analysis/graph/core/criticalpath/ICriticalPathAlgorithm.java
new file mode 100644 (file)
index 0000000..f564f99
--- /dev/null
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.analysis.graph.core.criticalpath;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfGraph;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfVertex;
+
+/**
+ * Interface for all critical path algorithms
+ *
+ * @author Francis Giraldeau
+ */
+public interface ICriticalPathAlgorithm {
+
+    /**
+     * Computes the critical path
+     *
+     * @param start
+     *            The starting vertex
+     * @param end
+     *            The end vertex
+     * @return The graph of the critical path
+     */
+    public TmfGraph compute(TmfVertex start, @Nullable TmfVertex end);
+
+    /**
+     * Unique ID of this analysis
+     *
+     * @return the ID string
+     */
+    public String getID();
+
+    /**
+     * Human readable display name
+     *
+     * @return display name
+     */
+    public String getDisplayName();
+
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/analysis/graph/core/criticalpath/package-info.java b/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/analysis/graph/core/criticalpath/package-info.java
new file mode 100644 (file)
index 0000000..4e1c0b7
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.analysis.graph.core.criticalpath;
\ No newline at end of file
diff --git a/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/AbstractCriticalPathAlgorithm.java b/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/AbstractCriticalPathAlgorithm.java
new file mode 100644 (file)
index 0000000..ce9051f
--- /dev/null
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.analysis.graph.core.criticalpath;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.analysis.graph.core.base.IGraphWorker;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfEdge;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfGraph;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfVertex;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfVertex.EdgeDirection;
+import org.eclipse.tracecompass.analysis.graph.core.criticalpath.ICriticalPathAlgorithm;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+
+/**
+ * Abstract class for critical path algorithms
+ *
+ * @author Francis Giraldeau
+ */
+public abstract class AbstractCriticalPathAlgorithm implements ICriticalPathAlgorithm {
+
+    private final TmfGraph fGraph;
+
+    /**
+     * Constructor
+     *
+     * @param graph
+     *            The graph on which to calculate critical path
+     */
+    public AbstractCriticalPathAlgorithm(TmfGraph graph) {
+        fGraph = graph;
+    }
+
+    /**
+     * Get the graph
+     *
+     * @return the graph
+     */
+    public TmfGraph getGraph() {
+        return fGraph;
+    }
+
+    /**
+     * Copy link of type TYPE between nodes FROM and TO in the graph PATH. The
+     * return value is the tail node for the new path.
+     *
+     * @param criticalPath
+     *            The graph on which to add the link
+     * @param graph
+     *            The original graph on which to calculate critical path
+     * @param anchor
+     *            The anchor vertex from the path graph
+     * @param from
+     *            The origin vertex in the main graph
+     * @param to
+     *            The destination vertex in the main graph
+     * @param ts
+     *            The timestamp of the edge
+     * @param type
+     *            The type of the edge to create
+     * @return The destination vertex in the path graph
+     */
+    public TmfVertex copyLink(TmfGraph criticalPath, TmfGraph graph, TmfVertex anchor, TmfVertex from, TmfVertex to, long ts, TmfEdge.EdgeType type) {
+        IGraphWorker parentFrom = graph.getParentOf(from);
+        IGraphWorker parentTo = graph.getParentOf(to);
+        if (parentTo == null) {
+            throw new NullPointerException();
+        }
+        TmfVertex tmp = new TmfVertex(ts);
+        criticalPath.add(parentTo, tmp);
+        if (parentFrom == parentTo) {
+            anchor.linkHorizontal(tmp).setType(type);
+        } else {
+            anchor.linkVertical(tmp).setType(type);
+        }
+        return tmp;
+    }
+
+    /**
+     * Find the next incoming vertex from another object (in vertical) from a
+     * node in a given direction
+     *
+     * @param vertex
+     *            The starting vertex
+     * @param dir
+     *            The direction in which to search
+     * @return The next incoming vertex
+     */
+    public static @Nullable TmfVertex findIncoming(TmfVertex vertex, EdgeDirection dir) {
+        TmfVertex currentVertex = vertex;
+        while (true) {
+            TmfEdge incoming = currentVertex.getEdge(EdgeDirection.INCOMING_VERTICAL_EDGE);
+            if (incoming != null) {
+                return currentVertex;
+            }
+            TmfEdge edge = currentVertex.getEdge(dir);
+            if (edge == null || edge.getType() != TmfEdge.EdgeType.EPS) {
+                break;
+            }
+            currentVertex = TmfVertex.getNeighborFromEdge(edge, dir);
+        }
+        return null;
+    }
+
+    @Override
+    public String getID() {
+        return NonNullUtils.checkNotNull(getClass().getName());
+    }
+
+    @Override
+    public String getDisplayName() {
+        return NonNullUtils.checkNotNull(getClass().getSimpleName());
+    }
+
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/AlgorithmManager.java b/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/AlgorithmManager.java
new file mode 100644 (file)
index 0000000..78504c0
--- /dev/null
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.analysis.graph.core.criticalpath;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.analysis.graph.core.criticalpath.ICriticalPathAlgorithm;
+
+/**
+ * Register algorithm
+ *
+ * FIXME: is there already a facility in Eclipse to replace this class?
+ * @author Francis Giraldeau
+ *
+ */
+public final class AlgorithmManager {
+
+    private static @Nullable AlgorithmManager INSTANCE;
+    private final Map<String, Class<? extends ICriticalPathAlgorithm>> map;
+
+    private AlgorithmManager() {
+        map = new HashMap<>();
+    }
+
+    /**
+     * Get the singleton instance
+     *
+     * @return the instance
+     */
+    public static AlgorithmManager getInstance() {
+        AlgorithmManager manager = INSTANCE;
+        if (manager == null) {
+            manager = new AlgorithmManager();
+            manager.register(CriticalPathAlgorithmBounded.class);
+            INSTANCE = manager;
+        }
+        return manager;
+    }
+
+    /**
+     * Register a type in the manager
+     *
+     * @param type the class to register
+     */
+    public void register(Class<? extends ICriticalPathAlgorithm> type) {
+        map.put(type.getSimpleName(), type);
+    }
+
+    /**
+     * Return registered types
+     * @return the types
+     */
+    public Map<String, Class<? extends ICriticalPathAlgorithm>> registeredTypes() {
+        return map;
+    }
+
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/CriticalPathAlgorithmBounded.java b/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/CriticalPathAlgorithmBounded.java
new file mode 100644 (file)
index 0000000..4179b92
--- /dev/null
@@ -0,0 +1,303 @@
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.analysis.graph.core.criticalpath;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Stack;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.analysis.graph.core.base.IGraphWorker;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfEdge;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfGraph;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfVertex;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfVertex.EdgeDirection;
+
+/**
+ * Critical path bounded algorithm: backward resolution of blocking limited to
+ * the blocking window
+ *
+ * This algorithm is described in
+ *
+ * F. Giraldeau and M.Dagenais, Wait analysis of distributed systems using
+ * kernel tracing, IEEE Transactions on Parallel and Distributed Systems
+ *
+ * @author Francis Giraldeau
+ */
+public class CriticalPathAlgorithmBounded extends AbstractCriticalPathAlgorithm {
+
+    /**
+     * Constructor
+     *
+     * @param graph
+     *            The graph on which to calculate the critical path
+     */
+    public CriticalPathAlgorithmBounded(TmfGraph graph) {
+        super(graph);
+    }
+
+    @Override
+    public TmfGraph compute(TmfVertex start, @Nullable TmfVertex end) {
+        /* Create new graph for the critical path result */
+        TmfGraph criticalPath = new TmfGraph();
+
+        /* Get the main graph from which to get critical path */
+        TmfGraph graph = getGraph();
+
+        /*
+         * Calculate path starting from the object the start vertex belongs to
+         */
+        IGraphWorker parent = graph.getParentOf(start);
+        if (parent == null) {
+            throw new NullPointerException();
+        }
+        criticalPath.add(parent, new TmfVertex(start));
+        TmfVertex currentVertex = start;
+        TmfEdge nextEdge = currentVertex.getEdge(EdgeDirection.OUTGOING_HORIZONTAL_EDGE);
+
+        long endTime = Long.MAX_VALUE;
+        if (end != null) {
+            endTime = end.getTs();
+        }
+
+        /*
+         * Run through all horizontal edges from this object and resolve each
+         * blocking as they come
+         */
+        while (nextEdge != null) {
+            TmfVertex nextVertex = nextEdge.getVertexTo();
+            if (nextVertex.getTs() >= endTime) {
+                break;
+            }
+            switch (nextEdge.getType()) {
+            case USER_INPUT:
+            case BLOCK_DEVICE:
+            case TIMER:
+            case INTERRUPTED:
+            case PREEMPTED:
+            case RUNNING:
+                /**
+                 * This edge is not blocked, so nothing to resolve, just add the
+                 * edge to the critical path
+                 */
+                /**
+                 * TODO: Normally, the parent of the link's vertex to should be
+                 * the object itself, verify if that is true
+                 */
+                IGraphWorker parentTo = graph.getParentOf(nextEdge.getVertexTo());
+                if (parentTo == null) {
+                    throw new NullPointerException();
+                }
+                if (parentTo != parent) {
+                    System.err.println("no, the parents of horizontal edges are not always identical... shouldn't they be?"); //$NON-NLS-1$
+                }
+                criticalPath.append(parentTo, new TmfVertex(nextEdge.getVertexTo()), nextEdge.getType());
+                break;
+            case NETWORK:
+            case BLOCKED:
+                List<TmfEdge> links = resolveBlockingBounded(nextEdge, nextEdge.getVertexFrom());
+                Collections.reverse(links);
+                appendPathComponent(criticalPath, graph, currentVertex, links);
+                break;
+            case EPS:
+                if (nextEdge.getDuration() != 0) {
+                    throw new RuntimeException("epsilon duration is not zero " + nextEdge); //$NON-NLS-1$
+                }
+                break;
+            case DEFAULT:
+                throw new RuntimeException("Illegal link type " + nextEdge.getType()); //$NON-NLS-1$
+            case UNKNOWN:
+            default:
+                break;
+            }
+            currentVertex = nextVertex;
+            nextEdge = currentVertex.getEdge(EdgeDirection.OUTGOING_HORIZONTAL_EDGE);
+        }
+        return criticalPath;
+    }
+
+    /** Add the links to the critical path, with currentVertex to glue to */
+    private void appendPathComponent(TmfGraph criticalPath, TmfGraph graph, TmfVertex currentVertex, List<TmfEdge> links) {
+        IGraphWorker currentActor = graph.getParentOf(currentVertex);
+        if (currentActor == null) {
+            throw new NullPointerException();
+        }
+        if (links.isEmpty()) {
+            /*
+             * The next vertex should not be null, since we glue only after
+             * resolve of the blocking of the edge to that vertex
+             */
+            TmfEdge next = currentVertex.getEdge(EdgeDirection.OUTGOING_HORIZONTAL_EDGE);
+            if (next == null) {
+                return;
+            }
+            criticalPath.append(currentActor, new TmfVertex(next.getVertexTo()), next.getType());
+            return;
+        }
+        // FIXME: assert last link.to actor == currentActor
+
+        // attach subpath to b1 and b2
+        TmfVertex b1 = criticalPath.getTail(currentActor);
+        if (b1 == null) {
+            throw new NullPointerException();
+        }
+        // TmfVertex b2 = new TmfVertex(curr.neighbor(TmfVertex.OUTH));
+
+        // glue head
+        TmfEdge lnk = links.get(0);
+        TmfVertex anchor = null;
+        IGraphWorker objSrc = graph.getParentOf(lnk.getVertexFrom());
+        if (objSrc == null) {
+            throw new NullPointerException();
+        }
+        if (objSrc == currentActor) {
+            anchor = b1;
+        } else {
+            anchor = new TmfVertex(currentVertex);
+            criticalPath.add(objSrc, anchor);
+            b1.linkVertical(anchor);
+            /* fill any gap with UNKNOWN */
+            if (lnk.getVertexFrom().compareTo(anchor) > 0) {
+                anchor = new TmfVertex(lnk.getVertexFrom());
+                TmfEdge edge = criticalPath.append(objSrc, anchor);
+                if (edge == null) {
+                    throw new NullPointerException();
+                }
+                edge.setType(TmfEdge.EdgeType.UNKNOWN);
+            }
+        }
+
+        // glue body
+        TmfEdge prev = null;
+        for (TmfEdge link : links) {
+            // check connectivity
+            if (prev != null && prev.getVertexTo() != link.getVertexFrom()) {
+                anchor = copyLink(criticalPath, graph, anchor, prev.getVertexTo(), link.getVertexFrom(),
+                        prev.getVertexTo().getTs(), TmfEdge.EdgeType.DEFAULT);
+            }
+            anchor = copyLink(criticalPath, graph, anchor, link.getVertexFrom(), link.getVertexTo(),
+                    link.getVertexTo().getTs(), link.getType());
+            prev = link;
+        }
+    }
+
+    /**
+     * Resolve a blocking by going through the graph vertically from the
+     * blocking edge
+     *
+     * FIXME: build a tree with partial subpath in order to return the best
+     * path, not the last one traversed
+     *
+     * @param blocking
+     *            The blocking edge
+     * @param bound
+     *            The vertex that limits the boundary until which to resolve the
+     *            blocking
+     * @return The list of non-blocking edges
+     */
+    private List<TmfEdge> resolveBlockingBounded(TmfEdge blocking, TmfVertex bound) {
+
+        LinkedList<TmfEdge> subPath = new LinkedList<>();
+        TmfVertex junction = findIncoming(blocking.getVertexTo(), EdgeDirection.OUTGOING_HORIZONTAL_EDGE);
+        /* if wake-up source is not found, return empty list */
+        if (junction == null) {
+            return subPath;
+        }
+
+        TmfEdge down = junction.getEdge(EdgeDirection.INCOMING_VERTICAL_EDGE);
+        if (down == null) {
+            throw new NullPointerException();
+        }
+        subPath.add(down);
+        TmfVertex vertexFrom = down.getVertexFrom();
+
+        TmfVertex currentBound = bound.compareTo(blocking.getVertexFrom()) < 0 ? blocking.getVertexFrom() : bound;
+
+        Stack<TmfVertex> stack = new Stack<>();
+        while (vertexFrom != null && vertexFrom.compareTo(currentBound) > 0) {
+            /* shortcut for down link that goes beyond the blocking */
+            TmfEdge inVerticalEdge = vertexFrom.getEdge(EdgeDirection.INCOMING_VERTICAL_EDGE);
+            if (inVerticalEdge != null && inVerticalEdge.getVertexFrom().compareTo(currentBound) <= 0) {
+                subPath.add(inVerticalEdge);
+                break;
+            }
+
+            /**
+             * Add DOWN links to explore stack in case dead-end occurs. Here is
+             * an example to illustrate the procedure.
+             *
+             * <pre>
+             *           -------------------------
+             *            BLOCKED    | PREEMPT
+             *           -------------------------
+             *                       ^
+             *                       |WAKE-UP
+             *                       |
+             *         +--------------------+
+             * +-------+      INTERRUPT     +--------+
+             *         +--------------------+
+             *           ^   ^   |       ^
+             *           |   |   |       |
+             *           +   +   v       +
+             *           1   2   3       4
+             * </pre>
+             *
+             * The event wake-up is followed backward. The edge 4 will never be
+             * visited (it cannot be the cause of the wake-up, because it occurs
+             * after it). The edge 3 will not be explored, because it is
+             * outgoing. The edges 2 and 1 will be pushed on the stack. When the
+             * beginning of the interrupt is reached, then the edges on the
+             * stack will be explored.
+             *
+             * If a dead-end is reached, while the stack is not empty, the
+             * accumulated path is rewinded, and a different incoming edge is
+             * tried. The backward traversal ends if there is nothing left to
+             * explore, or if the start of the blocking window start is reached.
+             *
+             * Do not add if left is BLOCKED, because this link would be visited
+             * twice
+             */
+            TmfEdge incomingEdge = vertexFrom.getEdge(EdgeDirection.INCOMING_HORIZONTAL_EDGE);
+            if (inVerticalEdge != null &&
+                    (incomingEdge == null ||
+                            incomingEdge.getType() != TmfEdge.EdgeType.BLOCKED ||
+                            incomingEdge.getType() != TmfEdge.EdgeType.NETWORK)) {
+                stack.push(vertexFrom);
+            }
+            if (incomingEdge != null) {
+                if (incomingEdge.getType() == TmfEdge.EdgeType.BLOCKED || incomingEdge.getType() == TmfEdge.EdgeType.NETWORK) {
+                    subPath.addAll(resolveBlockingBounded(incomingEdge, currentBound));
+                } else {
+                    subPath.add(incomingEdge);
+                }
+                vertexFrom = incomingEdge.getVertexFrom();
+            } else {
+                if (!stack.isEmpty()) {
+                    TmfVertex v = stack.pop();
+                    /* rewind subpath */
+                    while (!subPath.isEmpty() && subPath.getLast().getVertexFrom() != v) {
+                        subPath.removeLast();
+                    }
+                    TmfEdge edge = v.getEdge(EdgeDirection.INCOMING_VERTICAL_EDGE);
+                    if (edge != null) {
+                        subPath.add(edge);
+                        vertexFrom = edge.getVertexFrom();
+                        continue;
+                    }
+                }
+                vertexFrom = null;
+            }
+
+        }
+        return subPath;
+    }
+
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/Messages.java b/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/Messages.java
new file mode 100644 (file)
index 0000000..b0dc804
--- /dev/null
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.analysis.graph.core.criticalpath;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Externalized string for this package
+ *
+ * @author Geneviève Bastien
+ */
+@SuppressWarnings("javadoc")
+public class Messages {
+    private static final String BUNDLE_NAME = "org.eclipse.tracecompass.internal.analysis.graph.core.criticalpath.messages"; //$NON-NLS-1$
+
+    public static @Nullable String CriticalPathModule_waitingForGraph;
+    public static @Nullable String CriticalPathModule_fullHelpText;
+    public static @Nullable String CriticalPathModule_cantExecute;
+
+    static {
+        // initialize resource bundle
+        NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+    }
+
+    private Messages() {
+    }
+
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/messages.properties b/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/messages.properties
new file mode 100644 (file)
index 0000000..52bd941
--- /dev/null
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2015 École Polytechnique de Montréal
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+###############################################################################
+
+CriticalPathModule_waitingForGraph=Waiting for {0} module to complete...
+CriticalPathModule_fullHelpText=Computes the critical path of an execution graph.  To compute the critical path, you need to select a process in the control flow view and the path will be computed for that process.
+CriticalPathModule_cantExecute=There is no graph available on which to compute the critical path
\ No newline at end of file
diff --git a/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/package-info.java b/analysis/org.eclipse.tracecompass.analysis.graph.core/src/org/eclipse/tracecompass/internal/analysis/graph/core/criticalpath/package-info.java
new file mode 100644 (file)
index 0000000..a954674
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.analysis.graph.core.criticalpath;
\ No newline at end of file
This page took 0.035921 seconds and 5 git commands to generate.