/*******************************************************************************
- * Copyright (c) 2013 Ericsson
+ * Copyright (c) 2013, 2014 Ericsson
*
* 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.linuxtools.tmf.ui.views.callstack;
+import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.linuxtools.internal.tmf.ui.Activator;
import org.eclipse.linuxtools.internal.tmf.ui.ITmfImageConstants;
import org.eclipse.linuxtools.internal.tmf.ui.Messages;
+import org.eclipse.linuxtools.statesystem.core.ITmfStateSystem;
+import org.eclipse.linuxtools.statesystem.core.exceptions.AttributeNotFoundException;
+import org.eclipse.linuxtools.statesystem.core.exceptions.StateSystemDisposedException;
+import org.eclipse.linuxtools.statesystem.core.exceptions.StateValueTypeException;
+import org.eclipse.linuxtools.statesystem.core.exceptions.TimeRangeException;
+import org.eclipse.linuxtools.statesystem.core.interval.ITmfStateInterval;
+import org.eclipse.linuxtools.statesystem.core.statevalue.ITmfStateValue;
+import org.eclipse.linuxtools.statesystem.core.statevalue.ITmfStateValue.Type;
import org.eclipse.linuxtools.tmf.core.callstack.CallStackStateProvider;
-import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
-import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException;
-import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
-import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
-import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal;
import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;
import org.eclipse.linuxtools.tmf.core.signal.TmfTraceClosedSignal;
import org.eclipse.linuxtools.tmf.core.signal.TmfTraceOpenedSignal;
import org.eclipse.linuxtools.tmf.core.signal.TmfTraceSelectedSignal;
-import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
-import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
-import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue.Type;
import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
import org.eclipse.linuxtools.tmf.core.timestamp.TmfNanoTimestamp;
import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestampDelta;
import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
-import org.eclipse.linuxtools.tmf.core.trace.TmfExperiment;
+import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
import org.eclipse.linuxtools.tmf.ui.editors.ITmfTraceEditor;
import org.eclipse.linuxtools.tmf.ui.views.TmfView;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphRangeListener;
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.ui.IActionBars;
import org.eclipse.ui.IEditorPart;
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$
+
// ------------------------------------------------------------------------
// Fields
// ------------------------------------------------------------------------
private ITmfTrace fTrace;
// The selected thread map
- private final Map<ITmfTrace, String> fSelectedThreadMap = new HashMap<ITmfTrace, String>();
+ private final Map<ITmfTrace, String> fSelectedThreadMap = new HashMap<>();
// The time graph entry list
private List<ThreadEntry> fEntryList;
// The trace to entry list hash map
- private final Map<ITmfTrace, ArrayList<ThreadEntry>> fEntryListMap = new HashMap<ITmfTrace, ArrayList<ThreadEntry>>();
+ private final Map<ITmfTrace, ArrayList<ThreadEntry>> fEntryListMap = new HashMap<>();
// The trace to build thread hash map
- private final Map<ITmfTrace, BuildThread> fBuildThreadMap = new HashMap<ITmfTrace, BuildThread>();
+ private final Map<ITmfTrace, BuildThread> fBuildThreadMap = new HashMap<>();
+
+ /** The map to map function addresses to function names */
+ private Map<String, String> fNameMapping;
// The start time
private long fStartTime;
// The previous item action
private Action fPreviousItemAction;
+ /** The action to import a function-name mapping file */
+ private Action fImportMappingAction;
+
// The zoom thread
private ZoomThread fZoomThread;
// ------------------------------------------------------------------------
private class ThreadEntry implements ITimeGraphEntry {
- // The Trace
- private final ITmfTrace fThreadTrace;
// The start time
private final long fTraceStartTime;
// The end time
private final String fName;
// The thread attribute quark
private final int fThreadQuark;
+ // The state system from which this entry comes
+ private final ITmfStateSystem fSS;
public ThreadEntry(ITmfTrace trace, String name, int threadQuark, long startTime, long endTime) {
- fThreadTrace = trace;
- fChildren = new ArrayList<CallStackEntry>();
+ fChildren = new ArrayList<>();
fName = name;
fTraceStartTime = startTime;
fTraceEndTime = endTime;
fThreadQuark = threadQuark;
+
+ fSS = getCallStackStateSystem(trace);
}
@Override
@Override
public boolean hasChildren() {
if (fChildren == null) {
- ITmfStateSystem ss = fThreadTrace.getStateSystems().get(CallStackStateProvider.ID);
+ ITmfStateSystem ss = getStateSystem();
+ if (ss == null) {
+ return false;
+ }
try {
int eventStackQuark = ss.getQuarkRelative(fThreadQuark, CallStackStateProvider.CALL_STACK);
ITmfStateInterval eventStackInterval = ss.querySingleState(ss.getStartTime(), eventStackQuark);
return fThreadQuark;
}
- public ITmfTrace getTrace() {
- return fThreadTrace;
+ @Nullable
+ public ITmfStateSystem getStateSystem() {
+ return fSS;
}
public void addChild(CallStackEntry entry) {
}
long resolution = Math.max(1, (fZoomEndTime - fZoomStartTime) / fDisplayWidth);
for (ThreadEntry threadEntry : fZoomEntryList) {
- ITmfStateSystem ss = threadEntry.fThreadTrace.getStateSystems().get(CallStackStateProvider.ID);
- if (ss == null || !ss.waitUntilBuilt()) {
+ ITmfStateSystem ss = threadEntry.getStateSystem();
+ if (ss == null) {
+ continue;
+ }
+ ss.waitUntilBuilt();
+ if (ss.isCancelled()) {
continue;
}
for (ITimeGraphEntry child : threadEntry.getChildren()) {
fTimeGraphCombo.getTreeViewer().getTree().getColumn(3).setWidth(COLUMN_WIDTHS[3]);
fTimeGraphCombo.getTreeViewer().getTree().getColumn(4).setWidth(COLUMN_WIDTHS[4]);
- fTimeGraphCombo.setTimeGraphProvider(new CallStackPresentationProvider());
+ fTimeGraphCombo.setTimeGraphProvider(new CallStackPresentationProvider(this));
fTimeGraphCombo.getTimeGraphViewer().setTimeFormat(TimeFormat.CALENDAR);
fTimeGraphCombo.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
}
TimeGraphViewer viewer = fTimeGraphCombo.getTimeGraphViewer();
for (ThreadEntry threadEntry : fEntryList) {
- ITmfStateSystem ss = threadEntry.getTrace().getStateSystems().get(CallStackStateProvider.ID);
+ ITmfStateSystem ss = threadEntry.getStateSystem();
if (ss == null || beginTime < ss.getStartTime() || beginTime > ss.getCurrentEndTime()) {
continue;
}
// ------------------------------------------------------------------------
// Internal
// ------------------------------------------------------------------------
+
private void loadTrace() {
synchronized (fEntryListMap) {
fEntryList = fEntryListMap.get(fTrace);
private void buildThreadList(final ITmfTrace trace, IProgressMonitor monitor) {
fStartTime = Long.MAX_VALUE;
fEndTime = Long.MIN_VALUE;
- ITmfTrace[] traces;
- if (trace instanceof TmfExperiment) {
- TmfExperiment experiment = (TmfExperiment) trace;
- traces = experiment.getTraces();
- } else {
- traces = new ITmfTrace[] { trace };
- }
- ArrayList<ThreadEntry> entryList = new ArrayList<ThreadEntry>();
+ ITmfTrace[] traces = TmfTraceManager.getTraceSet(trace);
+ ArrayList<ThreadEntry> entryList = new ArrayList<>();
for (ITmfTrace aTrace : traces) {
if (monitor.isCanceled()) {
return;
}
- ITmfStateSystem ss = aTrace.getStateSystems().get(CallStackStateProvider.ID);
- if (ss == null || !ss.waitUntilBuilt()) {
- String threadName = Messages.CallStackView_StackInfoNotAvailable + ' ' + '(' + aTrace.getName() + ')';
- ThreadEntry threadEntry = new ThreadEntry(aTrace, threadName, -1, 0, 0);
- entryList.add(threadEntry);
+ ITmfStateSystem ss = getCallStackStateSystem(aTrace);
+ if (ss == null) {
+ addUnavailableEntry(aTrace, entryList);
+ continue;
+ }
+ ss.waitUntilBuilt();
+ if (ss.isCancelled()) {
+ addUnavailableEntry(aTrace, entryList);
continue;
}
long startTime = ss.getStartTime();
}
}
synchronized (fEntryListMap) {
- fEntryListMap.put(trace, new ArrayList<ThreadEntry>(entryList));
+ fEntryListMap.put(trace, new ArrayList<>(entryList));
}
if (trace == fTrace) {
refresh();
}
}
+ private void addUnavailableEntry(ITmfTrace trace, List<ThreadEntry> list) {
+ String threadName = Messages.CallStackView_StackInfoNotAvailable + ' ' + '(' + trace.getName() + ')';
+ ThreadEntry threadEntry = new ThreadEntry(trace, threadName, -1, 0, 0);
+ list.add(threadEntry);
+ }
+
private void buildStatusEvents(ITmfTrace trace, CallStackEntry entry, IProgressMonitor monitor) {
- ITmfStateSystem ss = entry.getTrace().getStateSystems().get(CallStackStateProvider.ID);
+ ITmfStateSystem ss = getCallStackStateSystem(entry.getTrace());
+ if (ss == null) {
+ return;
+ }
long start = ss.getStartTime();
long end = ss.getCurrentEndTime() + 1;
long resolution = Math.max(1, (end - start) / fDisplayWidth);
private static List<ITimeEvent> getEventList(CallStackEntry entry,
long startTime, long endTime, long resolution,
IProgressMonitor monitor) {
- ITmfStateSystem ss = entry.getTrace().getStateSystems().get(CallStackStateProvider.ID);
+ ITmfStateSystem ss = getCallStackStateSystem(entry.getTrace());
+ if (ss == null) {
+ return null;
+ }
long start = Math.max(startTime, ss.getStartTime());
long end = Math.min(endTime, ss.getCurrentEndTime() + 1);
if (end <= start) {
List<ITimeEvent> eventList = null;
try {
List<ITmfStateInterval> stackIntervals = ss.queryHistoryRange(entry.getQuark(), start, end - 1, resolution, monitor);
- eventList = new ArrayList<ITimeEvent>(stackIntervals.size());
+ eventList = new ArrayList<>(stackIntervals.size());
long lastEndTime = -1;
boolean lastIsNull = true;
for (ITmfStateInterval statusInterval : stackIntervals) {
return;
}
for (ThreadEntry threadEntry : fEntryList) {
- ITmfStateSystem ss = threadEntry.fThreadTrace.getStateSystems().get(CallStackStateProvider.ID);
- if (ss == null || !ss.waitUntilBuilt()) {
+ ITmfStateSystem ss = threadEntry.getStateSystem();
+ if (ss == null) {
+ continue;
+ }
+ ss.waitUntilBuilt();
+ if (ss.isCancelled()) {
continue;
}
long queryTime = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), time));
String name = ""; //$NON-NLS-1$
try {
if (nameValue.getType() == Type.STRING) {
- name = nameValue.unboxStr();
+ 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) {
synchronized (fEntryListMap) {
fEntryList = fEntryListMap.get(fTrace);
if (fEntryList == null) {
- fEntryList = new ArrayList<ThreadEntry>();
+ fEntryList = new ArrayList<>();
}
entries = fEntryList.toArray(new ITimeGraphEntry[0]);
}
}
private void fillLocalToolBar(IToolBarManager manager) {
+ manager.add(getImportMappingAction());
manager.add(fTimeGraphCombo.getTimeGraphViewer().getResetScaleAction());
manager.add(getPreviousEventAction());
manager.add(getNextEventAction());
try {
CallStackEntry callStackEntry = (CallStackEntry) entry;
ITmfTrace trace = callStackEntry.getTrace();
- ITmfStateSystem ss = trace.getStateSystems().get(CallStackStateProvider.ID);
+ ITmfStateSystem ss = getCallStackStateSystem(trace);
+ if (ss == null) {
+ return;
+ }
long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectionBegin()));
ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
int quark = ss.getQuarkRelative(threadEntry.getThreadQuark(), CallStackStateProvider.CALL_STACK);
fTimeGraphCombo.setSelection(selectedEntry);
viewer.getTimeGraphControl().fireSelectionChanged();
startZoomThread(viewer.getTime0(), viewer.getTime1());
+
} catch (AttributeNotFoundException e) {
Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
} catch (TimeRangeException e) {
try {
CallStackEntry callStackEntry = (CallStackEntry) entry;
ITmfTrace trace = callStackEntry.getTrace();
- ITmfStateSystem ss = trace.getStateSystems().get(CallStackStateProvider.ID);
+ ITmfStateSystem ss = getCallStackStateSystem(trace);
+ if (ss == null) {
+ return;
+ }
long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectionBegin()));
ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
int quark = ss.getQuarkRelative(threadEntry.getThreadQuark(), CallStackStateProvider.CALL_STACK);
fTimeGraphCombo.setSelection(selectedEntry);
viewer.getTimeGraphControl().fireSelectionChanged();
startZoomThread(viewer.getTime0(), viewer.getTime1());
+
} catch (AttributeNotFoundException e) {
Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
} catch (TimeRangeException e) {
return fPrevEventAction;
}
+ @Nullable
+ static ITmfStateSystem getCallStackStateSystem(ITmfTrace trace) {
+ /*
+ * Since we cannot know the exact analysis ID (in separate plugins), we
+ * will search using the analysis type.
+ */
+ Iterable<AbstractCallStackAnalysis> modules =
+ trace.getAnalysisModulesOfClass(AbstractCallStackAnalysis.class);
+ Iterator<AbstractCallStackAnalysis> it = modules.iterator();
+ if (!it.hasNext()) {
+ /* This trace does not provide a call-stack analysis */
+ return null;
+ }
+
+ /*
+ * We only look at the first module we find.
+ *
+ * TODO Handle the advanced case where one trace provides more than one
+ * call-stack analysis.
+ */
+ AbstractCallStackAnalysis module = it.next();
+ /* This analysis is not automatic, we need to schedule it on-demand */
+ module.schedule();
+ module.waitForInitialization();
+ ITmfStateSystem ss = module.getStateSystem();
+ if (ss == null) {
+ /* If we've waited for initialization, 'ss' should not be null */
+ throw new IllegalStateException();
+ }
+ return ss;
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods related to function name mapping
+ // ------------------------------------------------------------------------
+
+ /**
+ * Toolbar icon to import the function address-to-name mapping file.
+ */
+ private Action getImportMappingAction() {
+ if (fImportMappingAction != null) {
+ return fImportMappingAction;
+ }
+ fImportMappingAction = new Action() {
+ @Override
+ public void run() {
+ FileDialog dialog = new FileDialog(getViewSite().getShell());
+ dialog.setText(Messages.CallStackView_ImportMappingDialogTitle);
+ 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 ImportMappingJob(new File(filePath));
+ job.schedule();
+ }
+ };
+
+ fImportMappingAction.setText(Messages.CallStackView_ImportMappingButtonText);
+ fImportMappingAction.setToolTipText(Messages.CallStackView_ImportMappingButtonTooltip);
+ fImportMappingAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(IMPORT_MAPPING_ICON_PATH));
+
+ return fImportMappingAction;
+ }
+
+ private class ImportMappingJob extends Job {
+ private final File fMappingFile;
+
+ public ImportMappingJob(File mappingFile) {
+ super(Messages.CallStackView_ImportMappingJobName);
+ fMappingFile = mappingFile;
+ }
+
+ @Override
+ public IStatus run(IProgressMonitor monitor) {
+ fNameMapping = FunctionNameMapper.mapFromNmTextFile(fMappingFile);
+
+ /* Refresh the time graph and the list of entries */
+ buildThreadList(fTrace, new NullProgressMonitor());
+ redraw();
+
+ return Status.OK_STATUS;
+ }
+ }
+
+ 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 ret;
+ }
+
}