1 /*******************************************************************************
2 * Copyright (c) 2013, 2014 Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Patrick Tasse - Initial API and implementation
11 * Bernd Hufmann - Updated signal handling
12 * Marc-Andre Laperle - Map from binary file
13 *******************************************************************************/
15 package org
.eclipse
.linuxtools
.tmf
.ui
.views
.callstack
;
18 import java
.util
.ArrayList
;
19 import java
.util
.Comparator
;
20 import java
.util
.HashMap
;
21 import java
.util
.Iterator
;
22 import java
.util
.List
;
25 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
26 import org
.eclipse
.core
.runtime
.IStatus
;
27 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
28 import org
.eclipse
.core
.runtime
.Status
;
29 import org
.eclipse
.core
.runtime
.jobs
.Job
;
30 import org
.eclipse
.jdt
.annotation
.Nullable
;
31 import org
.eclipse
.jface
.action
.Action
;
32 import org
.eclipse
.jface
.action
.IAction
;
33 import org
.eclipse
.jface
.action
.IStatusLineManager
;
34 import org
.eclipse
.jface
.action
.IToolBarManager
;
35 import org
.eclipse
.jface
.action
.MenuManager
;
36 import org
.eclipse
.jface
.action
.Separator
;
37 import org
.eclipse
.jface
.dialogs
.IDialogSettings
;
38 import org
.eclipse
.jface
.resource
.ImageDescriptor
;
39 import org
.eclipse
.jface
.util
.IPropertyChangeListener
;
40 import org
.eclipse
.jface
.util
.PropertyChangeEvent
;
41 import org
.eclipse
.jface
.viewers
.DoubleClickEvent
;
42 import org
.eclipse
.jface
.viewers
.IDoubleClickListener
;
43 import org
.eclipse
.jface
.viewers
.ILabelProviderListener
;
44 import org
.eclipse
.jface
.viewers
.ISelection
;
45 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
46 import org
.eclipse
.jface
.viewers
.ITableLabelProvider
;
47 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
48 import org
.eclipse
.jface
.viewers
.Viewer
;
49 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Activator
;
50 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.ITmfImageConstants
;
51 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Messages
;
52 import org
.eclipse
.linuxtools
.statesystem
.core
.ITmfStateSystem
;
53 import org
.eclipse
.linuxtools
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
54 import org
.eclipse
.linuxtools
.statesystem
.core
.exceptions
.StateSystemDisposedException
;
55 import org
.eclipse
.linuxtools
.statesystem
.core
.exceptions
.StateValueTypeException
;
56 import org
.eclipse
.linuxtools
.statesystem
.core
.exceptions
.TimeRangeException
;
57 import org
.eclipse
.linuxtools
.statesystem
.core
.interval
.ITmfStateInterval
;
58 import org
.eclipse
.linuxtools
.statesystem
.core
.statevalue
.ITmfStateValue
;
59 import org
.eclipse
.linuxtools
.statesystem
.core
.statevalue
.ITmfStateValue
.Type
;
60 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfRangeSynchSignal
;
61 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
62 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTimeSynchSignal
;
63 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceClosedSignal
;
64 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
65 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
66 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.ITmfTimestamp
;
67 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfNanoTimestamp
;
68 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimeRange
;
69 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimestamp
;
70 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimestampDelta
;
71 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
72 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfTraceManager
;
73 import org
.eclipse
.linuxtools
.tmf
.ui
.editors
.ITmfTraceEditor
;
74 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.TmfView
;
75 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.ITimeGraphRangeListener
;
76 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.ITimeGraphTimeListener
;
77 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphCombo
;
78 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphRangeUpdateEvent
;
79 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphTimeEvent
;
80 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphViewer
;
81 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
82 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
83 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.NullTimeEvent
;
84 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.TimeEvent
;
85 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.TimeGraphEntry
;
86 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphControl
;
87 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphSelection
;
88 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.TimeFormat
;
89 import org
.eclipse
.swt
.SWT
;
90 import org
.eclipse
.swt
.events
.ControlAdapter
;
91 import org
.eclipse
.swt
.events
.ControlEvent
;
92 import org
.eclipse
.swt
.events
.MouseAdapter
;
93 import org
.eclipse
.swt
.events
.MouseEvent
;
94 import org
.eclipse
.swt
.graphics
.Image
;
95 import org
.eclipse
.swt
.widgets
.Composite
;
96 import org
.eclipse
.swt
.widgets
.Display
;
97 import org
.eclipse
.swt
.widgets
.FileDialog
;
98 import org
.eclipse
.swt
.widgets
.Menu
;
99 import org
.eclipse
.swt
.widgets
.Tree
;
100 import org
.eclipse
.ui
.IActionBars
;
101 import org
.eclipse
.ui
.IEditorPart
;
104 * Main implementation for the Call Stack view
106 * @author Patrick Tasse
109 public class CallStackView
extends TmfView
{
111 // ------------------------------------------------------------------------
113 // ------------------------------------------------------------------------
116 public static final String ID
= "org.eclipse.linuxtools.tmf.ui.views.callstack"; //$NON-NLS-1$
121 private enum State
{ IDLE
, BUSY
, PENDING
}
123 private static final String
[] COLUMN_TIMES
= new String
[] {
124 Messages
.CallStackView_FunctionColumn
,
125 Messages
.CallStackView_DepthColumn
,
126 Messages
.CallStackView_EntryTimeColumn
,
127 Messages
.CallStackView_ExitTimeColumn
,
128 Messages
.CallStackView_DurationColumn
131 private static final int[] COLUMN_WIDTHS
= new int[] {
139 // Fraction of a function duration to be added as spacing
140 private static final double SPACING_RATIO
= 0.01;
142 private static final Image THREAD_IMAGE
= Activator
.getDefault().getImageFromPath("icons/obj16/thread_obj.gif"); //$NON-NLS-1$
143 private static final Image STACKFRAME_IMAGE
= Activator
.getDefault().getImageFromPath("icons/obj16/stckframe_obj.gif"); //$NON-NLS-1$
145 private static final String IMPORT_MAPPING_ICON_PATH
= "icons/etool16/import.gif"; //$NON-NLS-1$
146 private static final String IMPORT_BINARY_ICON_PATH
= "icons/obj16/binaries_obj.gif"; //$NON-NLS-1$
148 private static final ImageDescriptor SORT_BY_NAME_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha.gif"); //$NON-NLS-1$
149 private static final ImageDescriptor SORT_BY_NAME_REV_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha_rev.gif"); //$NON-NLS-1$
150 private static final ImageDescriptor SORT_BY_ID_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_num.gif"); //$NON-NLS-1$
151 private static final ImageDescriptor SORT_BY_ID_REV_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_num_rev.gif"); //$NON-NLS-1$
152 private static final ImageDescriptor SORT_BY_TIME_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_time.gif"); //$NON-NLS-1$
153 private static final ImageDescriptor SORT_BY_TIME_REV_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_time_rev.gif"); //$NON-NLS-1$
154 private static final String SORT_OPTION_KEY
= "sort.option"; //$NON-NLS-1$
155 private enum SortOption
{ BY_NAME
, BY_NAME_REV
, BY_ID
, BY_ID_REV
, BY_TIME
, BY_TIME_REV
}
156 private SortOption fSortOption
;
157 private Comparator
<ITimeGraphEntry
> fThreadComparator
= null;
158 private Action fSortByNameAction
;
159 private Action fSortByIdAction
;
160 private Action fSortByTimeAction
;
162 // ------------------------------------------------------------------------
164 // ------------------------------------------------------------------------
166 // The time graph combo
167 private TimeGraphCombo fTimeGraphCombo
;
169 // The selected trace
170 private ITmfTrace fTrace
;
172 // The selected thread map
173 private final Map
<ITmfTrace
, String
> fSelectedThreadMap
= new HashMap
<>();
175 // The time graph entry list
176 private List
<TraceEntry
> fEntryList
;
178 // The trace to entry list hash map
179 private final Map
<ITmfTrace
, ArrayList
<TraceEntry
>> fEntryListMap
= new HashMap
<>();
181 // The trace to build thread hash map
182 private final Map
<ITmfTrace
, BuildThread
> fBuildThreadMap
= new HashMap
<>();
184 /** The map to map function addresses to function names */
185 private Map
<String
, String
> fNameMapping
;
188 private long fStartTime
;
191 private long fEndTime
;
194 private int fDisplayWidth
;
196 // The next event action
197 private Action fNextEventAction
;
199 // The previous event action
200 private Action fPrevEventAction
;
202 // The next item action
203 private Action fNextItemAction
;
205 // The previous item action
206 private Action fPreviousItemAction
;
208 // The action to import a function-name mapping file
209 private Action fImportMappingAction
;
211 // The action to import a binary file mapping */
212 private Action fImportBinaryFileMappingAction
;
215 private ZoomThread fZoomThread
;
217 // The redraw state used to prevent unnecessary queuing of display runnables
218 private State fRedrawState
= State
.IDLE
;
220 // The redraw synchronization object
221 private final Object fSyncObj
= new Object();
223 // The saved time sync. signal used when switching off the pinning of a view
224 private TmfTimeSynchSignal fSavedTimeSyncSignal
;
226 // The saved time range sync. signal used when switching off the pinning of a view
227 private TmfRangeSynchSignal fSavedRangeSyncSignal
;
229 // ------------------------------------------------------------------------
231 // ------------------------------------------------------------------------
233 private class TraceEntry
extends TimeGraphEntry
{
234 public TraceEntry(String name
, long startTime
, long endTime
) {
235 super(name
, startTime
, endTime
);
239 public boolean hasTimeEvents() {
244 private class ThreadEntry
extends TimeGraphEntry
{
245 // The call stack quark
246 private final int fCallStackQuark
;
247 // The state system from which this entry comes
248 private final ITmfStateSystem fSS
;
250 private final long fThreadId
;
252 public ThreadEntry(ITmfStateSystem ss
, String name
, long threadId
, int callStackQuark
, long startTime
, long endTime
) {
253 super(name
, startTime
, endTime
);
254 fCallStackQuark
= callStackQuark
;
255 fThreadId
= threadId
;
260 public boolean hasTimeEvents() {
264 public int getCallStackQuark() {
265 return fCallStackQuark
;
268 public long getThreadId() {
273 public ITmfStateSystem
getStateSystem() {
278 private class ThreadNameComparator
implements Comparator
<ITimeGraphEntry
> {
279 private boolean reverse
;
280 public ThreadNameComparator(boolean reverse
) {
281 this.reverse
= reverse
;
284 public int compare(ITimeGraphEntry o1
, ITimeGraphEntry o2
) {
285 return reverse ? o2
.getName().compareTo(o1
.getName()) :
286 o1
.getName().compareTo(o2
.getName());
290 private class ThreadIdComparator
implements Comparator
<ITimeGraphEntry
> {
291 private boolean reverse
;
292 public ThreadIdComparator(boolean reverse
) {
293 this.reverse
= reverse
;
296 public int compare(ITimeGraphEntry o1
, ITimeGraphEntry o2
) {
297 ThreadEntry t1
= (ThreadEntry
) o1
;
298 ThreadEntry t2
= (ThreadEntry
) o2
;
299 return reverse ? Long
.compare(t2
.getThreadId(), t1
.getThreadId()) :
300 Long
.compare(t1
.getThreadId(), t2
.getThreadId());
304 private class ThreadTimeComparator
implements Comparator
<ITimeGraphEntry
> {
305 private boolean reverse
;
306 public ThreadTimeComparator(boolean reverse
) {
307 this.reverse
= reverse
;
310 public int compare(ITimeGraphEntry o1
, ITimeGraphEntry o2
) {
311 return reverse ? Long
.compare(o2
.getStartTime(), o1
.getStartTime()) :
312 Long
.compare(o1
.getStartTime(), o2
.getStartTime());
316 private class TreeContentProvider
implements ITreeContentProvider
{
319 public void dispose() {
323 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
327 public Object
[] getElements(Object inputElement
) {
328 return (ITimeGraphEntry
[]) inputElement
;
332 public Object
[] getChildren(Object parentElement
) {
333 ITimeGraphEntry entry
= (ITimeGraphEntry
) parentElement
;
334 return entry
.getChildren().toArray();
338 public Object
getParent(Object element
) {
339 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
340 return entry
.getParent();
344 public boolean hasChildren(Object element
) {
345 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
346 return entry
.hasChildren();
351 private class TreeLabelProvider
implements ITableLabelProvider
{
354 public void addListener(ILabelProviderListener listener
) {
358 public void dispose() {
362 public boolean isLabelProperty(Object element
, String property
) {
367 public void removeListener(ILabelProviderListener listener
) {
371 public Image
getColumnImage(Object element
, int columnIndex
) {
372 if (columnIndex
== 0) {
373 if (element
instanceof ThreadEntry
) {
375 } else if (element
instanceof CallStackEntry
) {
376 CallStackEntry entry
= (CallStackEntry
) element
;
377 if (entry
.getFunctionName().length() > 0) {
378 return STACKFRAME_IMAGE
;
386 public String
getColumnText(Object element
, int columnIndex
) {
387 if (element
instanceof CallStackEntry
) {
388 CallStackEntry entry
= (CallStackEntry
) element
;
389 if (columnIndex
== 0) {
390 return entry
.getFunctionName();
391 } else if (columnIndex
== 1 && entry
.getFunctionName().length() > 0) {
392 int depth
= entry
.getStackLevel();
393 return Integer
.toString(depth
);
394 } else if (columnIndex
== 2 && entry
.getFunctionName().length() > 0) {
395 ITmfTimestamp ts
= new TmfTimestamp(entry
.getFunctionEntryTime(), ITmfTimestamp
.NANOSECOND_SCALE
);
396 return ts
.toString();
397 } else if (columnIndex
== 3 && entry
.getFunctionName().length() > 0) {
398 ITmfTimestamp ts
= new TmfTimestamp(entry
.getFunctionExitTime(), ITmfTimestamp
.NANOSECOND_SCALE
);
399 return ts
.toString();
400 } else if (columnIndex
== 4 && entry
.getFunctionName().length() > 0) {
401 ITmfTimestamp ts
= new TmfTimestampDelta(entry
.getFunctionExitTime() - entry
.getFunctionEntryTime(), ITmfTimestamp
.NANOSECOND_SCALE
);
402 return ts
.toString();
404 } else if (element
instanceof ITimeGraphEntry
) {
405 if (columnIndex
== 0) {
406 return ((ITimeGraphEntry
) element
).getName();
409 return ""; //$NON-NLS-1$
414 private class BuildThread
extends Thread
{
415 private final ITmfTrace fBuildTrace
;
416 private final IProgressMonitor fMonitor
;
418 public BuildThread(ITmfTrace trace
) {
419 super("CallStackView build"); //$NON-NLS-1$
421 fMonitor
= new NullProgressMonitor();
426 buildThreadList(fBuildTrace
, fMonitor
);
427 synchronized (fBuildThreadMap
) {
428 fBuildThreadMap
.remove(this);
432 public void cancel() {
433 fMonitor
.setCanceled(true);
437 private class ZoomThread
extends Thread
{
438 private final List
<TraceEntry
> fZoomEntryList
;
439 private final long fZoomStartTime
;
440 private final long fZoomEndTime
;
441 private final IProgressMonitor fMonitor
;
443 public ZoomThread(List
<TraceEntry
> entryList
, long startTime
, long endTime
) {
444 super("CallStackView zoom"); //$NON-NLS-1$
445 fZoomEntryList
= entryList
;
446 fZoomStartTime
= startTime
;
447 fZoomEndTime
= endTime
;
448 fMonitor
= new NullProgressMonitor();
453 if (fZoomEntryList
== null) {
456 long resolution
= Math
.max(1, (fZoomEndTime
- fZoomStartTime
) / fDisplayWidth
);
457 for (TraceEntry traceEntry
: fZoomEntryList
) {
458 for (ITimeGraphEntry threadEntry
: traceEntry
.getChildren()) {
459 ITmfStateSystem ss
= ((ThreadEntry
) threadEntry
).getStateSystem();
464 if (ss
.isCancelled()) {
467 for (ITimeGraphEntry child
: threadEntry
.getChildren()) {
468 if (fMonitor
.isCanceled()) {
471 CallStackEntry entry
= (CallStackEntry
) child
;
472 if (fZoomStartTime
<= fStartTime
&& fZoomEndTime
>= fEndTime
) {
473 entry
.setZoomedEventList(null);
475 List
<ITimeEvent
> zoomedEventList
= getEventList(entry
, fZoomStartTime
, fZoomEndTime
, resolution
, fMonitor
);
476 if (zoomedEventList
!= null) {
477 entry
.setZoomedEventList(zoomedEventList
);
486 public void cancel() {
487 fMonitor
.setCanceled(true);
491 // ------------------------------------------------------------------------
493 // ------------------------------------------------------------------------
496 * Default constructor
498 public CallStackView() {
500 fDisplayWidth
= Display
.getDefault().getBounds().width
;
503 // ------------------------------------------------------------------------
505 // ------------------------------------------------------------------------
508 public void createPartControl(Composite parent
) {
509 fTimeGraphCombo
= new TimeGraphCombo(parent
, SWT
.NONE
);
511 fTimeGraphCombo
.setTreeContentProvider(new TreeContentProvider());
513 fTimeGraphCombo
.setTreeLabelProvider(new TreeLabelProvider());
515 fTimeGraphCombo
.setTreeColumns(COLUMN_TIMES
);
517 fTimeGraphCombo
.getTreeViewer().getTree().getColumn(0).setWidth(COLUMN_WIDTHS
[0]);
518 fTimeGraphCombo
.getTreeViewer().getTree().getColumn(1).setWidth(COLUMN_WIDTHS
[1]);
519 fTimeGraphCombo
.getTreeViewer().getTree().getColumn(2).setWidth(COLUMN_WIDTHS
[2]);
520 fTimeGraphCombo
.getTreeViewer().getTree().getColumn(3).setWidth(COLUMN_WIDTHS
[3]);
521 fTimeGraphCombo
.getTreeViewer().getTree().getColumn(4).setWidth(COLUMN_WIDTHS
[4]);
523 fTimeGraphCombo
.setTimeGraphProvider(new CallStackPresentationProvider(this));
524 fTimeGraphCombo
.getTimeGraphViewer().setTimeFormat(TimeFormat
.CALENDAR
);
526 fTimeGraphCombo
.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
528 public void timeRangeUpdated(TimeGraphRangeUpdateEvent event
) {
529 long startTime
= event
.getStartTime();
530 long endTime
= event
.getEndTime();
531 TmfTimeRange range
= new TmfTimeRange(new TmfNanoTimestamp(startTime
), new TmfNanoTimestamp(endTime
));
532 broadcast(new TmfRangeSynchSignal(CallStackView
.this, range
));
533 startZoomThread(startTime
, endTime
);
537 fTimeGraphCombo
.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
539 public void timeSelected(TimeGraphTimeEvent event
) {
540 long beginTime
= event
.getBeginTime();
541 long endTime
= event
.getEndTime();
542 selectTime(beginTime
);
543 broadcast(new TmfTimeSynchSignal(CallStackView
.this, new TmfNanoTimestamp(beginTime
), new TmfNanoTimestamp(endTime
)));
547 fTimeGraphCombo
.getTimeGraphViewer().getControl().addControlListener(new ControlAdapter() {
549 public void controlResized(ControlEvent e
) {
550 fDisplayWidth
= fTimeGraphCombo
.getTimeGraphViewer().getControl().getSize().x
;
551 if (fEntryList
!= null) {
552 startZoomThread(fTimeGraphCombo
.getTimeGraphViewer().getTime0(), fTimeGraphCombo
.getTimeGraphViewer().getTime1());
557 fTimeGraphCombo
.getTreeViewer().addDoubleClickListener(new IDoubleClickListener() {
559 public void doubleClick(DoubleClickEvent event
) {
560 Object selection
= ((IStructuredSelection
) event
.getSelection()).getFirstElement();
561 if (selection
instanceof CallStackEntry
) {
562 CallStackEntry entry
= (CallStackEntry
) selection
;
563 if (entry
.getFunctionName().length() > 0) {
564 long entryTime
= entry
.getFunctionEntryTime();
565 long exitTime
= entry
.getFunctionExitTime();
566 long spacingTime
= (long) ((exitTime
- entryTime
) * SPACING_RATIO
);
567 entryTime
-= spacingTime
;
568 exitTime
+= spacingTime
;
569 TmfTimeRange range
= new TmfTimeRange(new TmfNanoTimestamp(entryTime
), new TmfNanoTimestamp(exitTime
));
570 broadcast(new TmfRangeSynchSignal(CallStackView
.this, range
));
571 fTimeGraphCombo
.getTimeGraphViewer().setStartFinishTime(entryTime
, exitTime
);
572 startZoomThread(entryTime
, exitTime
);
578 fTimeGraphCombo
.getTimeGraphViewer().getTimeGraphControl().addMouseListener(new MouseAdapter() {
580 public void mouseDoubleClick(MouseEvent e
) {
581 TimeGraphControl timeGraphControl
= fTimeGraphCombo
.getTimeGraphViewer().getTimeGraphControl();
582 ISelection selection
= timeGraphControl
.getSelection();
583 if (selection
instanceof TimeGraphSelection
) {
584 Object o
= ((TimeGraphSelection
) selection
).getFirstElement();
585 if (o
instanceof CallStackEvent
) {
586 CallStackEvent event
= (CallStackEvent
) o
;
587 long startTime
= event
.getTime();
588 long endTime
= startTime
+ event
.getDuration();
589 long spacingTime
= (long) ((endTime
- startTime
) * SPACING_RATIO
);
590 startTime
-= spacingTime
;
591 endTime
+= spacingTime
;
592 TmfTimeRange range
= new TmfTimeRange(new TmfNanoTimestamp(startTime
), new TmfNanoTimestamp(endTime
));
593 broadcast(new TmfRangeSynchSignal(CallStackView
.this, range
));
594 fTimeGraphCombo
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
595 startZoomThread(startTime
, endTime
);
601 IStatusLineManager statusLineManager
= getViewSite().getActionBars().getStatusLineManager();
602 fTimeGraphCombo
.getTimeGraphViewer().getTimeGraphControl().setStatusLineManager(statusLineManager
);
604 // View Action Handling
606 contributeToActionBars();
610 IEditorPart editor
= getSite().getPage().getActiveEditor();
611 if (editor
instanceof ITmfTraceEditor
) {
612 ITmfTrace trace
= ((ITmfTraceEditor
) editor
).getTrace();
614 traceSelected(new TmfTraceSelectedSignal(this, trace
));
620 public void setFocus() {
621 fTimeGraphCombo
.setFocus();
624 // ------------------------------------------------------------------------
626 // ------------------------------------------------------------------------
628 * Handler for the trace opened signal.
630 * The incoming signal
634 public void traceOpened(TmfTraceOpenedSignal signal
) {
635 fTrace
= signal
.getTrace();
640 * Handler for the trace selected signal
643 * The incoming signal
646 public void traceSelected(final TmfTraceSelectedSignal signal
) {
647 if (signal
.getTrace() == fTrace
) {
650 fTrace
= signal
.getTrace();
655 * Trace is closed: clear the data structures and the view
657 * @param signal the signal received
660 public void traceClosed(final TmfTraceClosedSignal signal
) {
661 synchronized (fBuildThreadMap
) {
662 BuildThread buildThread
= fBuildThreadMap
.remove(signal
.getTrace());
663 if (buildThread
!= null) {
664 buildThread
.cancel();
667 synchronized (fEntryListMap
) {
668 fEntryListMap
.remove(signal
.getTrace());
670 fSelectedThreadMap
.remove(signal
.getTrace());
671 if (signal
.getTrace() == fTrace
) {
680 * Handler for the TimeSynch signal
683 * The incoming signal
686 public void synchToTime(final TmfTimeSynchSignal signal
) {
688 fSavedTimeSyncSignal
= isPinned() ?
new TmfTimeSynchSignal(signal
.getSource(), signal
.getBeginTime(), signal
.getEndTime()) : null;
690 if (signal
.getSource() == this || fTrace
== null || isPinned()) {
693 final long beginTime
= signal
.getBeginTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
694 final long endTime
= signal
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
695 Display
.getDefault().asyncExec(new Runnable() {
698 if (fTimeGraphCombo
.isDisposed()) {
701 if (beginTime
== endTime
) {
702 fTimeGraphCombo
.getTimeGraphViewer().setSelectedTime(beginTime
, true);
704 fTimeGraphCombo
.getTimeGraphViewer().setSelectionRange(beginTime
, endTime
);
706 selectTime(beginTime
);
707 startZoomThread(fTimeGraphCombo
.getTimeGraphViewer().getTime0(), fTimeGraphCombo
.getTimeGraphViewer().getTime1());
708 if (fEntryList
== null) {
711 TimeGraphViewer viewer
= fTimeGraphCombo
.getTimeGraphViewer();
712 for (TraceEntry traceEntry
: fEntryList
) {
713 for (ITimeGraphEntry child
: traceEntry
.getChildren()) {
714 ThreadEntry threadEntry
= (ThreadEntry
) child
;
715 ITmfStateSystem ss
= threadEntry
.getStateSystem();
716 if (ss
== null || beginTime
< ss
.getStartTime() || beginTime
> ss
.getCurrentEndTime()) {
720 int quark
= threadEntry
.getCallStackQuark();
721 ITmfStateInterval stackInterval
= ss
.querySingleState(beginTime
, quark
);
722 if (beginTime
== stackInterval
.getStartTime()) {
723 int stackLevel
= stackInterval
.getStateValue().unboxInt();
724 ITimeGraphEntry selectedEntry
= threadEntry
.getChildren().get(Math
.max(0, stackLevel
- 1));
725 fTimeGraphCombo
.setSelection(selectedEntry
);
726 viewer
.getTimeGraphControl().fireSelectionChanged();
729 } catch (AttributeNotFoundException e
) {
730 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
731 } catch (TimeRangeException e
) {
732 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
733 } catch (StateSystemDisposedException e
) {
734 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
735 } catch (StateValueTypeException e
) {
736 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
745 * Handler for the RangeSynch signal
748 * The incoming signal
751 public void synchToRange(final TmfRangeSynchSignal signal
) {
754 fSavedRangeSyncSignal
=
755 new TmfRangeSynchSignal(signal
.getSource(), new TmfTimeRange(signal
.getCurrentRange().getStartTime(), signal
.getCurrentRange().getEndTime()));
757 fSavedTimeSyncSignal
= null;
760 if (signal
.getSource() == this || fTrace
== null || isPinned()) {
763 if (signal
.getCurrentRange().getIntersection(fTrace
.getTimeRange()) == null) {
766 final long startTime
= signal
.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
767 final long endTime
= signal
.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
768 Display
.getDefault().asyncExec(new Runnable() {
771 if (fTimeGraphCombo
.isDisposed()) {
774 fTimeGraphCombo
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
775 startZoomThread(startTime
, endTime
);
780 // ------------------------------------------------------------------------
782 // ------------------------------------------------------------------------
784 private void loadTrace() {
785 synchronized (fEntryListMap
) {
786 fEntryList
= fEntryListMap
.get(fTrace
);
787 if (fEntryList
== null) {
788 synchronized (fBuildThreadMap
) {
789 BuildThread buildThread
= new BuildThread(fTrace
);
790 fBuildThreadMap
.put(fTrace
, buildThread
);
794 fStartTime
= fTrace
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
795 fEndTime
= fTrace
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
801 private void buildThreadList(final ITmfTrace trace
, IProgressMonitor monitor
) {
802 fStartTime
= Long
.MAX_VALUE
;
803 fEndTime
= Long
.MIN_VALUE
;
804 ITmfTrace
[] traces
= TmfTraceManager
.getTraceSet(trace
);
805 ArrayList
<TraceEntry
> entryList
= new ArrayList
<>();
806 for (ITmfTrace aTrace
: traces
) {
807 if (monitor
.isCanceled()) {
810 AbstractCallStackAnalysis module
= getCallStackModule(trace
);
811 if (module
== null) {
814 ITmfStateSystem ss
= module
.getStateSystem();
816 addUnavailableEntry(aTrace
, entryList
);
820 if (ss
.isCancelled()) {
821 addUnavailableEntry(aTrace
, entryList
);
824 long startTime
= ss
.getStartTime();
825 long endTime
= ss
.getCurrentEndTime() + 1;
826 fStartTime
= Math
.min(fStartTime
, startTime
);
827 fEndTime
= Math
.max(fEndTime
, endTime
);
828 String
[] threadPaths
= module
.getThreadsPattern();
829 List
<Integer
> threadQuarks
= ss
.getQuarks(threadPaths
);
830 TraceEntry traceEntry
= new TraceEntry(trace
.getName(), startTime
, endTime
);
831 traceEntry
.sortChildren(fThreadComparator
);
832 entryList
.add(traceEntry
);
833 for (int i
= 0; i
< threadQuarks
.size(); i
++) {
834 if (monitor
.isCanceled()) {
837 int threadQuark
= threadQuarks
.get(i
);
839 String
[] callStackPath
= module
.getCallStackPath();
840 int callStackQuark
= ss
.getQuarkRelative(threadQuark
, callStackPath
);
841 String threadName
= ss
.getAttributeName(threadQuark
);
842 long threadId
= ss
.querySingleState(ss
.getCurrentEndTime() , threadQuark
).getStateValue().unboxLong();
843 long start
= startTime
;
844 ITmfStateInterval startInterval
= ss
.querySingleState(startTime
, callStackQuark
);
845 if (startInterval
.getStateValue().isNull()) {
846 start
= Math
.min(startInterval
.getEndTime() + 1, endTime
);
849 ITmfStateInterval endInterval
= ss
.querySingleState(ss
.getCurrentEndTime(), callStackQuark
);
850 if (endInterval
.getStateValue().isNull()) {
851 end
= endInterval
.getStartTime() == startTime ? endTime
: endInterval
.getStartTime();
853 ThreadEntry threadEntry
= new ThreadEntry(ss
, threadName
, threadId
, callStackQuark
, start
, end
);
854 traceEntry
.addChild(threadEntry
);
856 for (int stackLevelQuark
: ss
.getSubAttributes(callStackQuark
, false)) {
857 CallStackEntry callStackEntry
= new CallStackEntry(threadName
, stackLevelQuark
, level
++, aTrace
, ss
);
858 threadEntry
.addChild(callStackEntry
);
860 } catch (AttributeNotFoundException e
) {
861 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
862 } catch (StateSystemDisposedException e
) {
867 synchronized (fEntryListMap
) {
868 fEntryListMap
.put(trace
, new ArrayList
<>(entryList
));
870 if (trace
== fTrace
) {
873 for (TraceEntry traceEntry
: entryList
) {
874 for (ITimeGraphEntry threadEntry
: traceEntry
.getChildren()) {
875 for (ITimeGraphEntry callStackEntry
: threadEntry
.getChildren()) {
876 if (monitor
.isCanceled()) {
879 buildStatusEvents(trace
, (CallStackEntry
) callStackEntry
, monitor
);
885 private void addUnavailableEntry(ITmfTrace trace
, List
<TraceEntry
> list
) {
886 String name
= Messages
.CallStackView_StackInfoNotAvailable
+ ' ' + '(' + trace
.getName() + ')';
887 TraceEntry unavailableEntry
= new TraceEntry(name
, 0, 0);
888 list
.add(unavailableEntry
);
891 private void buildStatusEvents(ITmfTrace trace
, CallStackEntry entry
, IProgressMonitor monitor
) {
892 ITmfStateSystem ss
= entry
.getStateSystem();
893 long start
= ss
.getStartTime();
894 long end
= ss
.getCurrentEndTime() + 1;
895 long resolution
= Math
.max(1, (end
- start
) / fDisplayWidth
);
896 List
<ITimeEvent
> eventList
= getEventList(entry
, start
, end
, resolution
, monitor
);
897 if (monitor
.isCanceled()) {
900 entry
.setEventList(eventList
);
901 if (trace
== fTrace
) {
906 private static List
<ITimeEvent
> getEventList(CallStackEntry entry
,
907 long startTime
, long endTime
, long resolution
,
908 IProgressMonitor monitor
) {
909 ITmfStateSystem ss
= entry
.getStateSystem();
910 long start
= Math
.max(startTime
, ss
.getStartTime());
911 long end
= Math
.min(endTime
, ss
.getCurrentEndTime() + 1);
915 List
<ITimeEvent
> eventList
= null;
917 List
<ITmfStateInterval
> stackIntervals
= ss
.queryHistoryRange(entry
.getQuark(), start
, end
- 1, resolution
, monitor
);
918 eventList
= new ArrayList
<>(stackIntervals
.size());
919 long lastEndTime
= -1;
920 boolean lastIsNull
= true;
921 for (ITmfStateInterval statusInterval
: stackIntervals
) {
922 if (monitor
.isCanceled()) {
925 long time
= statusInterval
.getStartTime();
926 long duration
= statusInterval
.getEndTime() - time
+ 1;
927 if (!statusInterval
.getStateValue().isNull()) {
928 final int modulo
= CallStackPresentationProvider
.NUM_COLORS
/ 2;
929 int value
= statusInterval
.getStateValue().toString().hashCode() % modulo
+ modulo
;
930 eventList
.add(new CallStackEvent(entry
, time
, duration
, value
));
933 if (lastEndTime
== -1) {
934 // add null event if it intersects the start time
935 eventList
.add(new NullTimeEvent(entry
, time
, duration
));
937 if (lastEndTime
!= time
&& lastIsNull
) {
938 // add unknown event if between two null states
939 eventList
.add(new TimeEvent(entry
, lastEndTime
, time
- lastEndTime
));
941 if (time
+ duration
>= endTime
) {
942 // add null event if it intersects the end time
943 eventList
.add(new NullTimeEvent(entry
, time
, duration
));
948 lastEndTime
= time
+ duration
;
950 } catch (AttributeNotFoundException e
) {
951 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
952 } catch (TimeRangeException e
) {
953 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
954 } catch (StateSystemDisposedException e
) {
960 private void selectTime(long time
) {
961 if (fEntryList
== null) {
964 for (TraceEntry traceEntry
: fEntryList
) {
965 for (ITimeGraphEntry threadEntry
: traceEntry
.getChildren()) {
966 ITmfStateSystem ss
= ((ThreadEntry
) threadEntry
).getStateSystem();
971 if (ss
.isCancelled()) {
974 long queryTime
= Math
.max(ss
.getStartTime(), Math
.min(ss
.getCurrentEndTime(), time
));
975 for (ITimeGraphEntry child
: threadEntry
.getChildren()) {
976 CallStackEntry callStackEntry
= (CallStackEntry
) child
;
978 ITmfStateInterval stackLevelInterval
= ss
.querySingleState(queryTime
, callStackEntry
.getQuark());
979 ITmfStateValue nameValue
= stackLevelInterval
.getStateValue();
980 String name
= ""; //$NON-NLS-1$
982 if (nameValue
.getType() == Type
.STRING
) {
983 String address
= nameValue
.unboxStr();
984 name
= getFunctionName(address
);
985 } else if (nameValue
.getType() == Type
.INTEGER
) {
986 name
= "0x" + Integer
.toHexString(nameValue
.unboxInt()); //$NON-NLS-1$
987 } else if (nameValue
.getType() == Type
.LONG
) {
988 name
= "0x" + Long
.toHexString(nameValue
.unboxLong()); //$NON-NLS-1$
990 } catch (StateValueTypeException e
) {
992 callStackEntry
.setFunctionName(name
);
993 if (name
.length() > 0) {
994 callStackEntry
.setFunctionEntryTime(stackLevelInterval
.getStartTime());
995 callStackEntry
.setFunctionExitTime(stackLevelInterval
.getEndTime() + 1);
997 } catch (AttributeNotFoundException e
) {
998 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
999 } catch (TimeRangeException e
) {
1000 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1001 } catch (StateSystemDisposedException e
) {
1002 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1007 fTimeGraphCombo
.refresh();
1010 private void refresh() {
1011 Display
.getDefault().asyncExec(new Runnable() {
1014 if (fTimeGraphCombo
.isDisposed()) {
1017 ITimeGraphEntry
[] entries
= null;
1018 synchronized (fEntryListMap
) {
1019 fEntryList
= fEntryListMap
.get(fTrace
);
1020 if (fEntryList
== null) {
1021 fEntryList
= new ArrayList
<>();
1023 entries
= fEntryList
.toArray(new ITimeGraphEntry
[0]);
1024 for (TraceEntry traceEntry
: fEntryList
) {
1025 traceEntry
.sortChildren(fThreadComparator
);
1028 fTimeGraphCombo
.setInput(entries
);
1029 fTimeGraphCombo
.getTimeGraphViewer().setTimeBounds(fStartTime
, fEndTime
);
1031 long selectionBeginTime
= fTrace
== null ?
0 : fTraceManager
.getSelectionBeginTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1032 long selectionEndTime
= fTrace
== null ?
0 : fTraceManager
.getSelectionEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1033 long startTime
= fTrace
== null ?
0 : fTraceManager
.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1034 long endTime
= fTrace
== null ?
0 : fTraceManager
.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1035 startTime
= Math
.max(startTime
, fStartTime
);
1036 endTime
= Math
.min(endTime
, fEndTime
);
1037 fTimeGraphCombo
.getTimeGraphViewer().setSelectionRange(selectionBeginTime
, selectionEndTime
);
1038 selectTime(selectionBeginTime
);
1039 fTimeGraphCombo
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
1040 startZoomThread(startTime
, endTime
);
1045 private void redraw() {
1046 synchronized (fSyncObj
) {
1047 if (fRedrawState
== State
.IDLE
) {
1048 fRedrawState
= State
.BUSY
;
1050 fRedrawState
= State
.PENDING
;
1054 Display
.getDefault().asyncExec(new Runnable() {
1057 if (fTimeGraphCombo
.isDisposed()) {
1060 fTimeGraphCombo
.redraw();
1061 fTimeGraphCombo
.update();
1062 synchronized (fSyncObj
) {
1063 if (fRedrawState
== State
.PENDING
) {
1064 fRedrawState
= State
.IDLE
;
1067 fRedrawState
= State
.IDLE
;
1074 private void startZoomThread(long startTime
, long endTime
) {
1075 if (fZoomThread
!= null) {
1076 fZoomThread
.cancel();
1078 fZoomThread
= new ZoomThread(fEntryList
, startTime
, endTime
);
1079 fZoomThread
.start();
1082 private void makeActions() {
1083 fPreviousItemAction
= fTimeGraphCombo
.getTimeGraphViewer().getPreviousItemAction();
1084 fPreviousItemAction
.setText(Messages
.TmfTimeGraphViewer_PreviousItemActionNameText
);
1085 fPreviousItemAction
.setToolTipText(Messages
.TmfTimeGraphViewer_PreviousItemActionToolTipText
);
1086 fNextItemAction
= fTimeGraphCombo
.getTimeGraphViewer().getNextItemAction();
1087 fNextItemAction
.setText(Messages
.TmfTimeGraphViewer_NextItemActionNameText
);
1088 fNextItemAction
.setToolTipText(Messages
.TmfTimeGraphViewer_NextItemActionToolTipText
);
1091 private void contributeToActionBars() {
1092 IActionBars bars
= getViewSite().getActionBars();
1093 fillLocalToolBar(bars
.getToolBarManager());
1095 // Create pin action
1096 contributePinActionToToolBar();
1097 fPinAction
.addPropertyChangeListener(new IPropertyChangeListener(){
1099 public void propertyChange(PropertyChangeEvent event
) {
1100 if (IAction
.CHECKED
.equals(event
.getProperty()) && !isPinned()) {
1101 if (fSavedRangeSyncSignal
!= null) {
1102 synchToRange(fSavedRangeSyncSignal
);
1103 fSavedRangeSyncSignal
= null;
1106 if (fSavedTimeSyncSignal
!= null) {
1107 synchToTime(fSavedTimeSyncSignal
);
1108 fSavedTimeSyncSignal
= null;
1115 private void fillLocalToolBar(IToolBarManager manager
) {
1116 manager
.add(getImportBinaryAction());
1117 manager
.add(getImportMappingAction());
1118 manager
.add(new Separator());
1119 manager
.add(getSortByNameAction());
1120 manager
.add(getSortByIdAction());
1121 manager
.add(getSortByTimeAction());
1122 manager
.add(new Separator());
1123 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getResetScaleAction());
1124 manager
.add(getPreviousEventAction());
1125 manager
.add(getNextEventAction());
1126 manager
.add(fPreviousItemAction
);
1127 manager
.add(fNextItemAction
);
1128 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getZoomInAction());
1129 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getZoomOutAction());
1130 manager
.add(new Separator());
1133 private void createContextMenu() {
1134 final MenuManager contextMenu
= new MenuManager();
1135 contextMenu
.add(getSortByNameAction());
1136 contextMenu
.add(getSortByIdAction());
1137 contextMenu
.add(getSortByTimeAction());
1139 Tree tree
= fTimeGraphCombo
.getTreeViewer().getTree();
1140 Menu menu
= contextMenu
.createContextMenu(tree
);
1145 * Get the the next event action.
1147 * @return The action object
1149 private Action
getNextEventAction() {
1150 if (fNextEventAction
== null) {
1151 fNextEventAction
= new Action() {
1154 TimeGraphViewer viewer
= fTimeGraphCombo
.getTimeGraphViewer();
1155 ITimeGraphEntry entry
= viewer
.getSelection();
1156 if (entry
instanceof CallStackEntry
) {
1158 CallStackEntry callStackEntry
= (CallStackEntry
) entry
;
1159 ITmfStateSystem ss
= callStackEntry
.getStateSystem();
1160 long time
= Math
.max(ss
.getStartTime(), Math
.min(ss
.getCurrentEndTime(), viewer
.getSelectionBegin()));
1161 ThreadEntry threadEntry
= (ThreadEntry
) callStackEntry
.getParent();
1162 int quark
= ss
.getParentAttributeQuark(callStackEntry
.getQuark());
1163 ITmfStateInterval stackInterval
= ss
.querySingleState(time
, quark
);
1164 long newTime
= stackInterval
.getEndTime() + 1;
1165 viewer
.setSelectedTimeNotify(newTime
, true);
1166 stackInterval
= ss
.querySingleState(Math
.min(ss
.getCurrentEndTime(), newTime
), quark
);
1167 int stackLevel
= stackInterval
.getStateValue().unboxInt();
1168 ITimeGraphEntry selectedEntry
= threadEntry
.getChildren().get(Math
.max(0, stackLevel
- 1));
1169 fTimeGraphCombo
.setSelection(selectedEntry
);
1170 viewer
.getTimeGraphControl().fireSelectionChanged();
1171 startZoomThread(viewer
.getTime0(), viewer
.getTime1());
1173 } catch (AttributeNotFoundException e
) {
1174 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1175 } catch (TimeRangeException e
) {
1176 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1177 } catch (StateSystemDisposedException e
) {
1178 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1179 } catch (StateValueTypeException e
) {
1180 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1186 fNextEventAction
.setText(Messages
.TmfTimeGraphViewer_NextEventActionNameText
);
1187 fNextEventAction
.setToolTipText(Messages
.TmfTimeGraphViewer_NextEventActionToolTipText
);
1188 fNextEventAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(ITmfImageConstants
.IMG_UI_NEXT_EVENT
));
1191 return fNextEventAction
;
1195 * Get the previous event action.
1197 * @return The Action object
1199 private Action
getPreviousEventAction() {
1200 if (fPrevEventAction
== null) {
1201 fPrevEventAction
= new Action() {
1204 TimeGraphViewer viewer
= fTimeGraphCombo
.getTimeGraphViewer();
1205 ITimeGraphEntry entry
= viewer
.getSelection();
1206 if (entry
instanceof CallStackEntry
) {
1208 CallStackEntry callStackEntry
= (CallStackEntry
) entry
;
1209 ITmfStateSystem ss
= callStackEntry
.getStateSystem();
1210 long time
= Math
.max(ss
.getStartTime(), Math
.min(ss
.getCurrentEndTime(), viewer
.getSelectionBegin()));
1211 ThreadEntry threadEntry
= (ThreadEntry
) callStackEntry
.getParent();
1212 int quark
= ss
.getParentAttributeQuark(callStackEntry
.getQuark());
1213 ITmfStateInterval stackInterval
= ss
.querySingleState(time
, quark
);
1214 if (stackInterval
.getStartTime() == time
&& time
> ss
.getStartTime()) {
1215 stackInterval
= ss
.querySingleState(time
- 1, quark
);
1217 viewer
.setSelectedTimeNotify(stackInterval
.getStartTime(), true);
1218 int stackLevel
= stackInterval
.getStateValue().unboxInt();
1219 ITimeGraphEntry selectedEntry
= threadEntry
.getChildren().get(Math
.max(0, stackLevel
- 1));
1220 fTimeGraphCombo
.setSelection(selectedEntry
);
1221 viewer
.getTimeGraphControl().fireSelectionChanged();
1222 startZoomThread(viewer
.getTime0(), viewer
.getTime1());
1224 } catch (AttributeNotFoundException e
) {
1225 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1226 } catch (TimeRangeException e
) {
1227 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1228 } catch (StateSystemDisposedException e
) {
1229 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1230 } catch (StateValueTypeException e
) {
1231 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1237 fPrevEventAction
.setText(Messages
.TmfTimeGraphViewer_PreviousEventActionNameText
);
1238 fPrevEventAction
.setToolTipText(Messages
.TmfTimeGraphViewer_PreviousEventActionToolTipText
);
1239 fPrevEventAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(ITmfImageConstants
.IMG_UI_PREV_EVENT
));
1242 return fPrevEventAction
;
1245 private static @Nullable AbstractCallStackAnalysis
getCallStackModule(ITmfTrace trace
) {
1247 * Since we cannot know the exact analysis ID (in separate plugins), we
1248 * will search using the analysis type.
1250 Iterable
<AbstractCallStackAnalysis
> modules
=
1251 trace
.getAnalysisModulesOfClass(AbstractCallStackAnalysis
.class);
1252 Iterator
<AbstractCallStackAnalysis
> it
= modules
.iterator();
1253 if (!it
.hasNext()) {
1254 /* This trace does not provide a call-stack analysis */
1259 * We only look at the first module we find.
1261 * TODO Handle the advanced case where one trace provides more than one
1262 * call-stack analysis.
1264 AbstractCallStackAnalysis module
= it
.next();
1265 /* This analysis is not automatic, we need to schedule it on-demand */
1267 module
.waitForInitialization();
1271 // ------------------------------------------------------------------------
1272 // Methods related to function name mapping
1273 // ------------------------------------------------------------------------
1276 * Common code for all import file mapping actions
1278 private abstract class AbstractImportFileMappingAction
extends Action
{
1279 private final String fDialogTitle
;
1281 private AbstractImportFileMappingAction(String dialogTitle
) {
1282 fDialogTitle
= dialogTitle
;
1287 FileDialog dialog
= new FileDialog(getViewSite().getShell());
1288 dialog
.setText(fDialogTitle
);
1289 final String filePath
= dialog
.open();
1290 if (filePath
== null) {
1291 /* No file was selected, don't change anything */
1296 * Start the mapping import in a separate thread (we do not want
1297 * to UI thread to do this).
1299 Job job
= new Job(Messages
.CallStackView_ImportMappingJobName
) {
1301 public IStatus
run(IProgressMonitor monitor
) {
1302 fNameMapping
= doMapping(new File(filePath
));
1304 /* Refresh the time graph and the list of entries */
1305 buildThreadList(fTrace
, new NullProgressMonitor());
1308 return Status
.OK_STATUS
;
1314 abstract Map
<String
, String
> doMapping(File file
);
1318 * Toolbar icon to import the function address-to-name mapping file.
1320 private Action
getImportMappingAction() {
1321 if (fImportMappingAction
!= null) {
1322 return fImportMappingAction
;
1324 fImportMappingAction
= new AbstractImportFileMappingAction(Messages
.CallStackView_ImportMappingDialogTitle
) {
1326 Map
<String
, String
> doMapping(File file
) {
1327 return FunctionNameMapper
.mapFromNmTextFile(file
);
1331 fImportMappingAction
.setText(Messages
.CallStackView_ImportMappingButtonText
);
1332 fImportMappingAction
.setToolTipText(Messages
.CallStackView_ImportMappingButtonTooltip
);
1333 fImportMappingAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(IMPORT_MAPPING_ICON_PATH
));
1335 return fImportMappingAction
;
1338 private Action
getSortByNameAction() {
1339 if (fSortByNameAction
== null) {
1340 fSortByNameAction
= new Action(Messages
.CallStackView_SortByThreadName
, IAction
.AS_CHECK_BOX
) {
1343 if (fSortOption
== SortOption
.BY_NAME
) {
1344 saveSortOption(SortOption
.BY_NAME_REV
);
1346 saveSortOption(SortOption
.BY_NAME
);
1350 fSortByNameAction
.setToolTipText(Messages
.CallStackView_SortByThreadName
);
1351 fSortByNameAction
.setImageDescriptor(SORT_BY_NAME_ICON
);
1353 return fSortByNameAction
;
1356 private Action
getSortByIdAction() {
1357 if (fSortByIdAction
== null) {
1358 fSortByIdAction
= new Action(Messages
.CallStackView_SortByThreadId
, IAction
.AS_CHECK_BOX
) {
1361 if (fSortOption
== SortOption
.BY_ID
) {
1362 saveSortOption(SortOption
.BY_ID_REV
);
1364 saveSortOption(SortOption
.BY_ID
);
1368 fSortByIdAction
.setToolTipText(Messages
.CallStackView_SortByThreadId
);
1369 fSortByIdAction
.setImageDescriptor(SORT_BY_ID_ICON
);
1371 return fSortByIdAction
;
1374 private Action
getSortByTimeAction() {
1375 if (fSortByTimeAction
== null) {
1376 fSortByTimeAction
= new Action(Messages
.CallStackView_SortByThreadTime
, IAction
.AS_CHECK_BOX
) {
1379 if (fSortOption
== SortOption
.BY_TIME
) {
1380 saveSortOption(SortOption
.BY_TIME_REV
);
1382 saveSortOption(SortOption
.BY_TIME
);
1386 fSortByTimeAction
.setToolTipText(Messages
.CallStackView_SortByThreadTime
);
1387 fSortByTimeAction
.setImageDescriptor(SORT_BY_TIME_ICON
);
1389 return fSortByTimeAction
;
1392 private void loadSortOption() {
1393 IDialogSettings settings
= Activator
.getDefault().getDialogSettings();
1394 IDialogSettings section
= settings
.getSection(getClass().getName());
1395 if (section
== null) {
1398 String sortOption
= section
.get(SORT_OPTION_KEY
);
1399 if (sortOption
== null) {
1404 getSortByNameAction().setChecked(false);
1405 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_ICON
);
1406 getSortByIdAction().setChecked(false);
1407 getSortByIdAction().setImageDescriptor(SORT_BY_ID_ICON
);
1408 getSortByTimeAction().setChecked(false);
1409 getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_ICON
);
1411 if (sortOption
.equals(SortOption
.BY_NAME
.name())) {
1412 fSortOption
= SortOption
.BY_NAME
;
1413 fThreadComparator
= new ThreadNameComparator(false);
1414 getSortByNameAction().setChecked(true);
1415 } else if (sortOption
.equals(SortOption
.BY_NAME_REV
.name())) {
1416 fSortOption
= SortOption
.BY_NAME_REV
;
1417 fThreadComparator
= new ThreadNameComparator(true);
1418 getSortByNameAction().setChecked(true);
1419 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_REV_ICON
);
1420 } else if (sortOption
.equals(SortOption
.BY_ID
.name())) {
1421 fSortOption
= SortOption
.BY_ID
;
1422 fThreadComparator
= new ThreadIdComparator(false);
1423 getSortByIdAction().setChecked(true);
1424 } else if (sortOption
.equals(SortOption
.BY_ID_REV
.name())) {
1425 fSortOption
= SortOption
.BY_ID_REV
;
1426 fThreadComparator
= new ThreadIdComparator(true);
1427 getSortByIdAction().setChecked(true);
1428 getSortByIdAction().setImageDescriptor(SORT_BY_ID_REV_ICON
);
1429 } else if (sortOption
.equals(SortOption
.BY_TIME
.name())) {
1430 fSortOption
= SortOption
.BY_TIME
;
1431 fThreadComparator
= new ThreadTimeComparator(false);
1432 getSortByTimeAction().setChecked(true);
1433 } else if (sortOption
.equals(SortOption
.BY_TIME_REV
.name())) {
1434 fSortOption
= SortOption
.BY_TIME_REV
;
1435 fThreadComparator
= new ThreadTimeComparator(true);
1436 getSortByTimeAction().setChecked(true);
1437 getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_REV_ICON
);
1441 private void saveSortOption(SortOption sortOption
) {
1442 IDialogSettings settings
= Activator
.getDefault().getDialogSettings();
1443 IDialogSettings section
= settings
.getSection(getClass().getName());
1444 if (section
== null) {
1445 section
= settings
.addNewSection(getClass().getName());
1447 section
.put(SORT_OPTION_KEY
, sortOption
.name());
1449 if (fEntryList
== null) {
1452 for (TraceEntry traceEntry
: fEntryList
) {
1453 traceEntry
.sortChildren(fThreadComparator
);
1459 * Toolbar icon to import the function address-to-name mapping binary file.
1461 private Action
getImportBinaryAction() {
1462 if (fImportBinaryFileMappingAction
!= null) {
1463 return fImportBinaryFileMappingAction
;
1466 fImportBinaryFileMappingAction
= new AbstractImportFileMappingAction(Messages
.CallStackView_ImportBinaryFileDialogTitle
) {
1468 Map
<String
, String
> doMapping(File file
) {
1469 return FunctionNameMapper
.mapFromBinaryFile(file
);
1473 fImportBinaryFileMappingAction
.setText(Messages
.CallStackView_ImportBinaryFileButtonText
);
1474 fImportBinaryFileMappingAction
.setToolTipText(Messages
.CallStackView_ImportBinaryFileButtonTooltip
);
1475 fImportBinaryFileMappingAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(IMPORT_BINARY_ICON_PATH
));
1477 return fImportBinaryFileMappingAction
;
1480 String
getFunctionName(String address
) {
1481 if (fNameMapping
== null) {
1482 /* No mapping available, just print the addresses */
1485 String ret
= fNameMapping
.get(address
);
1487 /* We didn't find this address in the mapping file, just use the address */