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;
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;
/**
// 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);
+ }
+ }
}
--- /dev/null
+/*******************************************************************************
+ * 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));
+ }
+}
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,
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
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>
--- /dev/null
+/*******************************************************************************
+ * 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
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+}
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.