timing: add statistics analysis to functions calls
authorMatthew Khouzam <matthew.khouzam@ericsson.com>
Fri, 28 Apr 2017 19:57:06 +0000 (15:57 -0400)
committerMatthew Khouzam <matthew.khouzam@ericsson.com>
Wed, 17 May 2017 17:13:50 +0000 (13:13 -0400)
This, with the flame graph, call stack, call graph and function densisty
can make a profiling perspective.

Additional tests coming in a separate patch.

Change-Id: Idcee650cf9b32963b5aaddd3e66a8d00e06b5b9e
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/79898
Reviewed-by: Hudson CI
Reviewed-by: Genevieve Bastien <gbastien+lttng@versatic.net>
Tested-by: Genevieve Bastien <gbastien+lttng@versatic.net>
analysis/org.eclipse.tracecompass.analysis.timing.core.tests/src/org/eclipse/tracecompass/analysis/timing/core/tests/callgraph/CallGraphAnalysisTest.java
analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/CallGraphStatisticsAnalysis.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/META-INF/MANIFEST.MF
analysis/org.eclipse.tracecompass.analysis.timing.ui/plugin.properties
analysis/org.eclipse.tracecompass.analysis.timing.ui/plugin.xml
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/statistics/CallGraphStatisticsView.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/statistics/CallGraphStatisticsViewer.java [new file with mode: 0644]
doc/org.eclipse.tracecompass.doc.user/doc/User-Guide.mediawiki

index 27fa9b1efd8358f1f54349abfbe33e11e5213363..735c0e07088a457c83915721d9cffd72f99f884b 100644 (file)
 package org.eclipse.tracecompass.analysis.timing.core.tests.callgraph;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import java.util.Collection;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.AggregatedCalledFunction;
 import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.CallGraphAnalysis;
 import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.ICalledFunction;
+import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.ThreadNode;
 import org.eclipse.tracecompass.segmentstore.core.ISegment;
 import org.eclipse.tracecompass.segmentstore.core.ISegmentStore;
 import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
@@ -32,6 +38,7 @@ import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend;
 import org.eclipse.tracecompass.statesystem.core.backend.StateHistoryBackendFactory;
 import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
 import org.eclipse.tracecompass.tmf.core.segment.ISegmentAspect;
+import org.junit.Assert;
 import org.junit.Test;
 
 /**
@@ -398,6 +405,41 @@ public class CallGraphAnalysisTest {
 
         // Test if the first child and the third one have the same address
         assertEquals("Test the address of two functions", firstChild.getSymbol(), thirdChild.getSymbol());
+
+        // test Flamegraph
+        Collection<@NonNull ThreadNode> flameGraph = cga.getFlameGraph();
+        assertNotNull("Test Flamegraph", flameGraph);
+        assertFalse(flameGraph.isEmpty());
+        ThreadNode flamegraphRoot = flameGraph.iterator().next();
+        assertNotNull("Test Flamegraph root", flamegraphRoot);
+
+        Collection<@NonNull ThreadNode> threadGraph = cga.getThreadNodes();
+        assertNotNull("Test ThreadNodes", threadGraph);
+        assertFalse(threadGraph.isEmpty());
+        ThreadNode threadgraphRoot = threadGraph.iterator().next();
+        localAssertEquals("Test Flamegraph root", threadgraphRoot, flamegraphRoot);
+
         cga.dispose();
     }
+
+    private void localAssertEquals(String message, AggregatedCalledFunction aggregatedCalledFunction, AggregatedCalledFunction actualElem) {
+        if (Objects.equals(aggregatedCalledFunction, actualElem)) {
+            return;
+        }
+        assertNotNull(message, aggregatedCalledFunction);
+        assertNotNull(message, actualElem);
+        Assert.assertEquals(message, aggregatedCalledFunction.getDepth(), actualElem.getDepth());
+        Assert.assertEquals(message, aggregatedCalledFunction.getDuration(), actualElem.getDuration());
+        Assert.assertEquals(message, aggregatedCalledFunction.getMaxDepth(), actualElem.getMaxDepth());
+        Assert.assertEquals(message, aggregatedCalledFunction.getMaxDepth(), actualElem.getMaxDepth());
+        Assert.assertEquals(message, aggregatedCalledFunction.getSelfTime(), actualElem.getSelfTime());
+        localAssertEquals(message, aggregatedCalledFunction.getChildren(), actualElem.getChildren());
+    }
+
+    private void localAssertEquals(String message, @NonNull Collection<@NonNull AggregatedCalledFunction> expected, @NonNull Collection<@NonNull AggregatedCalledFunction> actual) {
+        Iterator<@NonNull AggregatedCalledFunction> expectedIter = expected.iterator();
+        for (AggregatedCalledFunction actualElem : actual) {
+            localAssertEquals(message, expectedIter.next(), actualElem);
+        }
+    }
 }
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/CallGraphStatisticsAnalysis.java b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/CallGraphStatisticsAnalysis.java
new file mode 100644 (file)
index 0000000..fc04e79
--- /dev/null
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Ericsson
+ *
+ * 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.timing.core.callgraph;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider;
+import org.eclipse.tracecompass.analysis.timing.core.segmentstore.statistics.AbstractSegmentStatisticsAnalysis;
+import org.eclipse.tracecompass.segmentstore.core.ISegment;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
+
+/**
+ * Call graph statistics analysis used to get statistics on each function type.
+ *
+ * @author Matthew Khouzam
+ */
+public class CallGraphStatisticsAnalysis extends AbstractSegmentStatisticsAnalysis {
+
+    /** The analysis module ID */
+    public static final String ID = CallGraphAnalysis.ID + ".statistics"; //$NON-NLS-1$
+
+    @Override
+    protected @Nullable ISegmentStoreProvider getSegmentProviderAnalysis(@NonNull ITmfTrace trace) {
+        return TmfTraceUtils.getAnalysisModuleOfClass(trace, CallGraphAnalysis.class, CallGraphAnalysis.ID);
+    }
+
+    @Override
+    protected @Nullable String getSegmentType(@NonNull ISegment segment) {
+        return String.valueOf(SymbolAspect.SYMBOL_ASPECT.resolve(segment));
+    }
+}
index 92374c108e1377cccc41b22ef5b7dc7f42b4f60b..d040908d26565f3cbccafbdf32b1c45af88c363d 100644 (file)
@@ -27,6 +27,7 @@ Export-Package: org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore,
  org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.table,
  org.eclipse.tracecompass.internal.analysis.timing.ui,
  org.eclipse.tracecompass.internal.analysis.timing.ui.callgraph;x-friends:="org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests",
