/*******************************************************************************
- * Copyright (c) 2013, 2015 Ericsson
+ * Copyright (c) 2013, 2016 Ericsson and others.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
package org.eclipse.tracecompass.tmf.ui.views.callstack;
-import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.function.Consumer;
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.action.Action;
+import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
-import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.FileDialog;
-import org.eclipse.swt.widgets.Menu;
-import org.eclipse.swt.widgets.Tree;
-import org.eclipse.tracecompass.internal.tmf.core.callstack.FunctionNameMapper;
import org.eclipse.tracecompass.internal.tmf.ui.Activator;
import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
import org.eclipse.tracecompass.internal.tmf.ui.Messages;
import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue.Type;
import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
-import org.eclipse.tracecompass.tmf.core.timestamp.TmfNanoTimestamp;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampDelta;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
import org.eclipse.tracecompass.tmf.ui.editors.ITmfTraceEditor;
+import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProvider;
+import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProviderPreferencePage;
+import org.eclipse.tracecompass.tmf.ui.symbols.SymbolProviderConfigDialog;
+import org.eclipse.tracecompass.tmf.ui.symbols.SymbolProviderManager;
import org.eclipse.tracecompass.tmf.ui.views.timegraph.AbstractTimeGraphView;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphContentProvider;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphSelection;
import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchActionConstants;
/**
* Main implementation for the Call Stack view
// Fraction of a function duration to be added as spacing
private static final double SPACING_RATIO = 0.01;
+ private static final Image PROCESS_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/process_obj.gif"); //$NON-NLS-1$
private static final Image THREAD_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/thread_obj.gif"); //$NON-NLS-1$
private static final Image STACKFRAME_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/stckframe_obj.gif"); //$NON-NLS-1$
- private static final String IMPORT_MAPPING_ICON_PATH = "icons/etool16/import.gif"; //$NON-NLS-1$
private static final String IMPORT_BINARY_ICON_PATH = "icons/obj16/binaries_obj.gif"; //$NON-NLS-1$
private static final ImageDescriptor SORT_BY_NAME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha.gif"); //$NON-NLS-1$
// Fields
// ------------------------------------------------------------------------
- /** The map to map function addresses to function names */
- private Map<String, String> fNameMapping;
+ private final Map<ITmfTrace, ISymbolProvider> fSymbolProviders = new HashMap<>();
// The next event action
private Action fNextEventAction;
// The previous item action
private Action fPreviousItemAction;
- // The action to import a function-name mapping file
- private Action fImportMappingAction;
-
// The action to import a binary file mapping */
- private Action fImportBinaryFileMappingAction;
+ private Action fConfigureSymbolsAction;
// The saved time sync. signal used when switching off the pinning of a view
private TmfSelectionRangeUpdatedSignal fSavedTimeSyncSignal;
// a view
private TmfWindowRangeUpdatedSignal fSavedRangeSyncSignal;
+ // When set to true, syncToTime() will select the first call stack entry
+ // whose current state start time exactly matches the sync time.
+ private boolean fSyncSelection = false;
+
// ------------------------------------------------------------------------
// Classes
// ------------------------------------------------------------------------
}
}
+ private static class ProcessEntry extends TimeGraphEntry {
+
+ private final int fProcessId;
+
+ public ProcessEntry(String name, int processId, long startTime, long endTime) {
+ super(name, startTime, endTime);
+ fProcessId = processId;
+ }
+
+ @Override
+ public boolean hasTimeEvents() {
+ return false;
+ }
+ }
+
private static class ThreadEntry extends TimeGraphEntry {
- // The call stack quark
- private final int fCallStackQuark;
- // The state system from which this entry comes
- private final ITmfStateSystem fSS;
// The thread id
private final long fThreadId;
- public ThreadEntry(ITmfStateSystem ss, String name, long threadId, int callStackQuark, long startTime, long endTime) {
+ public ThreadEntry(String name, long threadId, long startTime, long endTime) {
super(name, startTime, endTime);
- fCallStackQuark = callStackQuark;
fThreadId = threadId;
- fSS = ss;
}
@Override
return false;
}
- public int getCallStackQuark() {
- return fCallStackQuark;
- }
-
public long getThreadId() {
return fThreadId;
}
-
- @Nullable
- public ITmfStateSystem getStateSystem() {
- return fSS;
- }
}
private class CallStackComparator implements Comparator<ITimeGraphEntry> {
public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
if (o1 instanceof ThreadEntry && o2 instanceof ThreadEntry) {
return fThreadComparator.compare(o1, o2);
+ } else if (o1 instanceof ProcessEntry && o2 instanceof ProcessEntry) {
+ return Integer.compare(((ProcessEntry) o1).fProcessId, ((ProcessEntry) o2).fProcessId);
}
return 0;
}
@Override
public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
- ThreadEntry t1 = (ThreadEntry) o1;
- ThreadEntry t2 = (ThreadEntry) o2;
- return reverse ? Long.compare(t2.getThreadId(), t1.getThreadId()) :
+ if (o1 instanceof ThreadEntry && o2 instanceof ThreadEntry) {
+ ThreadEntry t1 = (ThreadEntry) o1;
+ ThreadEntry t2 = (ThreadEntry) o2;
+ return reverse ? Long.compare(t2.getThreadId(), t1.getThreadId()) :
Long.compare(t1.getThreadId(), t2.getThreadId());
+ }
+ return 0;
}
}
@Override
public Image getColumnImage(Object element, int columnIndex) {
if (columnIndex == 0) {
- if (element instanceof ThreadEntry) {
+ if (element instanceof ProcessEntry) {
+ return PROCESS_IMAGE;
+ } else if (element instanceof ThreadEntry) {
return THREAD_IMAGE;
} else if (element instanceof CallStackEntry) {
CallStackEntry entry = (CallStackEntry) element;
int depth = entry.getStackLevel();
return Integer.toString(depth);
} else if (columnIndex == 2 && entry.getFunctionName().length() > 0) {
- ITmfTimestamp ts = new TmfTimestamp(entry.getFunctionEntryTime(), ITmfTimestamp.NANOSECOND_SCALE);
+ ITmfTimestamp ts = TmfTimestamp.fromNanos(entry.getFunctionEntryTime());
return ts.toString();
} else if (columnIndex == 3 && entry.getFunctionName().length() > 0) {
- ITmfTimestamp ts = new TmfTimestamp(entry.getFunctionExitTime(), ITmfTimestamp.NANOSECOND_SCALE);
+ ITmfTimestamp ts = TmfTimestamp.fromNanos(entry.getFunctionExitTime());
return ts.toString();
} else if (columnIndex == 4 && entry.getFunctionName().length() > 0) {
ITmfTimestamp ts = new TmfTimestampDelta(entry.getFunctionExitTime() - entry.getFunctionEntryTime(), ITmfTimestamp.NANOSECOND_SCALE);
long spacingTime = (long) ((exitTime - entryTime) * SPACING_RATIO);
entryTime -= spacingTime;
exitTime += spacingTime;
- TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(entryTime), new TmfNanoTimestamp(exitTime));
+ TmfTimeRange range = new TmfTimeRange(TmfTimestamp.fromNanos(entryTime), TmfTimestamp.fromNanos(exitTime));
broadcast(new TmfWindowRangeUpdatedSignal(CallStackView.this, range));
getTimeGraphViewer().setStartFinishTime(entryTime, exitTime);
startZoomThread(entryTime, exitTime);
long spacingTime = (long) ((endTime - startTime) * SPACING_RATIO);
startTime -= spacingTime;
endTime += spacingTime;
- TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(startTime), new TmfNanoTimestamp(endTime));
+ TmfTimeRange range = new TmfTimeRange(TmfTimestamp.fromNanos(startTime), TmfTimestamp.fromNanos(endTime));
broadcast(new TmfWindowRangeUpdatedSignal(CallStackView.this, range));
getTimeGraphViewer().setStartFinishTime(startTime, endTime);
startZoomThread(startTime, endTime);
});
contributeToActionBars();
- createContextMenu();
loadSortOption();
IEditorPart editor = getSite().getPage().getActiveEditor();
if (signal.getSource() == this || getTrace() == null || isPinned()) {
return;
}
- final long beginTime = signal.getBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
- final long endTime = signal.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ final long beginTime = signal.getBeginTime().toNanos();
+ final long endTime = signal.getEndTime().toNanos();
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
} else {
getTimeGraphViewer().setSelectionRange(beginTime, endTime, true);
}
+ fSyncSelection = true;
synchingToTime(beginTime);
+ fSyncSelection = false;
startZoomThread(getTimeGraphViewer().getTime0(), getTimeGraphViewer().getTime1());
- List<TimeGraphEntry> entryList = getEntryList(getTrace());
- if (entryList == null) {
- return;
- }
- TimeGraphViewer viewer = getTimeGraphViewer();
- for (TimeGraphEntry traceEntry : entryList) {
- for (ITimeGraphEntry child : traceEntry.getChildren()) {
- ThreadEntry threadEntry = (ThreadEntry) child;
- ITmfStateSystem ss = threadEntry.getStateSystem();
- if (ss == null || beginTime < ss.getStartTime() || beginTime > ss.getCurrentEndTime()) {
- continue;
- }
- try {
- int quark = threadEntry.getCallStackQuark();
- ITmfStateInterval stackInterval = ss.querySingleState(beginTime, quark);
- if (beginTime == stackInterval.getStartTime()) {
- int stackLevel = stackInterval.getStateValue().unboxInt();
- ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
- getTimeGraphCombo().setSelection(selectedEntry);
- viewer.getTimeGraphControl().fireSelectionChanged();
- break;
- }
- } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
- Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
- }
- }
- }
}
});
+
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ @TmfSignalHandler
+ public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal) {
+
+ if (isPinned()) {
+ fSavedRangeSyncSignal = new TmfWindowRangeUpdatedSignal(signal.getSource(), signal.getCurrentRange());
+ fSavedTimeSyncSignal = null;
+ }
+
+ if ((signal.getSource() == this) || isPinned()) {
+ return;
+ }
+ super.windowRangeUpdated(signal);
}
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
@Override
- protected void buildEventList(final ITmfTrace trace, final ITmfTrace parentTrace, final IProgressMonitor monitor) {
+ @TmfSignalHandler
+ public void traceClosed(TmfTraceClosedSignal signal) {
+ super.traceClosed(signal);
+ synchronized(fSymbolProviders){
+ for(ITmfTrace trace : getTracesToBuild(signal.getTrace())){
+ fSymbolProviders.remove(trace);
+ }
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ protected void refresh() {
+ super.refresh();
+ updateConfigureSymbolsAction();
+ }
+
+ @Override
+ protected void buildEntryList(final ITmfTrace trace, final ITmfTrace parentTrace, final IProgressMonitor monitor) {
if (monitor.isCanceled()) {
return;
}
+
+ /*
+ * Load the symbol provider for the current trace, even if it does not
+ * provide a call stack analysis module. See
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=494212
+ */
+ ISymbolProvider provider = fSymbolProviders.get(trace);
+ if (provider == null) {
+ provider = SymbolProviderManager.getInstance().getSymbolProvider(trace);
+ provider.loadConfiguration(null);
+ fSymbolProviders.put(trace, provider);
+ }
+
+ /* Continue with the call stack view specific operations */
AbstractCallStackAnalysis module = getCallStackModule(trace);
if (module == null) {
addUnavailableEntry(trace, parentTrace);
}
Map<ITmfTrace, TraceEntry> traceEntryMap = new HashMap<>();
+ Map<Integer, ProcessEntry> processEntryMap = new HashMap<>();
Map<Integer, ThreadEntry> threadEntryMap = new HashMap<>();
- String[] threadPaths = module.getThreadsPattern();
long start = ss.getStartTime();
if (start == end && !complete) { // when complete execute one last time regardless of end time
continue;
}
- List<Integer> threadQuarks = ss.getQuarks(threadPaths);
+
TraceEntry traceEntry = traceEntryMap.get(trace);
if (traceEntry == null) {
traceEntry = new TraceEntry(trace.getName(), start, end + 1);
} else {
traceEntry.updateEndTime(end);
}
- for (int i = 0; i < threadQuarks.size(); i++) {
- if (monitor.isCanceled()) {
- return;
- }
- int threadQuark = threadQuarks.get(i);
- try {
- String[] callStackPath = module.getCallStackPath();
- int callStackQuark = ss.getQuarkRelative(threadQuark, callStackPath);
- String threadName = ss.getAttributeName(threadQuark);
- long threadEnd = end + 1;
- ITmfStateInterval endInterval = ss.querySingleState(ss.getCurrentEndTime(), callStackQuark);
- if (endInterval.getStateValue().isNull() && endInterval.getStartTime() != ss.getStartTime()) {
- threadEnd = endInterval.getStartTime();
- }
- ThreadEntry threadEntry = threadEntryMap.get(threadQuark);
- if (threadEntry == null) {
- long threadId = ss.querySingleState(ss.getCurrentEndTime(), threadQuark).getStateValue().unboxLong();
- long threadStart = start;
- ITmfStateInterval startInterval = ss.querySingleState(start, callStackQuark);
- if (startInterval.getStateValue().isNull()) {
- threadStart = Math.min(startInterval.getEndTime() + 1, end + 1);
+
+ try {
+ List<ITmfStateInterval> endStates = ss.queryFullState(ss.getCurrentEndTime());
+
+ List<Integer> processQuarks = ss.getQuarks(module.getProcessesPattern());
+ for (int processQuark : processQuarks) {
+
+ /*
+ * Default to trace entry, overwrite if a process entry exists.
+ */
+ TimeGraphEntry threadParent = traceEntry;
+ int processId = -1;
+ if (processQuark != ITmfStateSystem.ROOT_ATTRIBUTE) {
+ /* Create the entry for the process */
+ ProcessEntry processEntry = processEntryMap.get(processQuark);
+ if (processEntry == null) {
+ String processName = ss.getAttributeName(processQuark);
+ ITmfStateValue processStateValue = endStates.get(processQuark).getStateValue();
+ if (processStateValue.getType() == Type.INTEGER) {
+ processId = processStateValue.unboxInt();
+ } else {
+ try {
+ processId = Integer.parseInt(processName);
+ } catch (NumberFormatException e) {
+ /* use default processId */
+ }
+ }
+ processEntry = new ProcessEntry(processName, processId, start, end);
+ processEntryMap.put(processQuark, processEntry);
+ traceEntry.addChild(processEntry);
+ } else {
+ processEntry.updateEndTime(end);
}
- threadEntry = new ThreadEntry(ss, threadName, threadId, callStackQuark, threadStart, threadEnd);
- threadEntryMap.put(threadQuark, threadEntry);
- traceEntry.addChild(threadEntry);
- } else {
- threadEntry.updateEndTime(threadEnd);
+ /* The parent of the thread entries will be a process */
+ threadParent = processEntry;
}
- int level = 1;
- for (int stackLevelQuark : ss.getSubAttributes(callStackQuark, false)) {
- if (level > threadEntry.getChildren().size()) {
- CallStackEntry callStackEntry = new CallStackEntry(threadName, stackLevelQuark, level, trace, ss);
- threadEntry.addChild(callStackEntry);
+
+ /* Create the threads under the process */
+ List<Integer> threadQuarks = ss.getQuarks(processQuark, module.getThreadsPattern());
+
+ /*
+ * Only query startStates if necessary (threadEntry == null)
+ */
+ List<ITmfStateInterval> startStates = null;
+ for (int threadQuark : threadQuarks) {
+ if (monitor.isCanceled()) {
+ return;
+ }
+
+ String[] callStackPath = module.getCallStackPath();
+ int callStackQuark = ss.getQuarkRelative(threadQuark, callStackPath);
+ String threadName = ss.getAttributeName(threadQuark);
+ long threadEnd = end + 1;
+ ITmfStateInterval endInterval = endStates.get(callStackQuark);
+ if (endInterval.getStateValue().isNull() && endInterval.getStartTime() != ss.getStartTime()) {
+ threadEnd = endInterval.getStartTime();
+ }
+ /*
+ * Default to process/trace entry, overwrite if a thread entry exists.
+ */
+ TimeGraphEntry callStackParent = threadParent;
+ if (threadQuark != processQuark) {
+ ThreadEntry threadEntry = threadEntryMap.get(threadQuark);
+ if (threadEntry == null) {
+ if (startStates == null) {
+ startStates = ss.queryFullState(ss.getStartTime());
+ }
+ long threadId = -1;
+ ITmfStateValue threadStateValue = endStates.get(threadQuark).getStateValue();
+ if (threadStateValue.getType() == Type.LONG || threadStateValue.getType() == Type.INTEGER) {
+ threadId = threadStateValue.unboxLong();
+ } else {
+ try {
+ threadId = Long.parseLong(threadName);
+ } catch (NumberFormatException e) {
+ /* use default threadId */
+ }
+ }
+ long threadStart = start;
+ ITmfStateInterval startInterval = startStates.get(callStackQuark);
+ if (startInterval.getStateValue().isNull()) {
+ threadStart = Math.min(startInterval.getEndTime() + 1, end + 1);
+ }
+ threadEntry = new ThreadEntry(threadName, threadId, threadStart, threadEnd);
+ threadEntryMap.put(threadQuark, threadEntry);
+ threadParent.addChild(threadEntry);
+ } else {
+ threadEntry.updateEndTime(threadEnd);
+ }
+ /* The parent of the call stack entries will be a thread */
+ callStackParent = threadEntry;
+ }
+ int level = 1;
+ for (int stackLevelQuark : ss.getSubAttributes(callStackQuark, false)) {
+ if (level > callStackParent.getChildren().size()) {
+ CallStackEntry callStackEntry = new CallStackEntry(threadName, stackLevelQuark, level, processId, trace, ss);
+ callStackParent.addChild(callStackEntry);
+ }
+ level++;
}
- level++;
}
- } catch (AttributeNotFoundException e) {
- Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
- } catch (StateSystemDisposedException e) {
- /* Ignored */
}
+ } catch (AttributeNotFoundException e) {
+ Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
+ } catch (StateSystemDisposedException e) {
+ /* Ignored */
}
+
if (parentTrace == getTrace()) {
synchronized (this) {
setStartTime(getStartTime() == SWT.DEFAULT ? start : Math.min(getStartTime(), start));
synchingToTime(getTimeGraphViewer().getSelectionBegin());
refresh();
}
- for (ITimeGraphEntry threadEntry : traceEntry.getChildren()) {
- for (ITimeGraphEntry callStackEntry : threadEntry.getChildren()) {
+
+ Consumer<TimeGraphEntry> consumer = new Consumer<TimeGraphEntry>() {
+ @Override
+ public void accept(TimeGraphEntry entry) {
if (monitor.isCanceled()) {
return;
}
- buildStatusEvents(parentTrace, (CallStackEntry) callStackEntry, monitor, start, end);
+ if (entry instanceof CallStackEntry) {
+ buildStatusEvents(parentTrace, (CallStackEntry) entry, monitor, ss.getStartTime(), end);
+ return;
+ }
+ entry.getChildren().forEach(this);
}
- }
+ };
+ traceEntry.getChildren().forEach(consumer);
+
start = end;
}
}
long resolution = Math.max(1, (end - ss.getStartTime()) / getDisplayWidth());
List<ITimeEvent> eventList = getEventList(entry, start, end + 1, resolution, monitor);
if (eventList != null) {
- for (ITimeEvent event : eventList) {
- entry.addEvent(event);
- }
+ entry.setEventList(eventList);
}
if (trace == getTrace()) {
redraw();
}
/**
- * @since 2.0
+ * @since 1.2
*/
@Override
protected final List<ITimeEvent> getEventList(TimeGraphEntry tgentry, long startTime, long endTime, long resolution, IProgressMonitor monitor) {
if (end <= start) {
return null;
}
+ boolean isZoomThread = Thread.currentThread() instanceof ZoomThread;
List<ITimeEvent> eventList = null;
try {
List<ITmfStateInterval> stackIntervals = StateSystemUtils.queryHistoryRange(ss, entry.getQuark(), start, end - 1, resolution, monitor);
eventList = new ArrayList<>(stackIntervals.size());
long lastEndTime = -1;
- boolean lastIsNull = true;
+ boolean lastIsNull = false;
for (ITmfStateInterval statusInterval : stackIntervals) {
if (monitor.isCanceled()) {
return null;
eventList.add(new CallStackEvent(entry, time, duration, value));
lastIsNull = false;
} else {
- if (lastEndTime == -1) {
+ if (lastEndTime == -1 && isZoomThread) {
// add null event if it intersects the start time
eventList.add(new NullTimeEvent(entry, time, duration));
} else {
// add unknown event if between two null states
eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime));
}
- if (time + duration >= endTime) {
+ if (time + duration >= endTime && isZoomThread) {
// add null event if it intersects the end time
eventList.add(new NullTimeEvent(entry, time, duration));
}
}
/**
- * @since 2.0
+ * @since 1.2
*/
@Override
- protected void synchingToTime(long time) {
- List<TimeGraphEntry> entryList = getEntryList(getTrace());
- if (entryList == null) {
+ protected void synchingToTime(final long time) {
+ List<TimeGraphEntry> traceEntries = getEntryList(getTrace());
+ Map<ITmfStateSystem, List<ITmfStateInterval>> fullStateMap = new HashMap<>();
+ if (traceEntries == null) {
return;
}
- for (TimeGraphEntry traceEntry : entryList) {
- for (ITimeGraphEntry threadEntry : traceEntry.getChildren()) {
- ITmfStateSystem ss = ((ThreadEntry) threadEntry).getStateSystem();
- if (ss == null) {
- continue;
- }
- if (ss.isCancelled()) {
- continue;
- }
- if (time < ss.getStartTime() || time > ss.getCurrentEndTime()) {
- continue;
- }
- for (ITimeGraphEntry child : threadEntry.getChildren()) {
- CallStackEntry callStackEntry = (CallStackEntry) child;
+ Consumer<TimeGraphEntry> consumer = new Consumer<TimeGraphEntry>() {
+ @Override
+ public void accept(TimeGraphEntry entry) {
+ if (entry instanceof CallStackEntry) {
+ CallStackEntry callStackEntry = (CallStackEntry) entry;
+ ITmfStateSystem ss = callStackEntry.getStateSystem();
+ if (time < ss.getStartTime() || time > ss.getCurrentEndTime()) {
+ return;
+ }
+ ITmfTrace trace = callStackEntry.getTrace();
try {
- ITmfStateInterval stackLevelInterval = ss.querySingleState(time, callStackEntry.getQuark());
+ List<ITmfStateInterval> fullState = getFullState(ss);
+ ITmfStateInterval stackLevelInterval = fullState.get(callStackEntry.getQuark());
ITmfStateValue nameValue = stackLevelInterval.getStateValue();
- String name = ""; //$NON-NLS-1$
- try {
- if (nameValue.getType() == Type.STRING) {
- String address = nameValue.unboxStr();
- name = getFunctionName(address);
- } else if (nameValue.getType() == Type.INTEGER) {
- name = "0x" + Integer.toHexString(nameValue.unboxInt()); //$NON-NLS-1$
- } else if (nameValue.getType() == Type.LONG) {
- name = "0x" + Long.toHexString(nameValue.unboxLong()); //$NON-NLS-1$
- }
- } catch (StateValueTypeException e) {
- }
+
+ String name = getFunctionName(trace, callStackEntry.getProcessId(), time, nameValue);
callStackEntry.setFunctionName(name);
- if (name.length() > 0) {
+ if (!name.isEmpty()) {
callStackEntry.setFunctionEntryTime(stackLevelInterval.getStartTime());
callStackEntry.setFunctionExitTime(stackLevelInterval.getEndTime() + 1);
}
- } catch (AttributeNotFoundException e) {
- Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
+ if (fSyncSelection) {
+ int callStackQuark = ss.getParentAttributeQuark(callStackEntry.getQuark());
+ ITmfStateInterval stackInterval = fullState.get(callStackQuark);
+ if (time == stackInterval.getStartTime()) {
+ ITmfStateValue stackLevelState = stackInterval.getStateValue();
+ if (stackLevelState.unboxInt() == callStackEntry.getStackLevel() || stackLevelState.isNull()) {
+ Display.getDefault().asyncExec(() -> {
+ getTimeGraphCombo().setSelection(callStackEntry);
+ getTimeGraphViewer().getTimeGraphControl().fireSelectionChanged();
+ fSyncSelection = false;
+ });
+ }
+ }
+ }
} catch (StateSystemDisposedException e) {
/* Ignored */
}
+ return;
}
+ entry.getChildren().forEach(this);
}
- }
+
+ private List<ITmfStateInterval> getFullState(ITmfStateSystem ss) throws StateSystemDisposedException {
+ List<ITmfStateInterval> fullState = fullStateMap.get(ss);
+ if (fullState == null) {
+ fullState = ss.queryFullState(time);
+ fullStateMap.put(ss, fullState);
+ }
+ return fullState;
+ }
+ };
+ traceEntries.forEach(consumer);
if (Display.getCurrent() != null) {
getTimeGraphCombo().refresh();
}
}
+ String getFunctionName(ITmfTrace trace, int processId, long timestamp, ITmfStateValue nameValue) {
+ long address = Long.MAX_VALUE;
+ String name = ""; //$NON-NLS-1$
+ try {
+ if (nameValue.getType() == Type.STRING) {
+ name = nameValue.unboxStr();
+ try {
+ address = Long.parseLong(name, 16);
+ } catch (NumberFormatException e) {
+ // ignore
+ }
+ } else if (nameValue.getType() == Type.INTEGER) {
+ name = "0x" + Integer.toUnsignedString(nameValue.unboxInt(), 16); //$NON-NLS-1$
+ address = nameValue.unboxInt();
+ } else if (nameValue.getType() == Type.LONG) {
+ name = "0x" + Long.toUnsignedString(nameValue.unboxLong(), 16); //$NON-NLS-1$
+ address = nameValue.unboxLong();
+ }
+ } catch (StateValueTypeException e) {
+ }
+ if (address != Long.MAX_VALUE) {
+ ISymbolProvider provider = fSymbolProviders.get(trace);
+ if (provider != null) {
+ String symbol = provider.getSymbolText(processId, timestamp, address);
+ if (symbol != null) {
+ name = symbol;
+ }
+ }
+ }
+ return name;
+ }
+
private void makeActions() {
fPreviousItemAction = getTimeGraphViewer().getPreviousItemAction();
fPreviousItemAction.setText(Messages.TmfTimeGraphViewer_PreviousItemActionNameText);
}
/**
- * @since 2.0
+ * @since 1.2
*/
@Override
protected void fillLocalToolBar(IToolBarManager manager) {
makeActions();
- manager.add(getImportBinaryAction());
- manager.add(getImportMappingAction());
+ manager.add(getConfigureSymbolsAction());
manager.add(new Separator());
manager.add(getSortByNameAction());
manager.add(getSortByIdAction());
manager.add(getTimeGraphViewer().getZoomOutAction());
}
- private void createContextMenu() {
- final MenuManager contextMenu = new MenuManager();
+ /**
+ * @since 2.0
+ */
+ @Override
+ protected void fillTimeGraphEntryContextMenu(IMenuManager contextMenu) {
+ contextMenu.add(new GroupMarker(IWorkbenchActionConstants.GROUP_REORGANIZE));
contextMenu.add(getSortByNameAction());
contextMenu.add(getSortByIdAction());
contextMenu.add(getSortByTimeAction());
-
- Tree tree = getTimeGraphCombo().getTreeViewer().getTree();
- Menu menu = contextMenu.createContextMenu(tree);
- tree.setMenu(menu);
}
/**
viewer.getTimeGraphControl().fireSelectionChanged();
startZoomThread(viewer.getTime0(), viewer.getTime1());
- } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
+ } catch (TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
}
}
}
};
- fNextEventAction.setText(Messages.TmfTimeGraphViewer_NextEventActionNameText);
- fNextEventAction.setToolTipText(Messages.TmfTimeGraphViewer_NextEventActionToolTipText);
- fNextEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_EVENT));
+ fNextEventAction.setText(Messages.TmfTimeGraphViewer_NextStateChangeActionNameText);
+ fNextEventAction.setToolTipText(Messages.TmfTimeGraphViewer_NextStateChangeActionToolTipText);
+ fNextEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_STATE_CHANGE));
}
return fNextEventAction;
viewer.getTimeGraphControl().fireSelectionChanged();
startZoomThread(viewer.getTime0(), viewer.getTime1());
- } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
+ } catch (TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
}
}
}
};
- fPrevEventAction.setText(Messages.TmfTimeGraphViewer_PreviousEventActionNameText);
- fPrevEventAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousEventActionToolTipText);
- fPrevEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_EVENT));
+ fPrevEventAction.setText(Messages.TmfTimeGraphViewer_PreviousStateChangeActionNameText);
+ fPrevEventAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousStateChangeActionToolTipText);
+ fPrevEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_STATE_CHANGE));
}
return fPrevEventAction;
AbstractCallStackAnalysis module = it.next();
/* This analysis is not automatic, we need to schedule it on-demand */
module.schedule();
- module.waitForInitialization();
+ if (!module.waitForInitialization()) {
+ /* The initialization did not succeed */
+ return null;
+ }
return module;
}
// Methods related to function name mapping
// ------------------------------------------------------------------------
- /**
- * Common code for all import file mapping actions
- */
- private abstract class AbstractImportFileMappingAction extends Action {
- private final String fDialogTitle;
-
- private AbstractImportFileMappingAction(String dialogTitle) {
- fDialogTitle = dialogTitle;
- }
-
- @Override
- public void run() {
- FileDialog dialog = new FileDialog(getViewSite().getShell());
- dialog.setText(fDialogTitle);
- final String filePath = dialog.open();
- if (filePath == null) {
- /* No file was selected, don't change anything */
- return;
- }
-
- /*
- * Start the mapping import in a separate thread (we do not want to
- * UI thread to do this).
- */
- Job job = new Job(Messages.CallStackView_ImportMappingJobName) {
- @Override
- public IStatus run(IProgressMonitor monitor) {
- fNameMapping = doMapping(new File(filePath));
-
- /* Refresh call stack entries and event labels */
- Display.getDefault().asyncExec(new Runnable() {
- @Override
- public void run() {
- synchingToTime(getTimeGraphViewer().getSelectionBegin());
- }
- });
- return Status.OK_STATUS;
- }
- };
- job.schedule();
- }
-
- abstract Map<String, String> doMapping(File file);
- }
-
- /**
- * Toolbar icon to import the function address-to-name mapping file.
- */
- private Action getImportMappingAction() {
- if (fImportMappingAction != null) {
- return fImportMappingAction;
- }
- fImportMappingAction = new AbstractImportFileMappingAction(Messages.CallStackView_ImportMappingDialogTitle) {
- @Override
- Map<String, String> doMapping(File file) {
- return FunctionNameMapper.mapFromNmTextFile(file);
- }
- };
-
- fImportMappingAction.setText(Messages.CallStackView_ImportMappingButtonText);
- fImportMappingAction.setToolTipText(Messages.CallStackView_ImportMappingButtonTooltip);
- fImportMappingAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(IMPORT_MAPPING_ICON_PATH));
-
- return fImportMappingAction;
- }
-
private Action getSortByNameAction() {
if (fSortByNameAction == null) {
fSortByNameAction = new Action(Messages.CallStackView_SortByThreadName, IAction.AS_CHECK_BOX) {
refresh();
}
- /**
- * Toolbar icon to import the function address-to-name mapping binary file.
- */
- private Action getImportBinaryAction() {
- if (fImportBinaryFileMappingAction != null) {
- return fImportBinaryFileMappingAction;
+ private Action getConfigureSymbolsAction() {
+ if (fConfigureSymbolsAction != null) {
+ return fConfigureSymbolsAction;
}
- fImportBinaryFileMappingAction = new AbstractImportFileMappingAction(Messages.CallStackView_ImportBinaryFileDialogTitle) {
+ fConfigureSymbolsAction = new Action(Messages.CallStackView_ConfigureSymbolProvidersText) {
@Override
- Map<String, String> doMapping(File file) {
- return FunctionNameMapper.mapFromBinaryFile(file);
+ public void run() {
+ SymbolProviderConfigDialog dialog = new SymbolProviderConfigDialog(getSite().getShell(), getProviderPages());
+ if (dialog.open() == IDialogConstants.OK_ID) {
+ refresh();
+ }
}
};
- fImportBinaryFileMappingAction.setText(Messages.CallStackView_ImportBinaryFileButtonText);
- fImportBinaryFileMappingAction.setToolTipText(Messages.CallStackView_ImportBinaryFileButtonTooltip);
- fImportBinaryFileMappingAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(IMPORT_BINARY_ICON_PATH));
+ fConfigureSymbolsAction.setToolTipText(Messages.CallStackView_ConfigureSymbolProvidersTooltip);
+ fConfigureSymbolsAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(IMPORT_BINARY_ICON_PATH));
+
+ /*
+ * The updateConfigureSymbolsAction() method (called by refresh()) will
+ * set the action to true if applicable after the symbol provider has
+ * been properly loaded.
+ */
+ fConfigureSymbolsAction.setEnabled(false);
- return fImportBinaryFileMappingAction;
+ return fConfigureSymbolsAction;
}
- String getFunctionName(String address) {
- if (fNameMapping == null) {
- /* No mapping available, just print the addresses */
- return address;
- }
- String ret = fNameMapping.get(address);
- if (ret == null) {
- /*
- * We didn't find this address in the mapping file, just use the
- * address
- */
- return address;
+ /**
+ * @return an array of {@link ISymbolProviderPreferencePage} that will
+ * configure the current traces
+ */
+ private ISymbolProviderPreferencePage[] getProviderPages() {
+ List<ISymbolProviderPreferencePage> pages = new ArrayList<>();
+ ITmfTrace trace = getTrace();
+ if (trace != null) {
+ for (ITmfTrace subTrace : getTracesToBuild(trace)) {
+ ISymbolProvider provider = fSymbolProviders.get(subTrace);
+ if (provider != null) {
+ ISymbolProviderPreferencePage page = provider.createPreferencePage();
+ if (page != null) {
+ pages.add(page);
+ }
+ }
+ }
}
- return ret;
+ return pages.toArray(new ISymbolProviderPreferencePage[pages.size()]);
+ }
+
+ /**
+ * Update the enable status of the configure symbols action
+ */
+ private void updateConfigureSymbolsAction() {
+ ISymbolProviderPreferencePage[] providerPages = getProviderPages();
+ getConfigureSymbolsAction().setEnabled(providerPages.length > 0);
}
}