kernel: Aggregate the critical path as a weighted tree
This takes a critical path and flattens it to show the time spent on the
various critical path states and processes
Change-Id: Ie066d026b214d2b3ca8577571afdd621a3cdf6bd
Signed-off-by: Geneviève Bastien <gbastien+lttng@versatic.net>
Reviewed-on: https://git.eclipse.org/r/133090
Reviewed-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Tested-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Tested-by: Trace Compass Bot <tracecompass-bot@eclipse.org>
diff --git a/analyses/org.eclipse.tracecompass.incubator.kernel.core/META-INF/MANIFEST.MF b/analyses/org.eclipse.tracecompass.incubator.kernel.core/META-INF/MANIFEST.MF
index 4c90290..534dac2 100644
--- a/analyses/org.eclipse.tracecompass.incubator.kernel.core/META-INF/MANIFEST.MF
+++ b/analyses/org.eclipse.tracecompass.incubator.kernel.core/META-INF/MANIFEST.MF
@@ -15,11 +15,14 @@
org.eclipse.tracecompass.analysis.os.linux.core,
org.eclipse.tracecompass.incubator.analysis.core,
org.eclipse.tracecompass.incubator.callstack.core,
- org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional,
- org.eclipse.tracecompass.analysis.timing.core
+ org.eclipse.tracecompass.analysis.timing.core,
+ org.eclipse.tracecompass.analysis.graph.core,
+ org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional
Export-Package: org.eclipse.tracecompass.incubator.internal.kernel.core;x-friends:="org.eclipse.tracecompass.incubator.kernel.core.tests",
org.eclipse.tracecompass.incubator.internal.kernel.core.callstack.context;x-friends:="org.eclipse.tracecompass.incubator.lttng2.ust.extras.core",
+ org.eclipse.tracecompass.incubator.internal.kernel.core.criticalpath;x-internal:=true,
org.eclipse.tracecompass.incubator.internal.kernel.core.fileaccess;x-internal:=true,
org.eclipse.tracecompass.incubator.internal.kernel.core.filedescriptor;x-internal:=true
Automatic-Module-Name: org.eclipse.tracecompass.incubator.kernel.core
-Import-Package: com.google.common.collect
+Import-Package: com.google.common.collect,
+ org.apache.commons.lang3
diff --git a/analyses/org.eclipse.tracecompass.incubator.kernel.core/plugin.properties b/analyses/org.eclipse.tracecompass.incubator.kernel.core/plugin.properties
index 5113cb8..c4293a4 100644
--- a/analyses/org.eclipse.tracecompass.incubator.kernel.core/plugin.properties
+++ b/analyses/org.eclipse.tracecompass.incubator.kernel.core/plugin.properties
@@ -13,3 +13,4 @@
kernel.fileaccess.name = File Access
analysis.callstack.context = Context CallStacks
+analysis.criticalpath.aggregated = Critical Path Aggregated
diff --git a/analyses/org.eclipse.tracecompass.incubator.kernel.core/plugin.xml b/analyses/org.eclipse.tracecompass.incubator.kernel.core/plugin.xml
index 695da6b..b75e465 100644
--- a/analyses/org.eclipse.tracecompass.incubator.kernel.core/plugin.xml
+++ b/analyses/org.eclipse.tracecompass.incubator.kernel.core/plugin.xml
@@ -28,6 +28,14 @@
class="org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace">
</tracetype>
</module>
+ <module
+ analysis_module="org.eclipse.tracecompass.incubator.internal.kernel.core.criticalpath.CriticalPathAggregatedModule"
+ id="org.eclipse.tracecompass.incubator.kernel.core.criticalpath.aggregated"
+ name="%analysis.criticalpath.aggregated">
+ <tracetype
+ class="org.eclipse.tracecompass.tmf.core.trace.TmfTrace">
+ </tracetype>
+ </module>
</extension>
<extension
point="org.eclipse.tracecompass.tmf.core.dataprovider">
diff --git a/analyses/org.eclipse.tracecompass.incubator.kernel.core/src/org/eclipse/tracecompass/incubator/internal/kernel/core/criticalpath/CriticalPathAggregatedModule.java b/analyses/org.eclipse.tracecompass.incubator.kernel.core/src/org/eclipse/tracecompass/incubator/internal/kernel/core/criticalpath/CriticalPathAggregatedModule.java
new file mode 100644
index 0000000..8d90ef5
--- /dev/null
+++ b/analyses/org.eclipse.tracecompass.incubator.kernel.core/src/org/eclipse/tracecompass/incubator/internal/kernel/core/criticalpath/CriticalPathAggregatedModule.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2020 É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.incubator.internal.kernel.core.criticalpath;
+
+import java.util.Collection;
+import java.util.Objects;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.analysis.graph.core.criticalpath.CriticalPathModule;
+import org.eclipse.tracecompass.incubator.analysis.core.weighted.tree.IWeightedTreeProvider;
+import org.eclipse.tracecompass.incubator.analysis.core.weighted.tree.IWeightedTreeSet;
+import org.eclipse.tracecompass.incubator.analysis.core.weighted.tree.WeightedTree;
+import org.eclipse.tracecompass.tmf.core.TmfStrings;
+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.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfStartAnalysisSignal;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+
+/**
+ * Analysis modules that aggregates the states of the critical path into a
+ * weighted tree structure, to display in flame graphs or compare with other
+ * graphs.
+ *
+ * @author Geneviève Bastien
+ */
+public class CriticalPathAggregatedModule extends TmfAbstractAnalysisModule implements IWeightedTreeProvider<Object, String, WeightedTree<Object>> {
+
+ private static final MetricType DURATION_METRIC = new MetricType(Objects.requireNonNull(TmfStrings.duration()), DataType.NANOSECONDS, null);
+
+ private @Nullable CriticalPathModule fModule = null;
+ private @Nullable CriticalPathWeighted fCritPathCg = null;
+
+ @Override
+ protected boolean executeAnalysis(IProgressMonitor monitor) throws TmfAnalysisException {
+ CriticalPathModule module = fModule;
+ if (module == null) {
+ return false;
+ }
+ if (!module.waitForCompletion(Objects.requireNonNull(monitor))) {
+ return false;
+ }
+ fCritPathCg = CriticalPathWeighted.create(module.getCriticalPath());
+ return true;
+ }
+
+ /**
+ * Signal handler for analysis started, we need to rebuilt the entry list
+ * with updated statistics values for the current graph worker of the
+ * critical path module.
+ *
+ * @param signal
+ * The signal
+ */
+ @TmfSignalHandler
+ public void analysisStarted(TmfStartAnalysisSignal signal) {
+ IAnalysisModule analysis = signal.getAnalysisModule();
+ if (analysis instanceof CriticalPathModule) {
+ CriticalPathModule criticalPath = (CriticalPathModule) analysis;
+ Collection<ITmfTrace> traces = TmfTraceManager.getTraceSetWithExperiment(getTrace());
+ if (traces.contains(criticalPath.getTrace())) {
+ cancel();
+ fModule = criticalPath;
+ fCritPathCg = null;
+ resetAnalysis();
+ schedule();
+ }
+ }
+ }
+
+ @Override
+ protected void canceling() {
+ // Nothing to do
+ }
+
+ @Override
+ public MetricType getWeightType() {
+ return DURATION_METRIC;
+ }
+
+ @Override
+ public String getTitle() {
+ return "What the process is waiting for"; //$NON-NLS-1$
+ }
+
+ @Override
+ public IWeightedTreeSet<Object, String, WeightedTree<Object>> getTreeSet() {
+ CriticalPathWeighted critPathCg = fCritPathCg;
+ if (critPathCg != null) {
+ return critPathCg;
+ }
+ CriticalPathModule module = fModule;
+ if (module == null) {
+ return CriticalPathWeighted.create(null);
+ }
+ return CriticalPathWeighted.create(module.getCriticalPath());
+ }
+
+}
diff --git a/analyses/org.eclipse.tracecompass.incubator.kernel.core/src/org/eclipse/tracecompass/incubator/internal/kernel/core/criticalpath/CriticalPathWeighted.java b/analyses/org.eclipse.tracecompass.incubator.kernel.core/src/org/eclipse/tracecompass/incubator/internal/kernel/core/criticalpath/CriticalPathWeighted.java
new file mode 100644
index 0000000..9ed38f2
--- /dev/null
+++ b/analyses/org.eclipse.tracecompass.incubator.kernel.core/src/org/eclipse/tracecompass/incubator/internal/kernel/core/criticalpath/CriticalPathWeighted.java
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * Copyright (c) 2020 É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.incubator.internal.kernel.core.criticalpath;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.analysis.graph.core.base.IGraphWorker;
+import org.eclipse.tracecompass.analysis.graph.core.base.ITmfGraphVisitor;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfEdge;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfEdge.EdgeType;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfGraph;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfVertex;
+import org.eclipse.tracecompass.analysis.os.linux.core.execution.graph.OsWorker;
+import org.eclipse.tracecompass.incubator.analysis.core.weighted.tree.IWeightedTreeSet;
+import org.eclipse.tracecompass.incubator.analysis.core.weighted.tree.WeightedTree;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * A weighted tree set that contains the aggregation of the critical path graph
+ * states.
+ *
+ * The tree set will have 3 elements that all aggregate the full critical path,
+ * but differently.
+ * <ul>
+ * <li>1- Top level are all the processes involved and the second level is the
+ * time those processes spend in the various states</li>
+ * <li>2- with the _all suffix is the tree showing only the final status of the
+ * critical path: running, preempted, network, etc</li>
+ * <li>3- With the _proc suffix is the tree where the top level are the running
+ * processes and the states. Any of the dependent processes could have been in
+ * one of those states</li>
+ * </ul>
+ *
+ * @author Geneviève Bastien
+ */
+public class CriticalPathWeighted implements IWeightedTreeSet<Object, String, WeightedTree<Object>> {
+
+ /**
+ * An empty critical path
+ */
+ private static final CriticalPathWeighted EMPTY_CRIT_PATH_CG = new CriticalPathWeighted();
+ private static final String ALL_SUFFIX = "_all"; //$NON-NLS-1$
+ private static final String PROCESS_SUFFIX = "_proc"; //$NON-NLS-1$
+
+ private final List<String> fElements;
+ private WeightedTree<Object> fAggregatedTree;
+ private WeightedTree<Object> fTree;
+ private WeightedTree<Object> fProcessTree;
+
+ private class GraphToCallGraphConverter implements ITmfGraphVisitor {
+
+ private final TmfGraph fGraph;
+ private final IGraphWorker fMainWorker;
+
+ public GraphToCallGraphConverter(IGraphWorker mainWorker, TmfGraph graph) {
+ fGraph = graph;
+ fMainWorker = mainWorker;
+ }
+
+ @Override
+ public void visitHead(TmfVertex vertex) {
+ // Nothing to do
+
+ }
+
+ @Override
+ public void visit(TmfVertex vertex) {
+ // Nothing to do
+ }
+
+ @Override
+ public void visit(TmfEdge edge, boolean horizontal) {
+ if (edge.getDuration() == 0) {
+ return;
+ }
+ addEdgeToElement(edge);
+ addEdgeToAggregatedElement(edge);
+ addEdgeToProcessElement(edge);
+ }
+
+ private void addEdgeToAggregatedElement(TmfEdge edge) {
+ // Get the worker to which to attribute this edge, whether vertical
+ // or horizontal
+ IGraphWorker worker = fGraph.getParentOf(edge.getVertexTo());
+ if (worker == null) {
+ return;
+ }
+
+ // If it's another worker that is running, add a other process
+ // running state
+ if (worker != fMainWorker && edge.getType().equals(EdgeType.RUNNING)) {
+ WeightedTree<Object> callSite = new WeightedTree<>("Other process"); //$NON-NLS-1$
+ callSite.addToWeight(edge.getDuration());
+ fAggregatedTree.addChild(callSite);
+ return;
+ }
+
+ // Otherwise, add a first level call that corresponds to the worker
+ WeightedTree<Object> callSite = new WeightedTree<>(edge.getType());
+ callSite.addToWeight(edge.getDuration());
+ fAggregatedTree.addChild(callSite);
+
+ }
+
+ private void addEdgeToElement(TmfEdge edge) {
+ // Get the worker to which to attribute this edge, whether vertical
+ // or horizontal
+ IGraphWorker worker = fGraph.getParentOf(edge.getVertexTo());
+ if (worker == null) {
+ return;
+ }
+
+ // If it is the main worker, just add a 1st level call of the edge
+ // type
+ if (worker == fMainWorker) {
+ WeightedTree<Object> callSite = new WeightedTree<>(edge.getType());
+ callSite.addToWeight(edge.getDuration());
+ fTree.addChild(callSite);
+ return;
+ }
+
+ // Otherwise, add a first level call that corresponds to the worker
+ WeightedTree<Object> callSite = new WeightedTree<>(String.valueOf(worker));
+ callSite.addToWeight(edge.getDuration());
+
+ // Then, add a second level for the edge type if it is not running
+ if (!edge.getType().equals(EdgeType.RUNNING)) {
+ WeightedTree<Object> childType = new WeightedTree<>(edge.getType());
+ childType.addToWeight(edge.getDuration());
+ callSite.addChild(childType);
+ }
+ fTree.addChild(callSite);
+ }
+
+ private void addEdgeToProcessElement(TmfEdge edge) {
+ // Get the worker to which to attribute this edge, whether vertical
+ // or horizontal
+ IGraphWorker worker = fGraph.getParentOf(edge.getVertexTo());
+ if (worker == null) {
+ return;
+ }
+
+ // If it's another worker that is running, add a other process
+ // running state
+ if (worker != fMainWorker && edge.getType().equals(EdgeType.RUNNING)) {
+ WeightedTree<Object> callSite = new WeightedTree<>(((OsWorker) worker).getName());
+ callSite.addToWeight(edge.getDuration());
+ fProcessTree.addChild(callSite);
+ return;
+ }
+
+ // Otherwise, add a first level call that corresponds to the worker
+ WeightedTree<Object> callSite = new WeightedTree<>(edge.getType());
+ callSite.addToWeight(edge.getDuration());
+ fProcessTree.addChild(callSite);
+ }
+
+ }
+
+ private CriticalPathWeighted() {
+ // Private constructor to build the empty graph
+ fElements = Collections.emptyList();
+ fTree = new WeightedTree<>(StringUtils.EMPTY);
+ fAggregatedTree = new WeightedTree<>(StringUtils.EMPTY);
+ fProcessTree = new WeightedTree<>(StringUtils.EMPTY);
+ }
+
+ /**
+ * Create a new critical path weighted tree set from the graph received in
+ * parameter. The graph can be <code>null</code> or empty and this method
+ * will return an empty treeset. It transforms the graph received in
+ * parameter into a weighted tree, merging similar state's durations.
+ *
+ * @param graph
+ * The graph to transform into an aggregated weighted tree set.
+ * @return The critical path weighted treeset
+ */
+ public static CriticalPathWeighted create(@Nullable TmfGraph graph) {
+ if (graph == null) {
+ return EMPTY_CRIT_PATH_CG;
+ }
+ TmfVertex head = graph.getHead();
+ if (head == null) {
+ return EMPTY_CRIT_PATH_CG;
+ }
+ return new CriticalPathWeighted(graph);
+ }
+
+ /**
+ * Constructor. It transforms the graph received in parameter into a
+ * weighted tree, merging similar state's durations.
+ *
+ * @param graph
+ * The graph to flatten as a weighted tree
+ */
+ private CriticalPathWeighted(TmfGraph graph) {
+ TmfVertex head = graph.getHead();
+ if (head == null) {
+ throw new NullPointerException("Empty graph"); //$NON-NLS-1$
+ }
+
+ IGraphWorker worker = graph.getParentOf(head);
+ if (worker == null) {
+ throw new NullPointerException("head vertex has no parent"); //$NON-NLS-1$
+ }
+ fElements = ImmutableList.of(String.valueOf(worker), String.valueOf(worker) + ALL_SUFFIX, String.valueOf(worker) + PROCESS_SUFFIX);
+ fTree = new WeightedTree<>(String.valueOf(worker));
+ fAggregatedTree = new WeightedTree<>(String.valueOf(worker) + ALL_SUFFIX);
+ fProcessTree = new WeightedTree<>(String.valueOf(worker) + PROCESS_SUFFIX);
+ GraphToCallGraphConverter converter = new GraphToCallGraphConverter(worker, graph);
+ graph.scanLineTraverse(worker, converter);
+ }
+
+ @Override
+ public Collection<WeightedTree<Object>> getTreesFor(Object element) {
+ if (!(element instanceof String)) {
+ return Collections.emptyList();
+ }
+ String elStr = (String) element;
+ if (elStr.endsWith(ALL_SUFFIX)) {
+ return fAggregatedTree.getChildren();
+ }
+ if (elStr.endsWith(PROCESS_SUFFIX)) {
+ return fProcessTree.getChildren();
+ }
+ return fTree.getChildren();
+ }
+
+ @Override
+ public Collection<String> getElements() {
+ return fElements;
+ }
+
+}
diff --git a/analyses/org.eclipse.tracecompass.incubator.kernel.core/src/org/eclipse/tracecompass/incubator/internal/kernel/core/criticalpath/package-info.java b/analyses/org.eclipse.tracecompass.incubator.kernel.core/src/org/eclipse/tracecompass/incubator/internal/kernel/core/criticalpath/package-info.java
new file mode 100644
index 0000000..ef49324
--- /dev/null
+++ b/analyses/org.eclipse.tracecompass.incubator.kernel.core/src/org/eclipse/tracecompass/incubator/internal/kernel/core/criticalpath/package-info.java
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * Copyright (c) 2020 É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.incubator.internal.kernel.core.criticalpath;
diff --git a/analyses/org.eclipse.tracecompass.incubator.kernel.ui/META-INF/MANIFEST.MF b/analyses/org.eclipse.tracecompass.incubator.kernel.ui/META-INF/MANIFEST.MF
index 41ddc0f..8579605 100644
--- a/analyses/org.eclipse.tracecompass.incubator.kernel.ui/META-INF/MANIFEST.MF
+++ b/analyses/org.eclipse.tracecompass.incubator.kernel.ui/META-INF/MANIFEST.MF
@@ -17,7 +17,10 @@
org.eclipse.core.resources,
org.eclipse.tracecompass.analysis.os.linux.core,
org.eclipse.tracecompass.analysis.os.linux.ui,
- org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional
+ org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional,
+ org.eclipse.tracecompass.incubator.analysis.core,
+ org.eclipse.tracecompass.incubator.callstack.core,
+ org.eclipse.tracecompass.incubator.callstack.ui
Export-Package: org.eclipse.tracecompass.incubator.internal.kernel.ui;x-internal:=true,
org.eclipse.tracecompass.incubator.internal.kernel.ui.views.contextswitch;x-internal:=true,
org.eclipse.tracecompass.incubator.internal.kernel.ui.views.fileaccess;x-internal:=true
diff --git a/analyses/org.eclipse.tracecompass.incubator.kernel.ui/plugin.xml b/analyses/org.eclipse.tracecompass.incubator.kernel.ui/plugin.xml
index f352d05..60b42e9 100644
--- a/analyses/org.eclipse.tracecompass.incubator.kernel.ui/plugin.xml
+++ b/analyses/org.eclipse.tracecompass.incubator.kernel.ui/plugin.xml
@@ -37,5 +37,4 @@
</analysisModuleClass>
</output>
</extension>
-
</plugin>
diff --git a/callstack/org.eclipse.tracecompass.incubator.callstack.core/src/org/eclipse/tracecompass/incubator/internal/callstack/core/flamegraph/FlameGraphDataProvider.java b/callstack/org.eclipse.tracecompass.incubator.callstack.core/src/org/eclipse/tracecompass/incubator/internal/callstack/core/flamegraph/FlameGraphDataProvider.java
index 805e93a..314b168 100644
--- a/callstack/org.eclipse.tracecompass.incubator.callstack.core/src/org/eclipse/tracecompass/incubator/internal/callstack/core/flamegraph/FlameGraphDataProvider.java
+++ b/callstack/org.eclipse.tracecompass.incubator.callstack.core/src/org/eclipse/tracecompass/incubator/internal/callstack/core/flamegraph/FlameGraphDataProvider.java
@@ -143,11 +143,37 @@
private final long fTraceId = ENTRY_ID.getAndIncrement();
private final ReentrantReadWriteLock fLock = new ReentrantReadWriteLock(false);
- private @Nullable Pair<Map<String, Object>, TmfModelResponse<TmfTreeModel<FlameChartEntryModel>>> fCached;
+ private @Nullable Pair<CacheKey, TmfModelResponse<TmfTreeModel<FlameChartEntryModel>>> fCached;
private final Map<Long, FlameChartEntryModel> fEntries = new HashMap<>();
private final Map<Long, WeightedTreeEntry> fCgEntries = new HashMap<>();
private final Map<Long, Long> fEndTimes = new HashMap<>();
+ private class CacheKey {
+ private final Map<String, Object> fParameters;
+ private final IWeightedTreeSet<N, Object, WeightedTree<N>> fTreeSet;
+
+ public CacheKey(Map<String, Object> parameters, IWeightedTreeSet<N, Object, WeightedTree<N>> treeset) {
+ fParameters = parameters;
+ fTreeSet = treeset;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(fParameters, fTreeSet);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof FlameGraphDataProvider.CacheKey)) {
+ return false;
+ }
+ return Objects.equals(fParameters, ((FlameGraphDataProvider.CacheKey) obj).fParameters)
+ && Objects.equals(fTreeSet, ((FlameGraphDataProvider.CacheKey) obj).fTreeSet);
+ }
+
+
+ }
+
/** An internal class to describe the data for an entry */
private class WeightedTreeEntry {
private ITmfStateSystem fSs;
@@ -218,23 +244,28 @@
fLock.writeLock().lock();
try (FlowScopeLog scope = new FlowScopeLogBuilder(LOGGER, Level.FINE, "FlameGraphDataProvider#fetchTree") //$NON-NLS-1$
.setCategory(getClass().getSimpleName()).build()) {
- // Did we cache this tree with those parameters
- Pair<Map<String, Object>, TmfModelResponse<TmfTreeModel<FlameChartEntryModel>>> cached = fCached;
- if (cached != null && cached.getFirst().equals(fetchParameters)) {
+ // Did we cache this tree with those parameters and the callgraph?
+ // For some analyses, the returned callgraph for the same parameters
+ // may vary if the analysis was done again, we need to cache for
+ // callgraph as well
+ SubMonitor subMonitor = Objects.requireNonNull(SubMonitor.convert(monitor, "FlameGraphDataProvider#fetchRowModel", 2)); //$NON-NLS-1$
+ IWeightedTreeSet<N, Object, WeightedTree<N>> callGraph = getCallGraph(fetchParameters, subMonitor);
+ if (callGraph == null) {
+ return new TmfModelResponse<>(null, ITmfResponse.Status.FAILED, CommonStatusMessage.TASK_CANCELLED);
+ }
+
+ CacheKey cacheKey = new CacheKey(fetchParameters, callGraph);
+ Pair<CacheKey, TmfModelResponse<TmfTreeModel<FlameChartEntryModel>>> cached = fCached;
+ if (cached != null && cached.getFirst().equals(cacheKey)) {
return cached.getSecond();
}
fEntries.clear();
fCgEntries.clear();
- SubMonitor subMonitor = Objects.requireNonNull(SubMonitor.convert(monitor, "FlameGraphDataProvider#fetchRowModel", 2)); //$NON-NLS-1$
- IWeightedTreeSet<N, Object, WeightedTree<N>> callGraph = getCallGraph(fetchParameters, subMonitor);
if (subMonitor.isCanceled()) {
return new TmfModelResponse<>(null, ITmfResponse.Status.CANCELLED, CommonStatusMessage.TASK_CANCELLED);
}
- if (callGraph == null) {
- return new TmfModelResponse<>(null, ITmfResponse.Status.FAILED, CommonStatusMessage.TASK_CANCELLED);
- }
long start = 0;
@@ -261,7 +292,7 @@
TmfModelResponse<TmfTreeModel<FlameChartEntryModel>> response = new TmfModelResponse<>(new TmfTreeModel<>(Collections.emptyList(), tree),
ITmfResponse.Status.COMPLETED, CommonStatusMessage.COMPLETED);
- fCached = new Pair<>(fetchParameters, response);
+ fCached = new Pair<>(cacheKey, response);
return response;
} finally {
diff --git a/callstack/org.eclipse.tracecompass.incubator.callstack.ui/src/org/eclipse/tracecompass/incubator/internal/callstack/ui/flamegraph/FlameGraphView.java b/callstack/org.eclipse.tracecompass.incubator.callstack.ui/src/org/eclipse/tracecompass/incubator/internal/callstack/ui/flamegraph/FlameGraphView.java
index b1fac22..a53f6dc 100644
--- a/callstack/org.eclipse.tracecompass.incubator.callstack.ui/src/org/eclipse/tracecompass/incubator/internal/callstack/ui/flamegraph/FlameGraphView.java
+++ b/callstack/org.eclipse.tracecompass.incubator.callstack.ui/src/org/eclipse/tracecompass/incubator/internal/callstack/ui/flamegraph/FlameGraphView.java
@@ -71,6 +71,7 @@
import org.eclipse.tracecompass.common.core.log.TraceCompassLogUtils.FlowScopeLogBuilder;
import org.eclipse.tracecompass.incubator.analysis.core.weighted.tree.AllGroupDescriptor;
import org.eclipse.tracecompass.incubator.analysis.core.weighted.tree.IWeightedTreeGroupDescriptor;
+import org.eclipse.tracecompass.incubator.analysis.core.weighted.tree.IWeightedTreeProvider;
import org.eclipse.tracecompass.incubator.callstack.core.callgraph.ICallGraphProvider;
import org.eclipse.tracecompass.incubator.internal.callstack.core.flamegraph.DataProviderUtils;
import org.eclipse.tracecompass.incubator.internal.callstack.core.flamegraph.FlameGraphDataProvider;
@@ -97,6 +98,7 @@
import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
+import org.eclipse.tracecompass.tmf.core.signal.TmfStartAnalysisSignal;
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
import org.eclipse.tracecompass.tmf.core.symbols.ISymbolProvider;
@@ -1581,4 +1583,25 @@
Display.getDefault().asyncExec(() -> restartZoomThread());
}
+ /**
+ * Listen to see if one of the view's analysis is restarted
+ *
+ * @param signal
+ * The analysis started signal
+ */
+ @TmfSignalHandler
+ public void analysisStart(TmfStartAnalysisSignal signal) {
+ ITmfTrace trace = getTrace();
+ if (trace == null) {
+ return;
+ }
+ IAnalysisModule module = signal.getAnalysisModule();
+ // It is not possible to link the module ID to the data provider, so
+ // just rebuild if the started module is a weighted tree provider
+ // FIXME This may be a performance issue
+ if (module instanceof IWeightedTreeProvider) {
+ buildFlameGraph(trace, null, null);
+ }
+ }
+
}
diff --git a/callstack/org.eclipse.tracecompass.incubator.callstack.ui/src/org/eclipse/tracecompass/incubator/internal/callstack/ui/views/flamechart/CallStackAnalysisListener.java b/callstack/org.eclipse.tracecompass.incubator.callstack.ui/src/org/eclipse/tracecompass/incubator/internal/callstack/ui/views/flamechart/CallStackAnalysisListener.java
index c34b0fb..3e49a91 100644
--- a/callstack/org.eclipse.tracecompass.incubator.callstack.ui/src/org/eclipse/tracecompass/incubator/internal/callstack/ui/views/flamechart/CallStackAnalysisListener.java
+++ b/callstack/org.eclipse.tracecompass.incubator.callstack.ui/src/org/eclipse/tracecompass/incubator/internal/callstack/ui/views/flamechart/CallStackAnalysisListener.java
@@ -9,7 +9,7 @@
package org.eclipse.tracecompass.incubator.internal.callstack.ui.views.flamechart;
-import org.eclipse.tracecompass.incubator.callstack.core.callgraph.ICallGraphProvider;
+import org.eclipse.tracecompass.incubator.analysis.core.weighted.tree.IWeightedTreeProvider;
import org.eclipse.tracecompass.incubator.callstack.core.flamechart.IEventCallStackProvider;
import org.eclipse.tracecompass.incubator.callstack.core.instrumented.IFlameChartProvider;
import org.eclipse.tracecompass.incubator.internal.callstack.ui.flamegraph.FlameGraphSelView;
@@ -36,7 +36,7 @@
module.registerOutput(new TmfAnalysisViewOutput(FlameChartView.ID, module.getId()));
module.registerOutput(new TmfAnalysisViewOutput(FunctionDensityView.ID, module.getId()));
}
- if (module instanceof ICallGraphProvider) {
+ if (module instanceof IWeightedTreeProvider) {
module.registerOutput(new TmfAnalysisViewOutput(FlameGraphView.ID, module.getId()));
module.registerOutput(new TmfAnalysisViewOutput(FlameGraphSelView.SEL_ID, module.getId()));
module.registerOutput(new TmfAnalysisViewOutput(WeightedTreeView.ID, module.getId()));
diff --git a/callstack/org.eclipse.tracecompass.incubator.callstack.ui/src/org/eclipse/tracecompass/incubator/internal/callstack/ui/views/weightedtree/WeightedTreePieChartViewer.java b/callstack/org.eclipse.tracecompass.incubator.callstack.ui/src/org/eclipse/tracecompass/incubator/internal/callstack/ui/views/weightedtree/WeightedTreePieChartViewer.java
index c22ae03..f00c89d 100644
--- a/callstack/org.eclipse.tracecompass.incubator.callstack.ui/src/org/eclipse/tracecompass/incubator/internal/callstack/ui/views/weightedtree/WeightedTreePieChartViewer.java
+++ b/callstack/org.eclipse.tracecompass.incubator.callstack.ui/src/org/eclipse/tracecompass/incubator/internal/callstack/ui/views/weightedtree/WeightedTreePieChartViewer.java
@@ -268,6 +268,10 @@
for (WeightedTree<?> tree : trees) {
totalWeight += tree.getWeight();
}
+ if (totalWeight == 0) {
+ // Children have no weight, return
+ return;
+ }
long otherWeight = 0;
// Add to the list only the trees that would be visible (> threshold),
@@ -280,7 +284,7 @@
otherWeight += tree.getWeight();
}
}
- Collections.sort(list);
+ Collections.sort(list, Collections.reverseOrder());
int listSize = otherWeight == 0 ? list.size() : list.size() + 1;
double[][] sliceValues = new double[listSize][1];
diff --git a/callstack/org.eclipse.tracecompass.incubator.callstack.ui/src/org/eclipse/tracecompass/incubator/internal/callstack/ui/views/weightedtree/WeightedTreeViewer.java b/callstack/org.eclipse.tracecompass.incubator.callstack.ui/src/org/eclipse/tracecompass/incubator/internal/callstack/ui/views/weightedtree/WeightedTreeViewer.java
index 73ef1c5..37e8e9d 100644
--- a/callstack/org.eclipse.tracecompass.incubator.callstack.ui/src/org/eclipse/tracecompass/incubator/internal/callstack/ui/views/weightedtree/WeightedTreeViewer.java
+++ b/callstack/org.eclipse.tracecompass.incubator.callstack.ui/src/org/eclipse/tracecompass/incubator/internal/callstack/ui/views/weightedtree/WeightedTreeViewer.java
@@ -350,6 +350,12 @@
}
}
+ /**
+ * Listen to see if one of the view's analysis is restarted
+ *
+ * @param signal
+ * The analysis started signal
+ */
@TmfSignalHandler
public void analysisStart(TmfStartAnalysisSignal signal) {
ITmfTrace trace = getTrace();
@@ -358,7 +364,7 @@
}
Set<IWeightedTreeProvider<?, ?, WeightedTree<?>>> modules = fView.getWeightedTrees(trace);
if (modules.contains(signal.getAnalysisModule())) {
- this.updateContent(trace.getStartTime().toNanos(), trace.getEndTime().toNanos(), false);
+ updateContent(trace.getStartTime().toNanos(), trace.getEndTime().toNanos(), false);
}
}
@@ -552,7 +558,7 @@
Set<IWeightedTreeProvider<?, ?, WeightedTree<?>>> modules = fView.getWeightedTrees(trace);
- if (modules.isEmpty()) {
+ if (isSelection || modules.isEmpty()) {
return null;
}
modules.forEach(m -> {
@@ -593,7 +599,7 @@
* @param monitor
*/
private <@NonNull E> void setSelection(long start, long end, List<ITmfTreeViewerEntry> entryList, IWeightedTreeProvider<?, E, WeightedTree<?>> module, boolean isSelection, IProgressMonitor monitor) {
-
+ // Selection is not supported
}
@Override