+ org.eclipse.tracecompass.internal.analysis.timing.ui.callgraph.statistics;x-friends:="org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests",
  org.eclipse.tracecompass.internal.analysis.timing.ui.flamegraph;x-friends:="org.eclipse.tracecompass.analysis.timing.ui.swtbot.tests",
  org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore;x-internal:=true,
  org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.density;x-internal:=true,
index b7f17323b472eaffaaf1fd39f8f8b57697e6836b..6661faf6fc669b1b41430b859976c7f99613fdce 100644 (file)
@@ -16,3 +16,4 @@ view.callgraphDensity= Function Durations Distribution
 view.flameGraph= Flame Graph
 view.segstore.table = Segment Store Table
 view.segstore.statistics = Descriptive Statistics
+view.callgraph.statistics = Function Duration Statistics
\ No newline at end of file
index 3f84827d09d55b2fa233e3496e22c1c8d80ac992..53b583428556cab09f16b82e4fdb52fb8e2dd499 100644 (file)
                class="org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.CallGraphAnalysis">
          </analysisModuleClass>
       </output>
+      <output
+            class="org.eclipse.tracecompass.tmf.ui.analysis.TmfAnalysisViewOutput"
+            id="org.eclipse.tracecompass.internal.analysis.timing.ui.callgraph.statistics.callgraphstatistics">
+         <analysisModuleClass
+               class="org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.CallGraphAnalysis">
+         </analysisModuleClass>
+      </output>
    </extension>
    <extension
          point="org.eclipse.ui.views">
             name="%view.segstore.statistics"
             restorable="true">
       </view>
