From 905218ff9c666bf16ddc66a862ddfb01ff198dde Mon Sep 17 00:00:00 2001 From: Sonia Farrah Date: Thu, 30 Jun 2016 11:25:56 -0400 Subject: [PATCH] timing: show callStack segments in a density view This creates a segment store for the callstack view and populates it. Then the segments are used to fill a density view. The segments are special segments with links to their children. This effectively is a callgraph that can then be used for other analyses. Examples of these analyses are: * Flame graphs * Tree maps * Caller trees * Call statistcs These views will allow trace compass to work better as a profiler on an application level. Change-Id: I0a1e8eda192e0646dd02bc4134c672a392231208 Signed-off-by: Sonia Farrah Signed-off-by: Matthew Khouzam Reviewed-on: https://git.eclipse.org/r/76369 Reviewed-by: Genevieve Bastien Tested-by: Genevieve Bastien Reviewed-by: Hudson CI --- .../META-INF/MANIFEST.MF | 4 +- .../plugin.properties | 2 +- .../core/callgraph/CallGraphAnalysis.java | 345 ++++++++++++++++++ .../timing/core/callgraph/CalledFunction.java | 184 ++++++++++ .../timing/core/callgraph/Messages.java | 44 +++ .../timing/core/callgraph/messages.properties | 12 + .../timing/core/callgraph/package-info.java | 11 + .../META-INF/MANIFEST.MF | 5 +- .../build.properties | 3 +- .../icons/elcl16/callgraph.png | Bin 0 -> 182 bytes .../icons/elcl16/funcdensity.png | Bin 0 -> 176 bytes .../plugin.properties | 3 + .../plugin.xml | 37 ++ .../ui/callgraph/CallGraphAnalysisUI.java | 41 +++ .../ui/callgraph/CallGraphDensityView.java | 55 +++ .../ui/callgraph/CallGraphDensityViewer.java | 42 +++ .../ui/callgraph/CallGraphTableViewer.java | 72 ++++ .../timing/ui/callgraph/Messages.java | 32 ++ .../timing/ui/callgraph/SymbolAspect.java | 80 ++++ .../timing/ui/callgraph/messages.properties | 9 + .../SyncAlgorithmFullyIncremental.java | 9 +- 21 files changed, 981 insertions(+), 9 deletions(-) create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/CallGraphAnalysis.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/CalledFunction.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/Messages.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/messages.properties create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/package-info.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/icons/elcl16/callgraph.png create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/icons/elcl16/funcdensity.png create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/plugin.xml create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/CallGraphAnalysisUI.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/CallGraphDensityView.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/CallGraphDensityViewer.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/CallGraphTableViewer.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/Messages.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/SymbolAspect.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/messages.properties diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core/META-INF/MANIFEST.MF b/analysis/org.eclipse.tracecompass.analysis.timing.core/META-INF/MANIFEST.MF index 27b344b922..b5575eb8f1 100644 --- a/analysis/org.eclipse.tracecompass.analysis.timing.core/META-INF/MANIFEST.MF +++ b/analysis/org.eclipse.tracecompass.analysis.timing.core/META-INF/MANIFEST.MF @@ -17,6 +17,8 @@ Require-Bundle: org.eclipse.ui, Export-Package: org.eclipse.tracecompass.analysis.timing.core.segmentstore, org.eclipse.tracecompass.analysis.timing.core.segmentstore.statistics, org.eclipse.tracecompass.internal.analysis.timing.core, + org.eclipse.tracecompass.internal.analysis.timing.core.callgraph;x-friends:="org.eclipse.tracecompass.analysis.timing.ui", org.eclipse.tracecompass.internal.analysis.timing.core.store;x-friends:="org.eclipse.tracecompass.analysis.timing.core.tests,org.eclipse.tracecompass.tmf.analysis.xml.core" -Import-Package: com.google.common.collect, +Import-Package: com.google.common.annotations;version="15.0.0", + com.google.common.collect, com.google.common.hash diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core/plugin.properties b/analysis/org.eclipse.tracecompass.analysis.timing.core/plugin.properties index 30c4dba945..080780f7ae 100644 --- a/analysis/org.eclipse.tracecompass.analysis.timing.core/plugin.properties +++ b/analysis/org.eclipse.tracecompass.analysis.timing.core/plugin.properties @@ -8,4 +8,4 @@ ############################################################################### Bundle-Vendor = Eclipse Trace Compass -Bundle-Name = Trace Compass Timing Analysis Core Plug-in \ No newline at end of file +Bundle-Name = Trace Compass Timing Analysis Core Plug-in diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/CallGraphAnalysis.java b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/CallGraphAnalysis.java new file mode 100644 index 0000000000..8392816008 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/CallGraphAnalysis.java @@ -0,0 +1,345 @@ +/******************************************************************************* + * 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.core.callgraph; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.IAnalysisProgressListener; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider; +import org.eclipse.tracecompass.common.core.StreamUtils; +import org.eclipse.tracecompass.internal.analysis.timing.core.Activator; +import org.eclipse.tracecompass.internal.analysis.timing.core.store.ArrayListStore; +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.exceptions.AttributeNotFoundException; +import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException; +import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException; +import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval; +import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; +import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule; +import org.eclipse.tracecompass.tmf.core.analysis.TmfAbstractAnalysisModule; +import org.eclipse.tracecompass.tmf.core.callstack.CallStackAnalysis; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; + +/** + * Call stack analysis used to create a segment for each call function from an + * entry/exit event. It builds a segment tree from the state system. An example + * taken from the Fibonacci trace's callStack shows the structure of the segment + * tree given by this analysis: + * + *
+ * (Caller)  main
+ *            ↓↑
+ * (Callee) Fibonacci
+ *           ↓↑    ↓↑
+ *      Fibonacci Fibonacci
+ *         ↓↑         ↓↑
+ *         ...        ...
+ * 
+ * + * @author Sonia Farrah + */ +public abstract class CallGraphAnalysis extends TmfAbstractAnalysisModule implements ISegmentStoreProvider { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * Segment store + */ + private final ISegmentStore<@NonNull ISegment> fStore = new ArrayListStore<>(); + + /** + * Listeners + */ + private final ListenerList fListeners = new ListenerList(ListenerList.IDENTITY); + + /** + * The Trace's root functions list + */ + private final List fRootFunctions = new ArrayList<>(); + + /** + * The sub attributes of a certain thread + */ + private List fCurrentQuarks = Collections.emptyList(); + + /** + * Default constructor + */ + public CallGraphAnalysis() { + super(); + } + + @Override + public @NonNull String getHelpText() { + String msg = Messages.CallGraphAnalysis_Description; + return (msg != null) ? msg : super.getHelpText(); + } + + @Override + public @NonNull String getHelpText(@NonNull ITmfTrace trace) { + return getHelpText(); + } + + @Override + public boolean canExecute(ITmfTrace trace) { + /* + * FIXME: change to !Iterables.isEmpty(getDependentAnalyses()) when + * analysis dependencies work better + */ + return true; + } + + @Override + protected Iterable getDependentAnalyses() { + return TmfTraceManager.getTraceSet(getTrace()).stream() + .flatMap(trace -> StreamUtils.getStream(TmfTraceUtils.getAnalysisModulesOfClass(trace, CallStackAnalysis.class))) + .distinct().collect(Collectors.toList()); + } + + @Override + protected boolean executeAnalysis(@Nullable IProgressMonitor monitor) { + ITmfTrace trace = getTrace(); + if (monitor == null || trace == null) { + return false; + } + Iterable dependentAnalyses = getDependentAnalyses(); + for (IAnalysisModule module : dependentAnalyses) { + if (!(module instanceof CallStackAnalysis)) { + return false; + } + module.schedule(); + } + // TODO:Look at updates while the state system's being built + dependentAnalyses.forEach((t) -> t.waitForCompletion(monitor)); + for (IAnalysisModule module : dependentAnalyses) { + CallStackAnalysis callstackModule = (CallStackAnalysis) module; + String[] threadsPattern = callstackModule.getThreadsPattern(); + String[] processesPattern = callstackModule.getProcessesPattern(); + String[] callStackPath = callstackModule.getCallStackPath(); + ITmfStateSystem ss = callstackModule.getStateSystem(); + if (!iterateOverStateSystem(ss, threadsPattern, processesPattern, callStackPath, monitor)) { + return false; + } + } + monitor.worked(1); + monitor.done(); + return true; + + } + + /** + * Iterate over the process of the state system,then iterate over the + * different threads of each process. + * + * @param ss + * The state system + * @param threadsPattern + * The threads pattern + * @param processesPattern + * The processes pattern + * @param callStackPath + * The call stack path + * @param monitor + * The monitor + * @return Boolean + */ + @VisibleForTesting + protected boolean iterateOverStateSystem(@Nullable ITmfStateSystem ss, String[] threadsPattern, String[] processesPattern, String[] callStackPath, IProgressMonitor monitor) { + if (ss == null) { + return false; + } + List processQuarks = ss.getQuarks(processesPattern); + for (int processQuark : processQuarks) { + for (int threadQuark : ss.getQuarks(processQuark, threadsPattern)) { + if (!iterateOverQuark(ss, threadQuark, callStackPath, monitor)) { + return false; + } + } + } + sendUpdate(fStore); + return true; + } + + /** + * Iterate over functions with the same quark,search for their callees then + * add them to the segment store + * + * @param stateSystem + * The state system + * @param quark + * The quark + * @param subAttributePath + * sub-Attributes path + * @param monitor + * The monitor + * @return Boolean + */ + private boolean iterateOverQuark(ITmfStateSystem stateSystem, int quark, String[] subAttributePath, IProgressMonitor monitor) { + try { + long curTime = stateSystem.getStartTime(); + long limit = stateSystem.getCurrentEndTime(); + while (curTime < limit) { + if (monitor.isCanceled()) { + return false; + } + int callStackQuark = stateSystem.getQuarkRelative(quark, subAttributePath); + fCurrentQuarks = stateSystem.getSubAttributes(callStackQuark, false); + if (fCurrentQuarks.isEmpty()) { + return false; + } + final int depth = 0; + int quarkParent = fCurrentQuarks.get(depth); + ITmfStateInterval interval = stateSystem.querySingleState(curTime, quarkParent); + ITmfStateValue stateValue = interval.getStateValue(); + + if (!stateValue.isNull()) { + long intervalStart = interval.getStartTime(); + long intervalEnd = interval.getEndTime(); + // Create the segment for the first call event. + CalledFunction segment = new CalledFunction(intervalStart, intervalEnd + 1, stateValue.unboxLong(), depth); + fRootFunctions.add(segment); + if (!findChildren(segment, depth, stateSystem, fCurrentQuarks.size() + fCurrentQuarks.get(depth), monitor)) { + return false; + } + + } + + curTime = interval.getEndTime() + 1; + } + + } catch (AttributeNotFoundException | StateSystemDisposedException | TimeRangeException e) { + Activator.getInstance().logError(Messages.QueringStateSystemError, e); + return false; + } + return true; + } + + /** + * Find the functions called by a parent function in a call stack then add + * segments for each child, updating the self times of each node + * accordingly. + * + * @param node + * The segment of the stack call event(the parent) callStackQuark + * @param depth + * The depth of the parent function + * @param ss + * The quark of the segment parent ss The actual state system + * @param maxQuark + * The last quark in the state system + * @param monitor + * The progress monitor The progress monitor TODO: if stack size + * is an issue, convert to a stack instead of recursive function + */ + private boolean findChildren(CalledFunction node, int depth, ITmfStateSystem ss, int maxQuark, IProgressMonitor monitor) { + fStore.add(node); + long curTime = node.getStart(); + long limit = node.getEnd(); + ITmfStateInterval interval = null; + while (curTime < limit) { + if (monitor.isCanceled()) { + return false; + } + try { + if (depth + 1 < fCurrentQuarks.size()) { + interval = ss.querySingleState(curTime, fCurrentQuarks.get(depth + 1)); + } else { + return true; + } + } catch (StateSystemDisposedException e) { + Activator.getInstance().logError(Messages.QueringStateSystemError, e); + return false; + } + ITmfStateValue stateValue = interval.getStateValue(); + if (!stateValue.isNull()) { + long intervalStart = interval.getStartTime(); + long intervalEnd = interval.getEndTime(); + if (intervalStart < node.getStart() || intervalEnd > limit) { + return true; + } + CalledFunction segment = new CalledFunction(intervalStart, intervalEnd + 1, stateValue.unboxLong(), node.getDepth() + 1); + // Search for the children with the next quark. + findChildren(segment, depth + 1, ss, maxQuark, monitor); + node.addChild(segment); + } + curTime = interval.getEndTime() + 1; + } + return true; + } + + @Override + public void addListener(@NonNull IAnalysisProgressListener listener) { + fListeners.add(listener); + } + + @Override + public void removeListener(@NonNull IAnalysisProgressListener listener) { + fListeners.remove(listener); + } + + @Override + protected void canceling() { + // Do nothing + } + + @Override + public @Nullable ISegmentStore<@NonNull ISegment> getSegmentStore() { + return fStore; + } + + /** + * Update listeners + * + * @param store + * The segment store + */ + protected void sendUpdate(final ISegmentStore<@NonNull ISegment> store) { + getListeners().forEach(listener -> listener.onComplete(this, store)); + } + + /** + * Get Listeners + * + * @return The listeners + */ + protected Iterable getListeners() { + return Arrays.stream(fListeners.getListeners()) + .filter(listener -> listener instanceof IAnalysisProgressListener) + .map(listener -> (IAnalysisProgressListener) listener) + .collect(Collectors.toList()); + } + + /** + * The functions of the first level + * + * @return Functions of the first level + */ + public List getThreads() { + return ImmutableList.copyOf(fRootFunctions); + } + +} \ No newline at end of file diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/CalledFunction.java b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/CalledFunction.java new file mode 100644 index 0000000000..33ec49185e --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/CalledFunction.java @@ -0,0 +1,184 @@ +/******************************************************************************* + * 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.core.callgraph; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.segmentstore.core.ISegment; +import org.eclipse.tracecompass.segmentstore.core.SegmentComparators; + +import com.google.common.collect.Ordering; + +/** + * A Call stack function represented as an {@link ISegment}. It's used to build + * a segments tree based on the state system. The parent represents the caller + * of the function, and the children list represents its callees. + * + * @author Sonia Farrah + */ +public class CalledFunction implements ISegment { + + private static final long serialVersionUID = 7594768649825490010L; + private static final Comparator COMPARATOR; + static { + /* + * checkNotNull() has to be called separately, or else it breaks the + * type inference. + */ + Comparator comp = Ordering.from(SegmentComparators.INTERVAL_START_COMPARATOR).compound(SegmentComparators.INTERVAL_END_COMPARATOR); + COMPARATOR = checkNotNull(comp); + } + + private final long fStart; + private final long fEnd; + private final long fAddr; + private final int fDepth; + private final List fChildren = new ArrayList<>(); + @Nullable private CalledFunction fParent = null; + private long fSelfTime = 0; + + /** + * Create a new segment. + * + * The end position should be equal to or greater than the start position. + * + * @param start + * Start position of the segment + * @param end + * End position of the segment + * @param address + * The address of the call stack event + * @param depth + * The depth in the call stack of a function + */ + public CalledFunction(long start, long end, long address, int depth) { + if (start > end) { + throw new IllegalArgumentException(Messages.TimeError + "[" + start + "," + end + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + fStart = start; + fEnd = end; + fAddr = address; + // It'll be modified once we add a child to it + fSelfTime = fEnd - fStart; + fDepth = depth; + } + + @Override + public long getStart() { + return fStart; + } + + @Override + public long getEnd() { + return fEnd; + } + + @Override + public int compareTo(@Nullable ISegment o) { + if (o == null) { + throw new IllegalArgumentException(); + } + return COMPARATOR.compare(this, o); + } + + @Override + public String toString() { + return new String("[" + String.valueOf(fStart) + ", " + String.valueOf(fEnd) + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /** + * The address of the call stack event. + * + * @return The address + * + */ + public long getAddr() { + return fAddr; + } + + /** + * The children of the segment + * + * @return The children + * + */ + public List getChildren() { + return fChildren; + } + + /** + * The segment's parent + * + * @return The parent + * + */ + public @Nullable CalledFunction getParent() { + return fParent; + } + + /** + * The segment's parent + * + * @param parent + * The parent of the segment + * + */ + private void setParent(CalledFunction parent) { + fParent = parent; + } + + /** + * Add the child to the segment's children, and subtract the child's + * duration to the duration of the segment so we can calculate its self + * time. + * + * @param child + * The child to add to the segment's children + */ + public void addChild(CalledFunction child) { + child.setParent(this); + fChildren.add(child); + substractChildDuration(child.fEnd - child.fStart); + } + + /** + * Subtract the child's duration to the duration of the segment. + * + * @param childDuration + * The child's duration + */ + private void substractChildDuration(long childDuration) { + fSelfTime -= childDuration; + } + + /** + * The segment's self Time + * + * @return finalSelfTime The self time + */ + public long getSelfTime() { + return fSelfTime; + } + + /** + * The depth in the call stack of a function + * + * @return The depth of a function + */ + public int getDepth() { + return fDepth; + } + +} \ No newline at end of file diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/Messages.java b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/Messages.java new file mode 100644 index 0000000000..1a5cd49f91 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/Messages.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * 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.core.callgraph; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.osgi.util.NLS; + +/** + * Message bundle for the call stack analysis module + * + * @author Sonia Farrah + */ +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.messages"; //$NON-NLS-1$ + /** + * Analysis description for the help + */ + public static @Nullable String CallGraphAnalysis_Description; + /** + * The call stack event's name + */ + public static @Nullable String CallStack_FunctionName; + /** + * Querying state system error's message + */ + public static @Nullable String QueringStateSystemError; + /** + * Segment's start time exceeding its end time Error message + */ + public static @Nullable String TimeError; + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/messages.properties b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/messages.properties new file mode 100644 index 0000000000..605dec43fa --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/messages.properties @@ -0,0 +1,12 @@ +############################################################################### +# 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 +############################################################################### +CallGraphAnalysis_Description=Generate a callgraph for a trace with function entries and exits. +CallStack_FunctionName=Function name +QueringStateSystemError=Error querying state system +TimeError=Segment cannot end before it starts diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/package-info.java b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/package-info.java new file mode 100644 index 0000000000..874f5d74bc --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/callgraph/package-info.java @@ -0,0 +1,11 @@ +/******************************************************************************* + * Copyright (c) 2015, 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 + *******************************************************************************/ + +@org.eclipse.jdt.annotation.NonNullByDefault +package org.eclipse.tracecompass.internal.analysis.timing.core.callgraph; diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/META-INF/MANIFEST.MF b/analysis/org.eclipse.tracecompass.analysis.timing.ui/META-INF/MANIFEST.MF index 448c533a67..7927e757f7 100644 --- a/analysis/org.eclipse.tracecompass.analysis.timing.ui/META-INF/MANIFEST.MF +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/META-INF/MANIFEST.MF @@ -16,13 +16,16 @@ Require-Bundle: org.eclipse.ui, org.eclipse.tracecompass.segmentstore.core, org.eclipse.tracecompass.tmf.core, org.eclipse.tracecompass.tmf.ui, - org.swtchart + org.swtchart, + org.eclipse.tracecompass.analysis.timing.ui, + org.eclipse.jface Export-Package: org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore, org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density, org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.scatter, org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.statistics, 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-internal:=true, org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.density, org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.scatter, org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.statistics, diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/build.properties b/analysis/org.eclipse.tracecompass.analysis.timing.ui/build.properties index 8016acacc9..fc974de324 100644 --- a/analysis/org.eclipse.tracecompass.analysis.timing.ui/build.properties +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/build.properties @@ -13,7 +13,8 @@ bin.includes = META-INF/,\ plugin.properties,\ .,\ icons/,\ - about.html + about.html,\ + plugin.xml additional.bundles = org.eclipse.jdt.annotation jars.extra.classpath = platform:/plugin/org.eclipse.jdt.annotation src.includes = about.html diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/icons/elcl16/callgraph.png b/analysis/org.eclipse.tracecompass.analysis.timing.ui/icons/elcl16/callgraph.png new file mode 100644 index 0000000000000000000000000000000000000000..48e0b4b31beb3a114da3a2d34c280547a27db5f2 GIT binary patch literal 182 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#VfdwZr6z@a zl$fyStX>)SiA;_y%dcw58OaFGh}^Neqr=6eT + + + + + + + + + + + + + + + + + diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/CallGraphAnalysisUI.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/CallGraphAnalysisUI.java new file mode 100644 index 0000000000..ee63f08c9c --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/CallGraphAnalysisUI.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * 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; + +import java.util.Collections; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.CallGraphAnalysis; +import org.eclipse.tracecompass.tmf.core.segment.ISegmentAspect; + +/** + * CallGraph Analysis with aspects + * + * @author Sonia Farrah + */ +public class CallGraphAnalysisUI extends CallGraphAnalysis { + + /** + * ID + */ + public static final @NonNull String ID = "org.eclipse.tracecompass.internal.analysis.timing.ui.callgraph.callgraphanalysis"; //$NON-NLS-1$ + + /** + * Default constructor + */ + public CallGraphAnalysisUI() { + super(); + } + + @Override + public @NonNull Iterable<@NonNull ISegmentAspect> getSegmentAspects() { + return Collections.singletonList(SymbolAspect.SYMBOL_ASPECT); + } +} diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/CallGraphDensityView.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/CallGraphDensityView.java new file mode 100644 index 0000000000..83b6059c76 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/CallGraphDensityView.java @@ -0,0 +1,55 @@ +/****************************************************************************** + * 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; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density.AbstractSegmentStoreDensityView; +import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density.AbstractSegmentStoreDensityViewer; +import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.table.AbstractSegmentStoreTableViewer; +import org.eclipse.tracecompass.common.core.NonNullUtils; + +/** + * Call stack Density view displaying the call stack segments tree. + * + * @author Sonia Farrah + */ +public class CallGraphDensityView extends AbstractSegmentStoreDensityView { + + /** The view's ID */ + public static final @NonNull String ID = CallGraphDensityView.class.getPackage().getName() + ".callgraphkDensity"; //$NON-NLS-1$ + + /** + * Constructs a new density view. + */ + public CallGraphDensityView() { + super(ID); + } + + @Override + protected AbstractSegmentStoreTableViewer createSegmentStoreTableViewer(Composite parent) { + return new CallGraphTableViewer(new TableViewer(parent, SWT.FULL_SELECTION | SWT.VIRTUAL)) { + @Override + protected void createProviderColumns() { + super.createProviderColumns(); + Table t = (Table) getControl(); + t.setColumnOrder(new int[] { 2, 3, 0, 1 }); + } + }; + } + + @Override + protected AbstractSegmentStoreDensityViewer createSegmentStoreDensityViewer(Composite parent) { + return new CallGraphDensityViewer(NonNullUtils.checkNotNull(parent)); + } +} \ 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/CallGraphDensityViewer.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/CallGraphDensityViewer.java new file mode 100644 index 0000000000..319e18de2f --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/CallGraphDensityViewer.java @@ -0,0 +1,42 @@ +/****************************************************************************** + * 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; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider; +import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density.AbstractSegmentStoreDensityViewer; +import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.CallGraphAnalysis; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; + +/** + * Call stack segments density viewer + * + * @author Sonia Farrah + */ +public class CallGraphDensityViewer extends AbstractSegmentStoreDensityViewer { + + /** + * Constructs a new density viewer. + * + * @param parent + * the parent of the viewer + */ + public CallGraphDensityViewer(@NonNull Composite parent) { + super(parent); + } + + @Override + protected @Nullable ISegmentStoreProvider getSegmentStoreProvider(@NonNull ITmfTrace trace) { + return TmfTraceUtils.getAnalysisModuleOfClass(trace, CallGraphAnalysis.class, CallGraphAnalysisUI.ID); + } +} \ 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/CallGraphTableViewer.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/CallGraphTableViewer.java new file mode 100644 index 0000000000..e45322ea4d --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/CallGraphTableViewer.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * 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; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider; +import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.table.AbstractSegmentStoreTableViewer; +import org.eclipse.tracecompass.common.core.NonNullUtils; +import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.CallGraphAnalysis; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; + +/** + * Displays the Call Stack data in a column table + * + * @author Sonia Farrah + */ +public class CallGraphTableViewer extends AbstractSegmentStoreTableViewer { + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructor + * + * @param tableViewer + * The table viewer + */ + public CallGraphTableViewer(@NonNull TableViewer tableViewer) { + super(tableViewer); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + @Override + protected @Nullable ISegmentStoreProvider getSegmentStoreProvider(@NonNull ITmfTrace trace) { + CallGraphAnalysis fModule = TmfTraceUtils.getAnalysisModuleOfClass(trace, CallGraphAnalysis.class, CallGraphAnalysisUI.ID); + if (fModule == null) { + return null; + } + fModule.schedule(); + Job job = new Job(Messages.CallGraphAnalysis) { + + @Override + protected IStatus run(IProgressMonitor monitor) { + fModule.waitForCompletion(NonNullUtils.checkNotNull(monitor)); + if (monitor.isCanceled()) { + return Status.CANCEL_STATUS; + } + return Status.OK_STATUS; + } + }; + job.schedule(); + return fModule; + } +} \ 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/Messages.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/Messages.java new file mode 100644 index 0000000000..af2f106823 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/Messages.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * 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; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.osgi.util.NLS; + +/** + * Message bundle for the call stack views + * + * @author Sonia Farrah + */ +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.tracecompass.internal.analysis.timing.ui.callgraph.messages"; //$NON-NLS-1$ + /** + * Name of the job executing the callGraphAnalysis + */ + public static @Nullable String CallGraphAnalysis; + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/SymbolAspect.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/SymbolAspect.java new file mode 100644 index 0000000000..4bd8624d9e --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/SymbolAspect.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * 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; + +import java.util.Comparator; + +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.CalledFunction; +import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.Messages; +import org.eclipse.tracecompass.segmentstore.core.ISegment; +import org.eclipse.tracecompass.tmf.core.segment.ISegmentAspect; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; +import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProvider; +import org.eclipse.tracecompass.tmf.ui.symbols.SymbolProviderManager; + +/** + * An aspect used to get the function name of a call stack event or to compare + * the duration of two events + * + * @author Sonia Farrah + */ +public final class SymbolAspect implements ISegmentAspect { + /** + * A symbol aspect + */ + public static final @NonNull ISegmentAspect SYMBOL_ASPECT = new SymbolAspect(); + + /** + * Constructor + */ + public SymbolAspect() { + } + + @Override + public @NonNull String getName() { + return NonNullUtils.nullToEmptyString(Messages.CallStack_FunctionName); + } + + @Override + public @NonNull String getHelpText() { + return NonNullUtils.nullToEmptyString(Messages.CallStack_FunctionName); + } + + @Override + public @Nullable Comparator getComparator() { + return new Comparator() { + @Override + public int compare(@Nullable CalledFunction o1, @Nullable CalledFunction o2) { + if (o1 == null || o2 == null) { + throw new IllegalArgumentException(); + } + return Long.compare(o1.getLength(), o2.getLength()); + } + }; + } + + @Override + public @Nullable Object resolve(@NonNull ISegment segment) { + if (segment instanceof CalledFunction) { + CalledFunction calledFunction = (CalledFunction) segment; + ITmfTrace trace = TmfTraceManager.getInstance().getActiveTrace(); + if (trace != null) { + ISymbolProvider provider = SymbolProviderManager.getInstance().getSymbolProvider(trace); + String symbolText = provider.getSymbolText(calledFunction.getAddr()); + return symbolText == null ? "0x" + calledFunction.getAddr() : symbolText; //$NON-NLS-1$ + } + } + return null; + } +} \ 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/messages.properties b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/messages.properties new file mode 100644 index 0000000000..ca33c0405f --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/callgraph/messages.properties @@ -0,0 +1,9 @@ +############################################################################### +# 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 +############################################################################### +CallGraphAnalysis=CallGraph analysis diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/synchronization/SyncAlgorithmFullyIncremental.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/synchronization/SyncAlgorithmFullyIncremental.java index 2203f2b4ca..ca66e4e37c 100644 --- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/synchronization/SyncAlgorithmFullyIncremental.java +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/synchronization/SyncAlgorithmFullyIncremental.java @@ -492,8 +492,8 @@ public class SyncAlgorithmFullyIncremental extends SynchronizationAlgorithm { break; } - fStats.put(Messages.SyncAlgorithmFullyIncremental_refhost, fReferenceHostName + " (" + fReferenceHost + ")"); - fStats.put(Messages.SyncAlgorithmFullyIncremental_otherhost, fOtherHostName + " (" + fOtherHost + ")"); + fStats.put(Messages.SyncAlgorithmFullyIncremental_refhost, fReferenceHostName + " (" + fReferenceHost + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + fStats.put(Messages.SyncAlgorithmFullyIncremental_otherhost, fOtherHostName + " (" + fOtherHost + ")"); //$NON-NLS-1$ //$NON-NLS-2$ fStats.put(Messages.SyncAlgorithmFullyIncremental_quality, syncQuality); fStats.put(Messages.SyncAlgorithmFullyIncremental_alpha, fAlpha); fStats.put(Messages.SyncAlgorithmFullyIncremental_beta, fBeta); @@ -533,12 +533,11 @@ public class SyncAlgorithmFullyIncremental extends SynchronizationAlgorithm { fStats = new LinkedHashMap<>(); } - @SuppressWarnings("nls") @Override public String toString() { StringBuilder b = new StringBuilder(); - b.append("Between " + fReferenceHost + " and " + fOtherHost + " ["); - b.append(" alpha " + fAlpha + " beta " + fBeta + " ]"); + b.append("Between " + fReferenceHost + " and " + fOtherHost + " ["); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + b.append(" alpha " + fAlpha + " beta " + fBeta + " ]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ return b.toString(); } -- 2.34.1