1 /*******************************************************************************
2 * Copyright (c) 2013, 2015 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
.tracecompass
.tmf
.ui
.views
.callstack
;
17 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
20 import java
.util
.ArrayList
;
21 import java
.util
.Collections
;
22 import java
.util
.Comparator
;
23 import java
.util
.HashMap
;
24 import java
.util
.Iterator
;
25 import java
.util
.List
;
27 import java
.util
.concurrent
.CopyOnWriteArrayList
;
29 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
30 import org
.eclipse
.core
.runtime
.IStatus
;
31 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
32 import org
.eclipse
.core
.runtime
.Status
;
33 import org
.eclipse
.core
.runtime
.jobs
.Job
;
34 import org
.eclipse
.jdt
.annotation
.NonNull
;
35 import org
.eclipse
.jdt
.annotation
.Nullable
;
36 import org
.eclipse
.jface
.action
.Action
;
37 import org
.eclipse
.jface
.action
.IAction
;
38 import org
.eclipse
.jface
.action
.IStatusLineManager
;
39 import org
.eclipse
.jface
.action
.IToolBarManager
;
40 import org
.eclipse
.jface
.action
.MenuManager
;
41 import org
.eclipse
.jface
.action
.Separator
;
42 import org
.eclipse
.jface
.dialogs
.IDialogSettings
;
43 import org
.eclipse
.jface
.resource
.ImageDescriptor
;
44 import org
.eclipse
.jface
.util
.IPropertyChangeListener
;
45 import org
.eclipse
.jface
.util
.PropertyChangeEvent
;
46 import org
.eclipse
.jface
.viewers
.DoubleClickEvent
;
47 import org
.eclipse
.jface
.viewers
.IDoubleClickListener
;
48 import org
.eclipse
.jface
.viewers
.ILabelProviderListener
;
49 import org
.eclipse
.jface
.viewers
.ISelection
;
50 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
51 import org
.eclipse
.jface
.viewers
.ITableLabelProvider
;
52 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
53 import org
.eclipse
.jface
.viewers
.Viewer
;
54 import org
.eclipse
.swt
.SWT
;
55 import org
.eclipse
.swt
.events
.ControlAdapter
;
56 import org
.eclipse
.swt
.events
.ControlEvent
;
57 import org
.eclipse
.swt
.events
.MouseAdapter
;
58 import org
.eclipse
.swt
.events
.MouseEvent
;
59 import org
.eclipse
.swt
.graphics
.Image
;
60 import org
.eclipse
.swt
.widgets
.Composite
;
61 import org
.eclipse
.swt
.widgets
.Display
;
62 import org
.eclipse
.swt
.widgets
.FileDialog
;
63 import org
.eclipse
.swt
.widgets
.Menu
;
64 import org
.eclipse
.swt
.widgets
.Tree
;
65 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.callstack
.FunctionNameMapper
;
66 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Activator
;
67 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.ITmfImageConstants
;
68 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Messages
;
69 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystem
;
70 import org
.eclipse
.tracecompass
.statesystem
.core
.StateSystemUtils
;
71 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
72 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateSystemDisposedException
;
73 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateValueTypeException
;
74 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.TimeRangeException
;
75 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
76 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
77 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
.Type
;
78 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfWindowRangeUpdatedSignal
;
79 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
80 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSelectionRangeUpdatedSignal
;
81 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceClosedSignal
;
82 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
83 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
84 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
85 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfNanoTimestamp
;
86 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimeRange
;
87 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestamp
;
88 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestampDelta
;
89 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
90 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceContext
;
91 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceManager
;
92 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceUtils
;
93 import org
.eclipse
.tracecompass
.tmf
.ui
.editors
.ITmfTraceEditor
;
94 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.TmfView
;
95 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphContentProvider
;
96 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphRangeListener
;
97 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphTimeListener
;
98 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphCombo
;
99 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphRangeUpdateEvent
;
100 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphTimeEvent
;
101 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphViewer
;
102 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
103 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
104 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.NullTimeEvent
;
105 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.TimeEvent
;
106 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.TimeGraphEntry
;
107 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphControl
;
108 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphSelection
;
109 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.TimeFormat
;
110 import org
.eclipse
.ui
.IActionBars
;
111 import org
.eclipse
.ui
.IEditorPart
;
114 * Main implementation for the Call Stack view
116 * @author Patrick Tasse
118 public class CallStackView
extends TmfView
{
120 // ------------------------------------------------------------------------
122 // ------------------------------------------------------------------------
125 public static final String ID
= "org.eclipse.linuxtools.tmf.ui.views.callstack"; //$NON-NLS-1$
134 private static final String
[] COLUMN_TIMES
= new String
[] {
135 Messages
.CallStackView_FunctionColumn
,
136 Messages
.CallStackView_DepthColumn
,
137 Messages
.CallStackView_EntryTimeColumn
,
138 Messages
.CallStackView_ExitTimeColumn
,
139 Messages
.CallStackView_DurationColumn
142 private static final int[] COLUMN_WIDTHS
= new int[] {
150 /** Timeout between updates in the build thread in ms */
151 private static final long BUILD_UPDATE_TIMEOUT
= 500;
153 // Fraction of a function duration to be added as spacing
154 private static final double SPACING_RATIO
= 0.01;
156 private static final Image THREAD_IMAGE
= Activator
.getDefault().getImageFromPath("icons/obj16/thread_obj.gif"); //$NON-NLS-1$
157 private static final Image STACKFRAME_IMAGE
= Activator
.getDefault().getImageFromPath("icons/obj16/stckframe_obj.gif"); //$NON-NLS-1$
159 private static final String IMPORT_MAPPING_ICON_PATH
= "icons/etool16/import.gif"; //$NON-NLS-1$
160 private static final String IMPORT_BINARY_ICON_PATH
= "icons/obj16/binaries_obj.gif"; //$NON-NLS-1$
162 private static final ImageDescriptor SORT_BY_NAME_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha.gif"); //$NON-NLS-1$
163 private static final ImageDescriptor SORT_BY_NAME_REV_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha_rev.gif"); //$NON-NLS-1$
164 private static final ImageDescriptor SORT_BY_ID_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_num.gif"); //$NON-NLS-1$
165 private static final ImageDescriptor SORT_BY_ID_REV_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_num_rev.gif"); //$NON-NLS-1$
166 private static final ImageDescriptor SORT_BY_TIME_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_time.gif"); //$NON-NLS-1$
167 private static final ImageDescriptor SORT_BY_TIME_REV_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_time_rev.gif"); //$NON-NLS-1$
168 private static final String SORT_OPTION_KEY
= "sort.option"; //$NON-NLS-1$
170 private enum SortOption
{
171 BY_NAME
, BY_NAME_REV
, BY_ID
, BY_ID_REV
, BY_TIME
, BY_TIME_REV
174 private SortOption fSortOption
;
175 private Comparator
<ITimeGraphEntry
> fThreadComparator
= null;
176 private Action fSortByNameAction
;
177 private Action fSortByIdAction
;
178 private Action fSortByTimeAction
;
180 // ------------------------------------------------------------------------
182 // ------------------------------------------------------------------------
184 // The time graph combo
185 private TimeGraphCombo fTimeGraphCombo
;
187 // The selected trace
188 private ITmfTrace fTrace
;
190 // The selected thread map
191 private final Map
<ITmfTrace
, String
> fSelectedThreadMap
= new HashMap
<>();
193 // The time graph entry list
194 private List
<TraceEntry
> fEntryList
;
196 // The trace to entry list hash map
197 private final Map
<ITmfTrace
, List
<TraceEntry
>> fEntryListMap
= new HashMap
<>();
199 // The trace to build thread hash map
200 private final Map
<ITmfTrace
, BuildThread
> fBuildThreadMap
= new HashMap
<>();
202 /** The map to map function addresses to function names */
203 private Map
<String
, String
> fNameMapping
;
206 private long fStartTime
;
209 private long fEndTime
;
212 private int fDisplayWidth
;
214 // The next event action
215 private Action fNextEventAction
;
217 // The previous event action
218 private Action fPrevEventAction
;
220 // The next item action
221 private Action fNextItemAction
;
223 // The previous item action
224 private Action fPreviousItemAction
;
226 // The action to import a function-name mapping file
227 private Action fImportMappingAction
;
229 // The action to import a binary file mapping */
230 private Action fImportBinaryFileMappingAction
;
233 private ZoomThread fZoomThread
;
235 // The redraw state used to prevent unnecessary queuing of display runnables
236 private State fRedrawState
= State
.IDLE
;
238 // The redraw synchronization object
239 private final Object fSyncObj
= new Object();
241 // The saved time sync. signal used when switching off the pinning of a view
242 private TmfSelectionRangeUpdatedSignal fSavedTimeSyncSignal
;
244 // The saved window range signal used when switching off the pinning of
246 private TmfWindowRangeUpdatedSignal fSavedRangeSyncSignal
;
248 // ------------------------------------------------------------------------
250 // ------------------------------------------------------------------------
252 private class TraceEntry
extends TimeGraphEntry
{
253 public TraceEntry(String name
, long startTime
, long endTime
) {
254 super(name
, startTime
, endTime
);
258 public boolean hasTimeEvents() {
263 private class ThreadEntry
extends TimeGraphEntry
{
264 // The call stack quark
265 private final int fCallStackQuark
;
266 // The state system from which this entry comes
267 private final ITmfStateSystem fSS
;
269 private final long fThreadId
;
271 public ThreadEntry(ITmfStateSystem ss
, String name
, long threadId
, int callStackQuark
, long startTime
, long endTime
) {
272 super(name
, startTime
, endTime
);
273 fCallStackQuark
= callStackQuark
;
274 fThreadId
= threadId
;
279 public boolean hasTimeEvents() {
283 public int getCallStackQuark() {
284 return fCallStackQuark
;
287 public long getThreadId() {
292 public ITmfStateSystem
getStateSystem() {
297 private class ThreadNameComparator
implements Comparator
<ITimeGraphEntry
> {
298 private boolean reverse
;
300 public ThreadNameComparator(boolean reverse
) {
301 this.reverse
= reverse
;
305 public int compare(ITimeGraphEntry o1
, ITimeGraphEntry o2
) {
306 return reverse ? o2
.getName().compareTo(o1
.getName()) :
307 o1
.getName().compareTo(o2
.getName());
311 private class ThreadIdComparator
implements Comparator
<ITimeGraphEntry
> {
312 private boolean reverse
;
314 public ThreadIdComparator(boolean reverse
) {
315 this.reverse
= reverse
;
319 public int compare(ITimeGraphEntry o1
, ITimeGraphEntry o2
) {
320 ThreadEntry t1
= (ThreadEntry
) o1
;
321 ThreadEntry t2
= (ThreadEntry
) o2
;
322 return reverse ? Long
.compare(t2
.getThreadId(), t1
.getThreadId()) :
323 Long
.compare(t1
.getThreadId(), t2
.getThreadId());
327 private class ThreadTimeComparator
implements Comparator
<ITimeGraphEntry
> {
328 private boolean reverse
;
330 public ThreadTimeComparator(boolean reverse
) {
331 this.reverse
= reverse
;
335 public int compare(ITimeGraphEntry o1
, ITimeGraphEntry o2
) {
336 return reverse ? Long
.compare(o2
.getStartTime(), o1
.getStartTime()) :
337 Long
.compare(o1
.getStartTime(), o2
.getStartTime());
341 private class TreeContentProvider
implements ITreeContentProvider
{
344 public void dispose() {
348 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
352 public Object
[] getElements(Object inputElement
) {
353 if (inputElement
!= null) {
355 return ((List
<?
>) inputElement
).toArray(new ITimeGraphEntry
[0]);
356 } catch (ClassCastException e
) {
359 return new ITimeGraphEntry
[0];
363 public Object
[] getChildren(Object parentElement
) {
364 ITimeGraphEntry entry
= (ITimeGraphEntry
) parentElement
;
365 return entry
.getChildren().toArray();
369 public Object
getParent(Object element
) {
370 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
371 return entry
.getParent();
375 public boolean hasChildren(Object element
) {
376 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
377 return entry
.hasChildren();
382 private class TreeLabelProvider
implements ITableLabelProvider
{
385 public void addListener(ILabelProviderListener listener
) {
389 public void dispose() {
393 public boolean isLabelProperty(Object element
, String property
) {
398 public void removeListener(ILabelProviderListener listener
) {
402 public Image
getColumnImage(Object element
, int columnIndex
) {
403 if (columnIndex
== 0) {
404 if (element
instanceof ThreadEntry
) {
406 } else if (element
instanceof CallStackEntry
) {
407 CallStackEntry entry
= (CallStackEntry
) element
;
408 if (entry
.getFunctionName().length() > 0) {
409 return STACKFRAME_IMAGE
;
417 public String
getColumnText(Object element
, int columnIndex
) {
418 if (element
instanceof CallStackEntry
) {
419 CallStackEntry entry
= (CallStackEntry
) element
;
420 if (columnIndex
== 0) {
421 return entry
.getFunctionName();
422 } else if (columnIndex
== 1 && entry
.getFunctionName().length() > 0) {
423 int depth
= entry
.getStackLevel();
424 return Integer
.toString(depth
);
425 } else if (columnIndex
== 2 && entry
.getFunctionName().length() > 0) {
426 ITmfTimestamp ts
= new TmfTimestamp(entry
.getFunctionEntryTime(), ITmfTimestamp
.NANOSECOND_SCALE
);
427 return ts
.toString();
428 } else if (columnIndex
== 3 && entry
.getFunctionName().length() > 0) {
429 ITmfTimestamp ts
= new TmfTimestamp(entry
.getFunctionExitTime(), ITmfTimestamp
.NANOSECOND_SCALE
);
430 return ts
.toString();
431 } else if (columnIndex
== 4 && entry
.getFunctionName().length() > 0) {
432 ITmfTimestamp ts
= new TmfTimestampDelta(entry
.getFunctionExitTime() - entry
.getFunctionEntryTime(), ITmfTimestamp
.NANOSECOND_SCALE
);
433 return ts
.toString();
435 } else if (element
instanceof ITimeGraphEntry
) {
436 if (columnIndex
== 0) {
437 return ((ITimeGraphEntry
) element
).getName();
440 return ""; //$NON-NLS-1$
445 private class TimeGraphContentProvider
implements ITimeGraphContentProvider
{
448 public ITimeGraphEntry
[] getElements(Object inputElement
) {
449 if (inputElement
!= null) {
451 return ((List
<?
>) inputElement
).toArray(new ITimeGraphEntry
[0]);
452 } catch (ClassCastException e
) {
455 return new ITimeGraphEntry
[0];
460 private class BuildThread
extends Thread
{
461 private final @NonNull ITmfTrace fBuildTrace
;
462 private final ITmfTrace fParentTrace
;
463 private final IProgressMonitor fMonitor
;
465 public BuildThread(@NonNull ITmfTrace trace
, ITmfTrace parentTrace
) {
466 super("CallStackView build"); //$NON-NLS-1$
468 fParentTrace
= parentTrace
;
469 fMonitor
= new NullProgressMonitor();
474 buildThreadList(fBuildTrace
, fParentTrace
, fMonitor
);
475 synchronized (fBuildThreadMap
) {
476 fBuildThreadMap
.remove(fBuildTrace
);
480 public void cancel() {
481 fMonitor
.setCanceled(true);
485 private class ZoomThread
extends Thread
{
486 private final List
<TraceEntry
> fZoomEntryList
;
487 private final long fZoomStartTime
;
488 private final long fZoomEndTime
;
489 private final IProgressMonitor fMonitor
;
491 public ZoomThread(List
<TraceEntry
> entryList
, long startTime
, long endTime
) {
492 super("CallStackView zoom"); //$NON-NLS-1$
493 fZoomEntryList
= entryList
;
494 fZoomStartTime
= startTime
;
495 fZoomEndTime
= endTime
;
496 fMonitor
= new NullProgressMonitor();
501 if (fZoomEntryList
== null) {
504 long resolution
= Math
.max(1, (fZoomEndTime
- fZoomStartTime
) / fDisplayWidth
);
505 for (TraceEntry traceEntry
: fZoomEntryList
) {
506 for (ITimeGraphEntry threadEntry
: traceEntry
.getChildren()) {
507 ITmfStateSystem ss
= ((ThreadEntry
) threadEntry
).getStateSystem();
512 if (ss
.isCancelled()) {
515 for (ITimeGraphEntry child
: threadEntry
.getChildren()) {
516 if (fMonitor
.isCanceled()) {
519 CallStackEntry entry
= (CallStackEntry
) child
;
520 if (fZoomStartTime
<= fStartTime
&& fZoomEndTime
>= fEndTime
) {
521 entry
.setZoomedEventList(null);
523 List
<ITimeEvent
> zoomedEventList
= getEventList(entry
, fZoomStartTime
, fZoomEndTime
, resolution
, fMonitor
);
524 if (zoomedEventList
!= null) {
525 entry
.setZoomedEventList(zoomedEventList
);
534 public void cancel() {
535 fMonitor
.setCanceled(true);
539 // ------------------------------------------------------------------------
541 // ------------------------------------------------------------------------
544 * Default constructor
546 public CallStackView() {
548 fDisplayWidth
= Display
.getDefault().getBounds().width
;
551 // ------------------------------------------------------------------------
553 // ------------------------------------------------------------------------
556 public void createPartControl(Composite parent
) {
557 fTimeGraphCombo
= new TimeGraphCombo(parent
, SWT
.NONE
);
559 fTimeGraphCombo
.setTreeContentProvider(new TreeContentProvider());
561 fTimeGraphCombo
.setTreeLabelProvider(new TreeLabelProvider());
563 fTimeGraphCombo
.setTreeColumns(COLUMN_TIMES
);
565 fTimeGraphCombo
.getTreeViewer().getTree().getColumn(0).setWidth(COLUMN_WIDTHS
[0]);
566 fTimeGraphCombo
.getTreeViewer().getTree().getColumn(1).setWidth(COLUMN_WIDTHS
[1]);
567 fTimeGraphCombo
.getTreeViewer().getTree().getColumn(2).setWidth(COLUMN_WIDTHS
[2]);
568 fTimeGraphCombo
.getTreeViewer().getTree().getColumn(3).setWidth(COLUMN_WIDTHS
[3]);
569 fTimeGraphCombo
.getTreeViewer().getTree().getColumn(4).setWidth(COLUMN_WIDTHS
[4]);
571 fTimeGraphCombo
.setTimeGraphContentProvider(new TimeGraphContentProvider());
572 fTimeGraphCombo
.setTimeGraphProvider(new CallStackPresentationProvider(this));
573 fTimeGraphCombo
.getTimeGraphViewer().setTimeFormat(TimeFormat
.CALENDAR
);
575 fTimeGraphCombo
.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
577 public void timeRangeUpdated(TimeGraphRangeUpdateEvent event
) {
578 long startTime
= event
.getStartTime();
579 long endTime
= event
.getEndTime();
580 TmfTimeRange range
= new TmfTimeRange(new TmfNanoTimestamp(startTime
), new TmfNanoTimestamp(endTime
));
581 broadcast(new TmfWindowRangeUpdatedSignal(CallStackView
.this, range
));
582 startZoomThread(startTime
, endTime
);
586 fTimeGraphCombo
.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
588 public void timeSelected(TimeGraphTimeEvent event
) {
589 long beginTime
= event
.getBeginTime();
590 long endTime
= event
.getEndTime();
591 synchingToTime(beginTime
);
592 broadcast(new TmfSelectionRangeUpdatedSignal(CallStackView
.this, new TmfNanoTimestamp(beginTime
), new TmfNanoTimestamp(endTime
)));
596 fTimeGraphCombo
.getTimeGraphViewer().getControl().addControlListener(new ControlAdapter() {
598 public void controlResized(ControlEvent e
) {
599 fDisplayWidth
= fTimeGraphCombo
.getTimeGraphViewer().getControl().getSize().x
;
600 if (fEntryList
!= null) {
601 startZoomThread(fTimeGraphCombo
.getTimeGraphViewer().getTime0(), fTimeGraphCombo
.getTimeGraphViewer().getTime1());
606 fTimeGraphCombo
.getTreeViewer().addDoubleClickListener(new IDoubleClickListener() {
608 public void doubleClick(DoubleClickEvent event
) {
609 Object selection
= ((IStructuredSelection
) event
.getSelection()).getFirstElement();
610 if (selection
instanceof CallStackEntry
) {
611 CallStackEntry entry
= (CallStackEntry
) selection
;
612 if (entry
.getFunctionName().length() > 0) {
613 long entryTime
= entry
.getFunctionEntryTime();
614 long exitTime
= entry
.getFunctionExitTime();
615 long spacingTime
= (long) ((exitTime
- entryTime
) * SPACING_RATIO
);
616 entryTime
-= spacingTime
;
617 exitTime
+= spacingTime
;
618 TmfTimeRange range
= new TmfTimeRange(new TmfNanoTimestamp(entryTime
), new TmfNanoTimestamp(exitTime
));
619 broadcast(new TmfWindowRangeUpdatedSignal(CallStackView
.this, range
));
620 fTimeGraphCombo
.getTimeGraphViewer().setStartFinishTime(entryTime
, exitTime
);
621 startZoomThread(entryTime
, exitTime
);
627 fTimeGraphCombo
.getTimeGraphViewer().getTimeGraphControl().addMouseListener(new MouseAdapter() {
629 public void mouseDoubleClick(MouseEvent e
) {
630 TimeGraphControl timeGraphControl
= fTimeGraphCombo
.getTimeGraphViewer().getTimeGraphControl();
631 ISelection selection
= timeGraphControl
.getSelection();
632 if (selection
instanceof TimeGraphSelection
) {
633 Object o
= ((TimeGraphSelection
) selection
).getFirstElement();
634 if (o
instanceof CallStackEvent
) {
635 CallStackEvent event
= (CallStackEvent
) o
;
636 long startTime
= event
.getTime();
637 long endTime
= startTime
+ event
.getDuration();
638 long spacingTime
= (long) ((endTime
- startTime
) * SPACING_RATIO
);
639 startTime
-= spacingTime
;
640 endTime
+= spacingTime
;
641 TmfTimeRange range
= new TmfTimeRange(new TmfNanoTimestamp(startTime
), new TmfNanoTimestamp(endTime
));
642 broadcast(new TmfWindowRangeUpdatedSignal(CallStackView
.this, range
));
643 fTimeGraphCombo
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
644 startZoomThread(startTime
, endTime
);
650 IStatusLineManager statusLineManager
= getViewSite().getActionBars().getStatusLineManager();
651 fTimeGraphCombo
.getTimeGraphViewer().getTimeGraphControl().setStatusLineManager(statusLineManager
);
653 // View Action Handling
655 contributeToActionBars();
659 IEditorPart editor
= getSite().getPage().getActiveEditor();
660 if (editor
instanceof ITmfTraceEditor
) {
661 ITmfTrace trace
= ((ITmfTraceEditor
) editor
).getTrace();
663 traceSelected(new TmfTraceSelectedSignal(this, trace
));
669 public void setFocus() {
670 fTimeGraphCombo
.setFocus();
673 // ------------------------------------------------------------------------
675 // ------------------------------------------------------------------------
677 * Handler for the trace opened signal.
680 * The incoming signal
683 public void traceOpened(TmfTraceOpenedSignal signal
) {
684 fTrace
= signal
.getTrace();
689 * Handler for the trace selected signal
692 * The incoming signal
695 public void traceSelected(final TmfTraceSelectedSignal signal
) {
696 if (signal
.getTrace() == fTrace
) {
699 fTrace
= signal
.getTrace();
704 * Trace is closed: clear the data structures and the view
707 * the signal received
710 public void traceClosed(final TmfTraceClosedSignal signal
) {
711 synchronized (fBuildThreadMap
) {
712 for (ITmfTrace trace
: TmfTraceManager
.getTraceSet(signal
.getTrace())) {
713 BuildThread buildThread
= fBuildThreadMap
.remove(trace
);
714 if (buildThread
!= null) {
715 buildThread
.cancel();
719 synchronized (fEntryListMap
) {
720 fEntryListMap
.remove(signal
.getTrace());
722 fSelectedThreadMap
.remove(signal
.getTrace());
723 if (signal
.getTrace() == fTrace
) {
732 * Handler for the selection range signal.
735 * The incoming signal
739 public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal
) {
741 fSavedTimeSyncSignal
= isPinned() ?
new TmfSelectionRangeUpdatedSignal(signal
.getSource(), signal
.getBeginTime(), signal
.getEndTime()) : null;
743 if (signal
.getSource() == this || fTrace
== null || isPinned()) {
746 final long beginTime
= signal
.getBeginTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
747 final long endTime
= signal
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
748 Display
.getDefault().asyncExec(new Runnable() {
751 if (fTimeGraphCombo
.isDisposed()) {
754 if (beginTime
== endTime
) {
755 fTimeGraphCombo
.getTimeGraphViewer().setSelectedTime(beginTime
, true);
757 fTimeGraphCombo
.getTimeGraphViewer().setSelectionRange(beginTime
, endTime
);
759 synchingToTime(beginTime
);
760 startZoomThread(fTimeGraphCombo
.getTimeGraphViewer().getTime0(), fTimeGraphCombo
.getTimeGraphViewer().getTime1());
761 if (fEntryList
== null) {
764 TimeGraphViewer viewer
= fTimeGraphCombo
.getTimeGraphViewer();
765 for (TraceEntry traceEntry
: fEntryList
) {
766 for (ITimeGraphEntry child
: traceEntry
.getChildren()) {
767 ThreadEntry threadEntry
= (ThreadEntry
) child
;
768 ITmfStateSystem ss
= threadEntry
.getStateSystem();
769 if (ss
== null || beginTime
< ss
.getStartTime() || beginTime
> ss
.getCurrentEndTime()) {
773 int quark
= threadEntry
.getCallStackQuark();
774 ITmfStateInterval stackInterval
= ss
.querySingleState(beginTime
, quark
);
775 if (beginTime
== stackInterval
.getStartTime()) {
776 int stackLevel
= stackInterval
.getStateValue().unboxInt();
777 ITimeGraphEntry selectedEntry
= threadEntry
.getChildren().get(Math
.max(0, stackLevel
- 1));
778 fTimeGraphCombo
.setSelection(selectedEntry
);
779 viewer
.getTimeGraphControl().fireSelectionChanged();
782 } catch (AttributeNotFoundException
| TimeRangeException
| StateSystemDisposedException
| StateValueTypeException e
) {
783 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
792 * Handler for the window range signal.
795 * The incoming signal
799 public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal
) {
802 fSavedRangeSyncSignal
=
803 new TmfWindowRangeUpdatedSignal(signal
.getSource(), new TmfTimeRange(signal
.getCurrentRange().getStartTime(), signal
.getCurrentRange().getEndTime()));
805 fSavedTimeSyncSignal
= null;
808 if (signal
.getSource() == this || fTrace
== null || isPinned()) {
811 if (signal
.getCurrentRange().getIntersection(fTrace
.getTimeRange()) == null) {
814 final long startTime
= signal
.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
815 final long endTime
= signal
.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
816 Display
.getDefault().asyncExec(new Runnable() {
819 if (fTimeGraphCombo
.isDisposed()) {
822 fTimeGraphCombo
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
823 startZoomThread(startTime
, endTime
);
828 // ------------------------------------------------------------------------
830 // ------------------------------------------------------------------------
832 private void loadTrace() {
833 synchronized (fEntryListMap
) {
834 fEntryList
= fEntryListMap
.get(fTrace
);
835 if (fEntryList
== null) {
836 fStartTime
= Long
.MAX_VALUE
;
837 fEndTime
= Long
.MIN_VALUE
;
839 synchronized (fBuildThreadMap
) {
840 for (ITmfTrace trace
: TmfTraceManager
.getTraceSet(fTrace
)) {
841 trace
= checkNotNull(trace
);
842 BuildThread buildThread
= new BuildThread(trace
, fTrace
);
843 fBuildThreadMap
.put(trace
, buildThread
);
848 fStartTime
= fTrace
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
849 fEndTime
= fTrace
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
855 private void buildThreadList(final @NonNull ITmfTrace trace
, final ITmfTrace parentTrace
, IProgressMonitor monitor
) {
856 if (monitor
.isCanceled()) {
859 AbstractCallStackAnalysis module
= getCallStackModule(trace
);
860 if (module
== null) {
861 addUnavailableEntry(trace
, parentTrace
);
864 ITmfStateSystem ss
= module
.getStateSystem();
866 addUnavailableEntry(trace
, parentTrace
);
870 Map
<ITmfTrace
, TraceEntry
> traceEntryMap
= new HashMap
<>();
871 Map
<Integer
, ThreadEntry
> threadEntryMap
= new HashMap
<>();
872 String
[] threadPaths
= module
.getThreadsPattern();
874 long start
= ss
.getStartTime();
876 boolean complete
= false;
878 if (monitor
.isCanceled()) {
881 complete
= ss
.waitUntilBuilt(BUILD_UPDATE_TIMEOUT
);
882 if (ss
.isCancelled()) {
885 long end
= ss
.getCurrentEndTime();
886 if (start
== end
&& !complete
) { // when complete execute one last time regardless of end time
889 List
<Integer
> threadQuarks
= ss
.getQuarks(threadPaths
);
890 TraceEntry traceEntry
= traceEntryMap
.get(trace
);
891 if (traceEntry
== null) {
892 traceEntry
= new TraceEntry(trace
.getName(), start
, end
+ 1);
893 traceEntryMap
.put(trace
, traceEntry
);
894 traceEntry
.sortChildren(fThreadComparator
);
895 addToEntryList(parentTrace
, Collections
.singletonList(traceEntry
));
897 traceEntry
.updateEndTime(end
);
899 for (int i
= 0; i
< threadQuarks
.size(); i
++) {
900 if (monitor
.isCanceled()) {
903 int threadQuark
= threadQuarks
.get(i
);
905 String
[] callStackPath
= module
.getCallStackPath();
906 int callStackQuark
= ss
.getQuarkRelative(threadQuark
, callStackPath
);
907 String threadName
= ss
.getAttributeName(threadQuark
);
908 long threadEnd
= end
+ 1;
909 ITmfStateInterval endInterval
= ss
.querySingleState(ss
.getCurrentEndTime(), callStackQuark
);
910 if (endInterval
.getStateValue().isNull() && endInterval
.getStartTime() != ss
.getStartTime()) {
911 threadEnd
= endInterval
.getStartTime();
913 ThreadEntry threadEntry
= threadEntryMap
.get(threadQuark
);
914 if (threadEntry
== null) {
915 long threadId
= ss
.querySingleState(ss
.getCurrentEndTime(), threadQuark
).getStateValue().unboxLong();
916 long threadStart
= start
;
917 ITmfStateInterval startInterval
= ss
.querySingleState(start
, callStackQuark
);
918 if (startInterval
.getStateValue().isNull()) {
919 threadStart
= Math
.min(startInterval
.getEndTime() + 1, end
+ 1);
921 threadEntry
= new ThreadEntry(ss
, threadName
, threadId
, callStackQuark
, threadStart
, threadEnd
);
922 threadEntryMap
.put(threadQuark
, threadEntry
);
923 traceEntry
.addChild(threadEntry
);
925 threadEntry
.updateEndTime(threadEnd
);
928 for (int stackLevelQuark
: ss
.getSubAttributes(callStackQuark
, false)) {
929 if (level
> threadEntry
.getChildren().size()) {
930 CallStackEntry callStackEntry
= new CallStackEntry(threadName
, stackLevelQuark
, level
, trace
, ss
);
931 threadEntry
.addChild(callStackEntry
);
935 } catch (AttributeNotFoundException e
) {
936 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
937 } catch (StateSystemDisposedException e
) {
941 if (parentTrace
== fTrace
) {
942 synchronized (fEntryListMap
) {
943 fStartTime
= Math
.min(fStartTime
, start
);
944 fEndTime
= Math
.max(fEndTime
, end
+ 1);
948 for (ITimeGraphEntry threadEntry
: traceEntry
.getChildren()) {
949 for (ITimeGraphEntry callStackEntry
: threadEntry
.getChildren()) {
950 if (monitor
.isCanceled()) {
953 buildStatusEvents(parentTrace
, (CallStackEntry
) callStackEntry
, monitor
, start
, end
);
960 private void addToEntryList(ITmfTrace trace
, List
<TraceEntry
> list
) {
961 synchronized (fEntryListMap
) {
962 List
<TraceEntry
> entryList
= fEntryListMap
.get(trace
);
963 if (entryList
== null) {
964 fEntryListMap
.put(trace
, new CopyOnWriteArrayList
<>(list
));
966 entryList
.addAll(list
);
971 private void addUnavailableEntry(ITmfTrace trace
, ITmfTrace parentTrace
) {
972 String name
= Messages
.CallStackView_StackInfoNotAvailable
+ ' ' + '(' + trace
.getName() + ')';
973 TraceEntry unavailableEntry
= new TraceEntry(name
, 0, 0);
974 addToEntryList(parentTrace
, Collections
.singletonList(unavailableEntry
));
975 if (parentTrace
== fTrace
) {
980 private void buildStatusEvents(ITmfTrace trace
, CallStackEntry entry
, IProgressMonitor monitor
, long start
, long end
) {
981 ITmfStateSystem ss
= entry
.getStateSystem();
982 long resolution
= Math
.max(1, (end
- ss
.getStartTime()) / fDisplayWidth
);
983 List
<ITimeEvent
> eventList
= getEventList(entry
, start
, end
+ 1, resolution
, monitor
);
984 if (eventList
!= null) {
985 for (ITimeEvent event
: eventList
) {
986 entry
.addEvent(event
);
989 if (trace
== fTrace
) {
994 private static List
<ITimeEvent
> getEventList(CallStackEntry entry
,
995 long startTime
, long endTime
, long resolution
,
996 IProgressMonitor monitor
) {
997 ITmfStateSystem ss
= entry
.getStateSystem();
998 long start
= Math
.max(startTime
, ss
.getStartTime());
999 long end
= Math
.min(endTime
, ss
.getCurrentEndTime() + 1);
1003 List
<ITimeEvent
> eventList
= null;
1005 List
<ITmfStateInterval
> stackIntervals
= StateSystemUtils
.queryHistoryRange(ss
, entry
.getQuark(), start
, end
- 1, resolution
, monitor
);
1006 eventList
= new ArrayList
<>(stackIntervals
.size());
1007 long lastEndTime
= -1;
1008 boolean lastIsNull
= true;
1009 for (ITmfStateInterval statusInterval
: stackIntervals
) {
1010 if (monitor
.isCanceled()) {
1013 long time
= statusInterval
.getStartTime();
1014 long duration
= statusInterval
.getEndTime() - time
+ 1;
1015 if (!statusInterval
.getStateValue().isNull()) {
1016 final int modulo
= CallStackPresentationProvider
.NUM_COLORS
/ 2;
1017 int value
= statusInterval
.getStateValue().toString().hashCode() % modulo
+ modulo
;
1018 eventList
.add(new CallStackEvent(entry
, time
, duration
, value
));
1021 if (lastEndTime
== -1) {
1022 // add null event if it intersects the start time
1023 eventList
.add(new NullTimeEvent(entry
, time
, duration
));
1025 if (lastEndTime
!= time
&& lastIsNull
) {
1026 // add unknown event if between two null states
1027 eventList
.add(new TimeEvent(entry
, lastEndTime
, time
- lastEndTime
));
1029 if (time
+ duration
>= endTime
) {
1030 // add null event if it intersects the end time
1031 eventList
.add(new NullTimeEvent(entry
, time
, duration
));
1036 lastEndTime
= time
+ duration
;
1038 } catch (AttributeNotFoundException e
) {
1039 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1040 } catch (TimeRangeException e
) {
1041 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1042 } catch (StateSystemDisposedException e
) {
1048 private void synchingToTime(long time
) {
1049 if (fEntryList
== null) {
1052 for (TraceEntry traceEntry
: fEntryList
) {
1053 for (ITimeGraphEntry threadEntry
: traceEntry
.getChildren()) {
1054 ITmfStateSystem ss
= ((ThreadEntry
) threadEntry
).getStateSystem();
1058 if (ss
.isCancelled()) {
1061 if (time
< ss
.getStartTime() || time
> ss
.getCurrentEndTime()) {
1064 for (ITimeGraphEntry child
: threadEntry
.getChildren()) {
1065 CallStackEntry callStackEntry
= (CallStackEntry
) child
;
1067 ITmfStateInterval stackLevelInterval
= ss
.querySingleState(time
, callStackEntry
.getQuark());
1068 ITmfStateValue nameValue
= stackLevelInterval
.getStateValue();
1069 String name
= ""; //$NON-NLS-1$
1071 if (nameValue
.getType() == Type
.STRING
) {
1072 String address
= nameValue
.unboxStr();
1073 name
= getFunctionName(address
);
1074 } else if (nameValue
.getType() == Type
.INTEGER
) {
1075 name
= "0x" + Integer
.toHexString(nameValue
.unboxInt()); //$NON-NLS-1$
1076 } else if (nameValue
.getType() == Type
.LONG
) {
1077 name
= "0x" + Long
.toHexString(nameValue
.unboxLong()); //$NON-NLS-1$
1079 } catch (StateValueTypeException e
) {
1081 callStackEntry
.setFunctionName(name
);
1082 if (name
.length() > 0) {
1083 callStackEntry
.setFunctionEntryTime(stackLevelInterval
.getStartTime());
1084 callStackEntry
.setFunctionExitTime(stackLevelInterval
.getEndTime() + 1);
1086 } catch (AttributeNotFoundException e
) {
1087 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1088 } catch (StateSystemDisposedException e
) {
1094 fTimeGraphCombo
.refresh();
1097 private void refresh() {
1098 Display
.getDefault().asyncExec(new Runnable() {
1101 if (fTimeGraphCombo
.isDisposed()) {
1104 synchronized (fEntryListMap
) {
1105 fEntryList
= fEntryListMap
.get(fTrace
);
1106 if (fEntryList
== null) {
1107 fEntryList
= new ArrayList
<>();
1109 for (TraceEntry traceEntry
: fEntryList
) {
1110 traceEntry
.sortChildren(fThreadComparator
);
1113 if (fEntryList
!= fTimeGraphCombo
.getInput()) {
1114 fTimeGraphCombo
.setInput(fEntryList
);
1116 fTimeGraphCombo
.refresh();
1118 fTimeGraphCombo
.getTimeGraphViewer().setTimeBounds(fStartTime
, fEndTime
);
1120 TmfTraceContext ctx
= TmfTraceManager
.getInstance().getCurrentTraceContext();
1121 long selectionBeginTime
= fTrace
== null ?
0 : ctx
.getSelectionRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1122 long selectionEndTime
= fTrace
== null ?
0 : ctx
.getSelectionRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1123 long startTime
= fTrace
== null ?
0 : ctx
.getWindowRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1124 long endTime
= fTrace
== null ?
0 : ctx
.getWindowRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1125 startTime
= Math
.max(startTime
, fStartTime
);
1126 endTime
= Math
.min(endTime
, fEndTime
);
1127 fTimeGraphCombo
.getTimeGraphViewer().setSelectionRange(selectionBeginTime
, selectionEndTime
);
1128 synchingToTime(selectionBeginTime
);
1129 fTimeGraphCombo
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
1130 startZoomThread(startTime
, endTime
);
1135 private void redraw() {
1136 synchronized (fSyncObj
) {
1137 if (fRedrawState
== State
.IDLE
) {
1138 fRedrawState
= State
.BUSY
;
1140 fRedrawState
= State
.PENDING
;
1144 Display
.getDefault().asyncExec(new Runnable() {
1147 if (fTimeGraphCombo
.isDisposed()) {
1150 fTimeGraphCombo
.redraw();
1151 fTimeGraphCombo
.update();
1152 synchronized (fSyncObj
) {
1153 if (fRedrawState
== State
.PENDING
) {
1154 fRedrawState
= State
.IDLE
;
1157 fRedrawState
= State
.IDLE
;
1164 private void startZoomThread(long startTime
, long endTime
) {
1165 if (fZoomThread
!= null) {
1166 fZoomThread
.cancel();
1168 fZoomThread
= new ZoomThread(fEntryList
, startTime
, endTime
);
1169 fZoomThread
.start();
1172 private void makeActions() {
1173 fPreviousItemAction
= fTimeGraphCombo
.getTimeGraphViewer().getPreviousItemAction();
1174 fPreviousItemAction
.setText(Messages
.TmfTimeGraphViewer_PreviousItemActionNameText
);
1175 fPreviousItemAction
.setToolTipText(Messages
.TmfTimeGraphViewer_PreviousItemActionToolTipText
);
1176 fNextItemAction
= fTimeGraphCombo
.getTimeGraphViewer().getNextItemAction();
1177 fNextItemAction
.setText(Messages
.TmfTimeGraphViewer_NextItemActionNameText
);
1178 fNextItemAction
.setToolTipText(Messages
.TmfTimeGraphViewer_NextItemActionToolTipText
);
1181 private void contributeToActionBars() {
1182 IActionBars bars
= getViewSite().getActionBars();
1183 fillLocalToolBar(bars
.getToolBarManager());
1185 // Create pin action
1186 contributePinActionToToolBar();
1187 fPinAction
.addPropertyChangeListener(new IPropertyChangeListener() {
1189 public void propertyChange(PropertyChangeEvent event
) {
1190 if (IAction
.CHECKED
.equals(event
.getProperty()) && !isPinned()) {
1191 if (fSavedRangeSyncSignal
!= null) {
1192 windowRangeUpdated(fSavedRangeSyncSignal
);
1193 fSavedRangeSyncSignal
= null;
1196 if (fSavedTimeSyncSignal
!= null) {
1197 selectionRangeUpdated(fSavedTimeSyncSignal
);
1198 fSavedTimeSyncSignal
= null;
1205 private void fillLocalToolBar(IToolBarManager manager
) {
1206 manager
.add(getImportBinaryAction());
1207 manager
.add(getImportMappingAction());
1208 manager
.add(new Separator());
1209 manager
.add(getSortByNameAction());
1210 manager
.add(getSortByIdAction());
1211 manager
.add(getSortByTimeAction());
1212 manager
.add(new Separator());
1213 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getResetScaleAction());
1214 manager
.add(getPreviousEventAction());
1215 manager
.add(getNextEventAction());
1216 manager
.add(fPreviousItemAction
);
1217 manager
.add(fNextItemAction
);
1218 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getZoomInAction());
1219 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getZoomOutAction());
1220 manager
.add(new Separator());
1223 private void createContextMenu() {
1224 final MenuManager contextMenu
= new MenuManager();
1225 contextMenu
.add(getSortByNameAction());
1226 contextMenu
.add(getSortByIdAction());
1227 contextMenu
.add(getSortByTimeAction());
1229 Tree tree
= fTimeGraphCombo
.getTreeViewer().getTree();
1230 Menu menu
= contextMenu
.createContextMenu(tree
);
1235 * Get the the next event action.
1237 * @return The action object
1239 private Action
getNextEventAction() {
1240 if (fNextEventAction
== null) {
1241 fNextEventAction
= new Action() {
1244 TimeGraphViewer viewer
= fTimeGraphCombo
.getTimeGraphViewer();
1245 ITimeGraphEntry entry
= viewer
.getSelection();
1246 if (entry
instanceof CallStackEntry
) {
1248 CallStackEntry callStackEntry
= (CallStackEntry
) entry
;
1249 ITmfStateSystem ss
= callStackEntry
.getStateSystem();
1250 long time
= Math
.max(ss
.getStartTime(), Math
.min(ss
.getCurrentEndTime(), viewer
.getSelectionBegin()));
1251 ThreadEntry threadEntry
= (ThreadEntry
) callStackEntry
.getParent();
1252 int quark
= ss
.getParentAttributeQuark(callStackEntry
.getQuark());
1253 ITmfStateInterval stackInterval
= ss
.querySingleState(time
, quark
);
1254 long newTime
= stackInterval
.getEndTime() + 1;
1255 viewer
.setSelectedTimeNotify(newTime
, true);
1256 stackInterval
= ss
.querySingleState(Math
.min(ss
.getCurrentEndTime(), newTime
), quark
);
1257 int stackLevel
= stackInterval
.getStateValue().unboxInt();
1258 ITimeGraphEntry selectedEntry
= threadEntry
.getChildren().get(Math
.max(0, stackLevel
- 1));
1259 fTimeGraphCombo
.setSelection(selectedEntry
);
1260 viewer
.getTimeGraphControl().fireSelectionChanged();
1261 startZoomThread(viewer
.getTime0(), viewer
.getTime1());
1263 } catch (AttributeNotFoundException
| TimeRangeException
| StateSystemDisposedException
| StateValueTypeException e
) {
1264 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1270 fNextEventAction
.setText(Messages
.TmfTimeGraphViewer_NextEventActionNameText
);
1271 fNextEventAction
.setToolTipText(Messages
.TmfTimeGraphViewer_NextEventActionToolTipText
);
1272 fNextEventAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(ITmfImageConstants
.IMG_UI_NEXT_EVENT
));
1275 return fNextEventAction
;
1279 * Get the previous event action.
1281 * @return The Action object
1283 private Action
getPreviousEventAction() {
1284 if (fPrevEventAction
== null) {
1285 fPrevEventAction
= new Action() {
1288 TimeGraphViewer viewer
= fTimeGraphCombo
.getTimeGraphViewer();
1289 ITimeGraphEntry entry
= viewer
.getSelection();
1290 if (entry
instanceof CallStackEntry
) {
1292 CallStackEntry callStackEntry
= (CallStackEntry
) entry
;
1293 ITmfStateSystem ss
= callStackEntry
.getStateSystem();
1294 long time
= Math
.max(ss
.getStartTime(), Math
.min(ss
.getCurrentEndTime(), viewer
.getSelectionBegin()));
1295 ThreadEntry threadEntry
= (ThreadEntry
) callStackEntry
.getParent();
1296 int quark
= ss
.getParentAttributeQuark(callStackEntry
.getQuark());
1297 ITmfStateInterval stackInterval
= ss
.querySingleState(time
, quark
);
1298 if (stackInterval
.getStartTime() == time
&& time
> ss
.getStartTime()) {
1299 stackInterval
= ss
.querySingleState(time
- 1, quark
);
1301 viewer
.setSelectedTimeNotify(stackInterval
.getStartTime(), true);
1302 int stackLevel
= stackInterval
.getStateValue().unboxInt();
1303 ITimeGraphEntry selectedEntry
= threadEntry
.getChildren().get(Math
.max(0, stackLevel
- 1));
1304 fTimeGraphCombo
.setSelection(selectedEntry
);
1305 viewer
.getTimeGraphControl().fireSelectionChanged();
1306 startZoomThread(viewer
.getTime0(), viewer
.getTime1());
1308 } catch (AttributeNotFoundException
| TimeRangeException
| StateSystemDisposedException
| StateValueTypeException e
) {
1309 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1315 fPrevEventAction
.setText(Messages
.TmfTimeGraphViewer_PreviousEventActionNameText
);
1316 fPrevEventAction
.setToolTipText(Messages
.TmfTimeGraphViewer_PreviousEventActionToolTipText
);
1317 fPrevEventAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(ITmfImageConstants
.IMG_UI_PREV_EVENT
));
1320 return fPrevEventAction
;
1323 private static @Nullable AbstractCallStackAnalysis
getCallStackModule(@NonNull ITmfTrace trace
) {
1325 * Since we cannot know the exact analysis ID (in separate plugins), we
1326 * will search using the analysis type.
1328 Iterable
<AbstractCallStackAnalysis
> modules
=
1329 TmfTraceUtils
.getAnalysisModulesOfClass(trace
, AbstractCallStackAnalysis
.class);
1330 Iterator
<AbstractCallStackAnalysis
> it
= modules
.iterator();
1331 if (!it
.hasNext()) {
1332 /* This trace does not provide a call-stack analysis */
1337 * We only look at the first module we find.
1339 * TODO Handle the advanced case where one trace provides more than one
1340 * call-stack analysis.
1342 AbstractCallStackAnalysis module
= it
.next();
1343 /* This analysis is not automatic, we need to schedule it on-demand */
1345 module
.waitForInitialization();
1349 // ------------------------------------------------------------------------
1350 // Methods related to function name mapping
1351 // ------------------------------------------------------------------------
1354 * Common code for all import file mapping actions
1356 private abstract class AbstractImportFileMappingAction
extends Action
{
1357 private final String fDialogTitle
;
1359 private AbstractImportFileMappingAction(String dialogTitle
) {
1360 fDialogTitle
= dialogTitle
;
1365 FileDialog dialog
= new FileDialog(getViewSite().getShell());
1366 dialog
.setText(fDialogTitle
);
1367 final String filePath
= dialog
.open();
1368 if (filePath
== null) {
1369 /* No file was selected, don't change anything */
1374 * Start the mapping import in a separate thread (we do not want to
1375 * UI thread to do this).
1377 Job job
= new Job(Messages
.CallStackView_ImportMappingJobName
) {
1379 public IStatus
run(IProgressMonitor monitor
) {
1380 fNameMapping
= doMapping(new File(filePath
));
1382 /* Refresh call stack entries and event labels */
1383 Display
.getDefault().asyncExec(new Runnable() {
1386 synchingToTime(fTimeGraphCombo
.getTimeGraphViewer().getSelectionBegin());
1389 return Status
.OK_STATUS
;
1395 abstract Map
<String
, String
> doMapping(File file
);
1399 * Toolbar icon to import the function address-to-name mapping file.
1401 private Action
getImportMappingAction() {
1402 if (fImportMappingAction
!= null) {
1403 return fImportMappingAction
;
1405 fImportMappingAction
= new AbstractImportFileMappingAction(Messages
.CallStackView_ImportMappingDialogTitle
) {
1407 Map
<String
, String
> doMapping(File file
) {
1408 return FunctionNameMapper
.mapFromNmTextFile(file
);
1412 fImportMappingAction
.setText(Messages
.CallStackView_ImportMappingButtonText
);
1413 fImportMappingAction
.setToolTipText(Messages
.CallStackView_ImportMappingButtonTooltip
);
1414 fImportMappingAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(IMPORT_MAPPING_ICON_PATH
));
1416 return fImportMappingAction
;
1419 private Action
getSortByNameAction() {
1420 if (fSortByNameAction
== null) {
1421 fSortByNameAction
= new Action(Messages
.CallStackView_SortByThreadName
, IAction
.AS_CHECK_BOX
) {
1424 if (fSortOption
== SortOption
.BY_NAME
) {
1425 saveSortOption(SortOption
.BY_NAME_REV
);
1427 saveSortOption(SortOption
.BY_NAME
);
1431 fSortByNameAction
.setToolTipText(Messages
.CallStackView_SortByThreadName
);
1432 fSortByNameAction
.setImageDescriptor(SORT_BY_NAME_ICON
);
1434 return fSortByNameAction
;
1437 private Action
getSortByIdAction() {
1438 if (fSortByIdAction
== null) {
1439 fSortByIdAction
= new Action(Messages
.CallStackView_SortByThreadId
, IAction
.AS_CHECK_BOX
) {
1442 if (fSortOption
== SortOption
.BY_ID
) {
1443 saveSortOption(SortOption
.BY_ID_REV
);
1445 saveSortOption(SortOption
.BY_ID
);
1449 fSortByIdAction
.setToolTipText(Messages
.CallStackView_SortByThreadId
);
1450 fSortByIdAction
.setImageDescriptor(SORT_BY_ID_ICON
);
1452 return fSortByIdAction
;
1455 private Action
getSortByTimeAction() {
1456 if (fSortByTimeAction
== null) {
1457 fSortByTimeAction
= new Action(Messages
.CallStackView_SortByThreadTime
, IAction
.AS_CHECK_BOX
) {
1460 if (fSortOption
== SortOption
.BY_TIME
) {
1461 saveSortOption(SortOption
.BY_TIME_REV
);
1463 saveSortOption(SortOption
.BY_TIME
);
1467 fSortByTimeAction
.setToolTipText(Messages
.CallStackView_SortByThreadTime
);
1468 fSortByTimeAction
.setImageDescriptor(SORT_BY_TIME_ICON
);
1470 return fSortByTimeAction
;
1473 private void loadSortOption() {
1474 IDialogSettings settings
= Activator
.getDefault().getDialogSettings();
1475 IDialogSettings section
= settings
.getSection(getClass().getName());
1476 if (section
== null) {
1479 String sortOption
= section
.get(SORT_OPTION_KEY
);
1480 if (sortOption
== null) {
1485 getSortByNameAction().setChecked(false);
1486 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_ICON
);
1487 getSortByIdAction().setChecked(false);
1488 getSortByIdAction().setImageDescriptor(SORT_BY_ID_ICON
);
1489 getSortByTimeAction().setChecked(false);
1490 getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_ICON
);
1492 if (sortOption
.equals(SortOption
.BY_NAME
.name())) {
1493 fSortOption
= SortOption
.BY_NAME
;
1494 fThreadComparator
= new ThreadNameComparator(false);
1495 getSortByNameAction().setChecked(true);
1496 } else if (sortOption
.equals(SortOption
.BY_NAME_REV
.name())) {
1497 fSortOption
= SortOption
.BY_NAME_REV
;
1498 fThreadComparator
= new ThreadNameComparator(true);
1499 getSortByNameAction().setChecked(true);
1500 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_REV_ICON
);
1501 } else if (sortOption
.equals(SortOption
.BY_ID
.name())) {
1502 fSortOption
= SortOption
.BY_ID
;
1503 fThreadComparator
= new ThreadIdComparator(false);
1504 getSortByIdAction().setChecked(true);
1505 } else if (sortOption
.equals(SortOption
.BY_ID_REV
.name())) {
1506 fSortOption
= SortOption
.BY_ID_REV
;
1507 fThreadComparator
= new ThreadIdComparator(true);
1508 getSortByIdAction().setChecked(true);
1509 getSortByIdAction().setImageDescriptor(SORT_BY_ID_REV_ICON
);
1510 } else if (sortOption
.equals(SortOption
.BY_TIME
.name())) {
1511 fSortOption
= SortOption
.BY_TIME
;
1512 fThreadComparator
= new ThreadTimeComparator(false);
1513 getSortByTimeAction().setChecked(true);
1514 } else if (sortOption
.equals(SortOption
.BY_TIME_REV
.name())) {
1515 fSortOption
= SortOption
.BY_TIME_REV
;
1516 fThreadComparator
= new ThreadTimeComparator(true);
1517 getSortByTimeAction().setChecked(true);
1518 getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_REV_ICON
);
1522 private void saveSortOption(SortOption sortOption
) {
1523 IDialogSettings settings
= Activator
.getDefault().getDialogSettings();
1524 IDialogSettings section
= settings
.getSection(getClass().getName());
1525 if (section
== null) {
1526 section
= settings
.addNewSection(getClass().getName());
1528 section
.put(SORT_OPTION_KEY
, sortOption
.name());
1530 if (fEntryList
== null) {
1533 for (TraceEntry traceEntry
: fEntryList
) {
1534 traceEntry
.sortChildren(fThreadComparator
);
1540 * Toolbar icon to import the function address-to-name mapping binary file.
1542 private Action
getImportBinaryAction() {
1543 if (fImportBinaryFileMappingAction
!= null) {
1544 return fImportBinaryFileMappingAction
;
1547 fImportBinaryFileMappingAction
= new AbstractImportFileMappingAction(Messages
.CallStackView_ImportBinaryFileDialogTitle
) {
1549 Map
<String
, String
> doMapping(File file
) {
1550 return FunctionNameMapper
.mapFromBinaryFile(file
);
1554 fImportBinaryFileMappingAction
.setText(Messages
.CallStackView_ImportBinaryFileButtonText
);
1555 fImportBinaryFileMappingAction
.setToolTipText(Messages
.CallStackView_ImportBinaryFileButtonTooltip
);
1556 fImportBinaryFileMappingAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(IMPORT_BINARY_ICON_PATH
));
1558 return fImportBinaryFileMappingAction
;
1561 String
getFunctionName(String address
) {
1562 if (fNameMapping
== null) {
1563 /* No mapping available, just print the addresses */
1566 String ret
= fNameMapping
.get(address
);
1569 * We didn't find this address in the mapping file, just use the