+      <view
+            allowMultiple="false"
+            category="org.eclipse.linuxtools.tmf.ui.views.category"
+            class="org.eclipse.tracecompass.internal.analysis.timing.ui.callgraph.statistics.CallGraphStatisticsView"
+            icon="icons/eview16/statistics_view.gif"
+            id="org.eclipse.tracecompass.internal.analysis.timing.ui.callgraph.statistics.callgraphstatistics"
+            name="%view.callgraph.statistics"
+            restorable="true">
+      </view>
    </extension>
 </plugin>
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/statistics/CallGraphStatisticsView.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/statistics/CallGraphStatisticsView.java
new file mode 100644 (file)
index 0000000..c75718f
--- /dev/null
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Ericsson
+ *
+ * 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.timing.ui.callgraph.statistics;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.statistics.AbstractSegmentsStatisticsView;
+import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.statistics.AbstractSegmentsStatisticsViewer;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
+import org.eclipse.tracecompass.tmf.ui.symbols.TmfSymbolProviderUpdatedSignal;
+
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * View to display Function Duration statistics.
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class CallGraphStatisticsView extends AbstractSegmentsStatisticsView {
+
+    /** The view ID */
+    public static final String ID = CallGraphStatisticsView.class.getPackage().getName() + ".callgraphStatistics"; //$NON-NLS-1$
+    private @Nullable CallGraphStatisticsViewer fViewer;
+
+    /**
+     * Constructor
+     */
+    public CallGraphStatisticsView() {
+        super();
+        TmfSignalManager.register(this);
+    }
+
+    @Override
+    protected AbstractSegmentsStatisticsViewer createSegmentStoreStatisticsViewer(Composite parent) {
+        fViewer = new CallGraphStatisticsViewer(parent);
+        return fViewer;
+    }
+
+    /**
+     * Symbol map provider updated
+     *
+     * @param signal
+     *            the signal
+     */
+    @TmfSignalHandler
+    public void symbolMapUpdated(TmfSymbolProviderUpdatedSignal signal) {
+        if (signal.getSource() != this) {
+            CallGraphStatisticsViewer viewer = fViewer;
+            if (viewer != null) {
+                viewer.refresh();
+            }
+        }
+    }
+
+    /**
+     * Get the current tree viewer
+     *
+     * @return the current tree viewer
+     */
+    @VisibleForTesting
+    public @Nullable CallGraphStatisticsViewer getTreeViewer() {
+        return fViewer;
+    }
+
+}
\ No newline at end of file
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/statistics/CallGraphStatisticsViewer.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/statistics/CallGraphStatisticsViewer.java
new file mode 100644 (file)
index 0000000..657bc02
--- /dev/null
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Ericsson
+ *
+ * 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.timing.ui.callgraph.statistics;
+
+import java.util.Objects;
+import java.util.function.Function;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.statistics.AbstractSegmentsStatisticsViewer;
+import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.CallGraphStatisticsAnalysis;
+import org.eclipse.tracecompass.tmf.core.analysis.TmfAbstractAnalysisModule;
+import org.eclipse.tracecompass.tmf.core.symbols.ISymbolProvider;
+import org.eclipse.tracecompass.tmf.core.symbols.SymbolProviderManager;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+
+/**
+ * A tree viewer implementation for displaying function duration statistics
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class CallGraphStatisticsViewer extends AbstractSegmentsStatisticsViewer {
+
+    private static final class SymbolFormatter implements Function<SegmentStoreStatisticsEntry, String> {
+
+        private final @Nullable ISymbolProvider fSymbolProvider;
+
+        public SymbolFormatter(@Nullable ITmfTrace trace) {
+            fSymbolProvider = trace != null ? SymbolProviderManager.getInstance().getSymbolProvider(trace) : null;
+        }
+
+        @Override
+        public String apply(@Nullable SegmentStoreStatisticsEntry stat) {
+
+            String original = (stat == null) ? "null" : stat.getName(); //$NON-NLS-1$
+            ISymbolProvider symbolProvider = fSymbolProvider;
+            if (symbolProvider == null) {
+                return original;
+            }
+            try {
+                Long address = Long.decode(original);
+                String res = symbolProvider.getSymbolText(address);
+                if (res != null) {
+                    return res;
+                }
+                return "0x" + Long.toHexString(address); //$NON-NLS-1$
+            } catch (NumberFormatException e) {
+                // it's OK, ignore it
+            }
+            return original;
+        }
+    }
+
+    /**
+     * Constructor
+     *
+     * @param parent
+     *            the parent composite
+     */
+    public CallGraphStatisticsViewer(Composite parent) {
+        super(Objects.requireNonNull(parent));
+        setLabelProvider(new SegmentStoreStatisticsLabelProvider() {
+            @Override
+            public @NonNull String getColumnText(@Nullable Object element, int columnIndex) {
+                if (columnIndex == 0 && (element instanceof SegmentStoreStatisticsEntry)) {
+                    SegmentStoreStatisticsEntry entry = (SegmentStoreStatisticsEntry) element;
+                    SymbolFormatter fe = new SymbolFormatter(getTrace());
+                    return String.valueOf(fe.apply(entry));
+                }
+                return super.getColumnText(element, columnIndex);
+            }
+        });
+    }
+
+    /**
+     * Gets the statistics analysis module
+     *
+     * @return the statistics analysis module
+     */
+    @Override
+    protected @Nullable TmfAbstractAnalysisModule createStatisticsAnalysiModule() {
+        return new CallGraphStatisticsAnalysis();
+    }
+}
index 2ac7af7e3894b7340db62f5bd159196d343c4243..ca9a100f7d9d1ccbf14c6a087530de0c409f92c5 100644 (file)
@@ -2719,6 +2719,16 @@ that seems to be taking too longThen, using the context menu '''Go to maximum'''
 to the maximum duration and see if the OS is, for example, preempting the function for too long,
 or if the issue is in the code being executed.
 
+== Function Duration Statistics ==
+
+This displays the descriptive statistics of the 'wall time' durations of given functions. It gives an
+overview of how often a function is called, how much total time it took, its mean duration as well as
+its maximum, minimum times and the standard deviation.
+
+If a time range is selected it will display the local statistics too.
+
+This analysis is available if the ''Flame Graph'' is available.
+
 === Using the mouse ===
 
 *'''Double-click on the duration ruler''' will zoom the graph to the selected duration range.
This page took 0.02995 seconds and 5 git commands to generate.