1 /*******************************************************************************
2 * Copyright (c) 2013 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 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.tmf
.ui
.views
.callstack
;
16 import java
.util
.ArrayList
;
17 import java
.util
.HashMap
;
18 import java
.util
.Iterator
;
19 import java
.util
.List
;
22 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
23 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
24 import org
.eclipse
.jface
.action
.Action
;
25 import org
.eclipse
.jface
.action
.IAction
;
26 import org
.eclipse
.jface
.action
.IStatusLineManager
;
27 import org
.eclipse
.jface
.action
.IToolBarManager
;
28 import org
.eclipse
.jface
.action
.Separator
;
29 import org
.eclipse
.jface
.util
.IPropertyChangeListener
;
30 import org
.eclipse
.jface
.util
.PropertyChangeEvent
;
31 import org
.eclipse
.jface
.viewers
.DoubleClickEvent
;
32 import org
.eclipse
.jface
.viewers
.IDoubleClickListener
;
33 import org
.eclipse
.jface
.viewers
.ILabelProviderListener
;
34 import org
.eclipse
.jface
.viewers
.ISelection
;
35 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
36 import org
.eclipse
.jface
.viewers
.ITableLabelProvider
;
37 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
38 import org
.eclipse
.jface
.viewers
.Viewer
;
39 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Activator
;
40 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.ITmfImageConstants
;
41 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Messages
;
42 import org
.eclipse
.linuxtools
.tmf
.core
.callstack
.CallStackStateProvider
;
43 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.AttributeNotFoundException
;
44 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateSystemDisposedException
;
45 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateValueTypeException
;
46 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TimeRangeException
;
47 import org
.eclipse
.linuxtools
.tmf
.core
.interval
.ITmfStateInterval
;
48 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfRangeSynchSignal
;
49 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
50 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTimeSynchSignal
;
51 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceClosedSignal
;
52 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
53 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
54 import org
.eclipse
.linuxtools
.tmf
.core
.statesystem
.ITmfStateSystem
;
55 import org
.eclipse
.linuxtools
.tmf
.core
.statevalue
.ITmfStateValue
;
56 import org
.eclipse
.linuxtools
.tmf
.core
.statevalue
.ITmfStateValue
.Type
;
57 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.ITmfTimestamp
;
58 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfNanoTimestamp
;
59 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimeRange
;
60 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimestamp
;
61 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimestampDelta
;
62 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
63 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfExperiment
;
64 import org
.eclipse
.linuxtools
.tmf
.ui
.editors
.ITmfTraceEditor
;
65 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.TmfView
;
66 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.ITimeGraphRangeListener
;
67 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.ITimeGraphTimeListener
;
68 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphCombo
;
69 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphRangeUpdateEvent
;
70 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphTimeEvent
;
71 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphViewer
;
72 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
73 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
74 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.NullTimeEvent
;
75 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.TimeEvent
;
76 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphControl
;
77 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphSelection
;
78 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.TimeFormat
;
79 import org
.eclipse
.swt
.SWT
;
80 import org
.eclipse
.swt
.events
.ControlAdapter
;
81 import org
.eclipse
.swt
.events
.ControlEvent
;
82 import org
.eclipse
.swt
.events
.MouseAdapter
;
83 import org
.eclipse
.swt
.events
.MouseEvent
;
84 import org
.eclipse
.swt
.graphics
.Image
;
85 import org
.eclipse
.swt
.widgets
.Composite
;
86 import org
.eclipse
.swt
.widgets
.Display
;
87 import org
.eclipse
.ui
.IActionBars
;
88 import org
.eclipse
.ui
.IEditorPart
;
91 * Main implementation for the Call Stack view
93 * @author Patrick Tasse
96 public class CallStackView
extends TmfView
{
98 // ------------------------------------------------------------------------
100 // ------------------------------------------------------------------------
103 public static final String ID
= "org.eclipse.linuxtools.tmf.ui.views.callstack"; //$NON-NLS-1$
108 private enum State
{ IDLE
, BUSY
, PENDING
}
110 private static final String
[] COLUMN_NAMES
= new String
[] {
111 Messages
.CallStackView_FunctionColumn
,
112 Messages
.CallStackView_DepthColumn
,
113 Messages
.CallStackView_EntryTimeColumn
,
114 Messages
.CallStackView_ExitTimeColumn
,
115 Messages
.CallStackView_DurationColumn
118 private static final int[] COLUMN_WIDTHS
= new int[] {
126 // Fraction of a function duration to be added as spacing
127 private static final double SPACING_RATIO
= 0.01;
129 private static final Image THREAD_IMAGE
= Activator
.getDefault().getImageFromPath("icons/obj16/thread_obj.gif"); //$NON-NLS-1$
130 private static final Image STACKFRAME_IMAGE
= Activator
.getDefault().getImageFromPath("icons/obj16/stckframe_obj.gif"); //$NON-NLS-1$
132 // ------------------------------------------------------------------------
134 // ------------------------------------------------------------------------
136 // The time graph combo
137 private TimeGraphCombo fTimeGraphCombo
;
139 // The selected trace
140 private ITmfTrace fTrace
;
142 // The selected thread map
143 private final Map
<ITmfTrace
, String
> fSelectedThreadMap
= new HashMap
<ITmfTrace
, String
>();
145 // The time graph entry list
146 private List
<ThreadEntry
> fEntryList
;
148 // The trace to entry list hash map
149 private final Map
<ITmfTrace
, ArrayList
<ThreadEntry
>> fEntryListMap
= new HashMap
<ITmfTrace
, ArrayList
<ThreadEntry
>>();
151 // The trace to build thread hash map
152 private final Map
<ITmfTrace
, BuildThread
> fBuildThreadMap
= new HashMap
<ITmfTrace
, BuildThread
>();
155 private long fStartTime
;
158 private long fEndTime
;
161 private int fDisplayWidth
;
163 // The next event action
164 private Action fNextEventAction
;
166 // The previous event action
167 private Action fPrevEventAction
;
169 // The next item action
170 private Action fNextItemAction
;
172 // The previous item action
173 private Action fPreviousItemAction
;
176 private ZoomThread fZoomThread
;
178 // The redraw state used to prevent unnecessary queuing of display runnables
179 private State fRedrawState
= State
.IDLE
;
181 // The redraw synchronization object
182 private final Object fSyncObj
= new Object();
184 // The saved time sync. signal used when switching off the pinning of a view
185 private TmfTimeSynchSignal fSavedTimeSyncSignal
;
187 // The saved time range sync. signal used when switching off the pinning of a view
188 private TmfRangeSynchSignal fSavedRangeSyncSignal
;
190 // ------------------------------------------------------------------------
192 // ------------------------------------------------------------------------
194 private class ThreadEntry
implements ITimeGraphEntry
{
196 private final ITmfTrace fThreadTrace
;
198 private final long fTraceStartTime
;
200 private final long fTraceEndTime
;
201 // The children of the entry
202 private ArrayList
<CallStackEntry
> fChildren
;
204 private final String fName
;
205 // The thread attribute quark
206 private final int fThreadQuark
;
208 public ThreadEntry(ITmfTrace trace
, String name
, int threadQuark
, long startTime
, long endTime
) {
209 fThreadTrace
= trace
;
210 fChildren
= new ArrayList
<CallStackEntry
>();
212 fTraceStartTime
= startTime
;
213 fTraceEndTime
= endTime
;
214 fThreadQuark
= threadQuark
;
218 public ITimeGraphEntry
getParent() {
223 public boolean hasChildren() {
224 if (fChildren
== null) {
225 ITmfStateSystem ss
= fThreadTrace
.getStateSystems().get(CallStackStateProvider
.ID
);
227 int eventStackQuark
= ss
.getQuarkRelative(fThreadQuark
, CallStackStateProvider
.CALL_STACK
);
228 ITmfStateInterval eventStackInterval
= ss
.querySingleState(ss
.getStartTime(), eventStackQuark
);
229 return ! eventStackInterval
.getStateValue().isNull() || eventStackInterval
.getEndTime() != ss
.getCurrentEndTime();
230 } catch (AttributeNotFoundException e
) {
231 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
232 } catch (TimeRangeException e
) {
233 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
234 } catch (StateSystemDisposedException e
) {
238 return fChildren
!= null && fChildren
.size() > 0;
242 public List
<CallStackEntry
> getChildren() {
247 public String
getName() {
252 public long getStartTime() {
253 return fTraceStartTime
;
257 public long getEndTime() {
258 return fTraceEndTime
;
262 public boolean hasTimeEvents() {
267 public Iterator
<ITimeEvent
> getTimeEventsIterator() {
272 public <T
extends ITimeEvent
> Iterator
<T
> getTimeEventsIterator(long startTime
, long stopTime
, long visibleDuration
) {
276 public int getThreadQuark() {
280 public ITmfTrace
getTrace() {
284 public void addChild(CallStackEntry entry
) {
285 entry
.setParent(this);
286 fChildren
.add(entry
);
290 private class TreeContentProvider
implements ITreeContentProvider
{
293 public void dispose() {
297 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
301 public Object
[] getElements(Object inputElement
) {
302 return (ITimeGraphEntry
[]) inputElement
;
306 public Object
[] getChildren(Object parentElement
) {
307 ITimeGraphEntry entry
= (ITimeGraphEntry
) parentElement
;
308 return entry
.getChildren().toArray();
312 public Object
getParent(Object element
) {
313 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
314 return entry
.getParent();
318 public boolean hasChildren(Object element
) {
319 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
320 return entry
.hasChildren();
325 private class TreeLabelProvider
implements ITableLabelProvider
{
328 public void addListener(ILabelProviderListener listener
) {
332 public void dispose() {
336 public boolean isLabelProperty(Object element
, String property
) {
341 public void removeListener(ILabelProviderListener listener
) {
345 public Image
getColumnImage(Object element
, int columnIndex
) {
346 if (columnIndex
== 0) {
347 if (element
instanceof ThreadEntry
) {
349 } else if (element
instanceof CallStackEntry
) {
350 CallStackEntry entry
= (CallStackEntry
) element
;
351 if (entry
.getFunctionName().length() > 0) {
352 return STACKFRAME_IMAGE
;
360 public String
getColumnText(Object element
, int columnIndex
) {
361 if (element
instanceof ThreadEntry
) {
362 if (columnIndex
== 0) {
363 return ((ThreadEntry
) element
).getName();
365 } else if (element
instanceof CallStackEntry
) {
366 CallStackEntry entry
= (CallStackEntry
) element
;
367 if (columnIndex
== 0) {
368 return entry
.getFunctionName();
369 } else if (columnIndex
== 1 && entry
.getFunctionName().length() > 0) {
370 int depth
= entry
.getStackLevel();
371 return Integer
.toString(depth
);
372 } else if (columnIndex
== 2 && entry
.getFunctionName().length() > 0) {
373 ITmfTimestamp ts
= new TmfTimestamp(entry
.getStartTime(), ITmfTimestamp
.NANOSECOND_SCALE
);
374 return ts
.toString();
375 } else if (columnIndex
== 3 && entry
.getFunctionName().length() > 0) {
376 ITmfTimestamp ts
= new TmfTimestamp(entry
.getEndTime(), ITmfTimestamp
.NANOSECOND_SCALE
);
377 return ts
.toString();
378 } else if (columnIndex
== 4 && entry
.getFunctionName().length() > 0) {
379 ITmfTimestamp ts
= new TmfTimestampDelta(entry
.getEndTime() - entry
.getStartTime(), ITmfTimestamp
.NANOSECOND_SCALE
);
380 return ts
.toString();
383 return ""; //$NON-NLS-1$
388 private class BuildThread
extends Thread
{
389 private final ITmfTrace fBuildTrace
;
390 private final IProgressMonitor fMonitor
;
392 public BuildThread(ITmfTrace trace
) {
393 super("CallStackView build"); //$NON-NLS-1$
395 fMonitor
= new NullProgressMonitor();
400 buildThreadList(fBuildTrace
, fMonitor
);
401 synchronized (fBuildThreadMap
) {
402 fBuildThreadMap
.remove(this);
406 public void cancel() {
407 fMonitor
.setCanceled(true);
411 private class ZoomThread
extends Thread
{
412 private final List
<ThreadEntry
> fZoomEntryList
;
413 private final long fZoomStartTime
;
414 private final long fZoomEndTime
;
415 private final IProgressMonitor fMonitor
;
417 public ZoomThread(List
<ThreadEntry
> entryList
, long startTime
, long endTime
) {
418 super("ResourcesView zoom"); //$NON-NLS-1$
419 fZoomEntryList
= entryList
;
420 fZoomStartTime
= startTime
;
421 fZoomEndTime
= endTime
;
422 fMonitor
= new NullProgressMonitor();
427 if (fZoomEntryList
== null) {
430 long resolution
= Math
.max(1, (fZoomEndTime
- fZoomStartTime
) / fDisplayWidth
);
431 for (ThreadEntry threadEntry
: fZoomEntryList
) {
432 ITmfStateSystem ss
= threadEntry
.fThreadTrace
.getStateSystems().get(CallStackStateProvider
.ID
);
433 if (ss
== null || !ss
.waitUntilBuilt()) {
436 for (ITimeGraphEntry child
: threadEntry
.getChildren()) {
437 if (fMonitor
.isCanceled()) {
440 CallStackEntry entry
= (CallStackEntry
) child
;
441 if (fZoomStartTime
<= fStartTime
&& fZoomEndTime
>= fEndTime
) {
442 entry
.setZoomedEventList(null);
444 List
<ITimeEvent
> zoomedEventList
= getEventList(entry
, fZoomStartTime
, fZoomEndTime
, resolution
, fMonitor
);
445 if (zoomedEventList
!= null) {
446 entry
.setZoomedEventList(zoomedEventList
);
454 public void cancel() {
455 fMonitor
.setCanceled(true);
459 // ------------------------------------------------------------------------
461 // ------------------------------------------------------------------------
464 * Default constructor
466 public CallStackView() {
468 fDisplayWidth
= Display
.getDefault().getBounds().width
;
471 // ------------------------------------------------------------------------
473 // ------------------------------------------------------------------------
476 public void createPartControl(Composite parent
) {
477 fTimeGraphCombo
= new TimeGraphCombo(parent
, SWT
.NONE
);
479 fTimeGraphCombo
.setTreeContentProvider(new TreeContentProvider());
481 fTimeGraphCombo
.setTreeLabelProvider(new TreeLabelProvider());
483 fTimeGraphCombo
.setTreeColumns(COLUMN_NAMES
);
485 fTimeGraphCombo
.getTreeViewer().getTree().getColumn(0).setWidth(COLUMN_WIDTHS
[0]);
486 fTimeGraphCombo
.getTreeViewer().getTree().getColumn(1).setWidth(COLUMN_WIDTHS
[1]);
487 fTimeGraphCombo
.getTreeViewer().getTree().getColumn(2).setWidth(COLUMN_WIDTHS
[2]);
488 fTimeGraphCombo
.getTreeViewer().getTree().getColumn(3).setWidth(COLUMN_WIDTHS
[3]);
489 fTimeGraphCombo
.getTreeViewer().getTree().getColumn(4).setWidth(COLUMN_WIDTHS
[4]);
491 fTimeGraphCombo
.setTimeGraphProvider(new CallStackPresentationProvider());
492 fTimeGraphCombo
.getTimeGraphViewer().setTimeFormat(TimeFormat
.CALENDAR
);
494 fTimeGraphCombo
.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
496 public void timeRangeUpdated(TimeGraphRangeUpdateEvent event
) {
497 long startTime
= event
.getStartTime();
498 long endTime
= event
.getEndTime();
499 TmfTimeRange range
= new TmfTimeRange(new TmfNanoTimestamp(startTime
), new TmfNanoTimestamp(endTime
));
500 broadcast(new TmfRangeSynchSignal(CallStackView
.this, range
));
501 startZoomThread(startTime
, endTime
);
505 fTimeGraphCombo
.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
507 public void timeSelected(TimeGraphTimeEvent event
) {
508 long beginTime
= event
.getBeginTime();
509 long endTime
= event
.getEndTime();
510 selectTime(beginTime
);
511 broadcast(new TmfTimeSynchSignal(CallStackView
.this, new TmfNanoTimestamp(beginTime
), new TmfNanoTimestamp(endTime
)));
515 fTimeGraphCombo
.getTimeGraphViewer().getControl().addControlListener(new ControlAdapter() {
517 public void controlResized(ControlEvent e
) {
518 fDisplayWidth
= fTimeGraphCombo
.getTimeGraphViewer().getControl().getSize().x
;
519 if (fEntryList
!= null) {
520 startZoomThread(fTimeGraphCombo
.getTimeGraphViewer().getTime0(), fTimeGraphCombo
.getTimeGraphViewer().getTime1());
525 fTimeGraphCombo
.getTreeViewer().addDoubleClickListener(new IDoubleClickListener() {
527 public void doubleClick(DoubleClickEvent event
) {
528 Object selection
= ((IStructuredSelection
) event
.getSelection()).getFirstElement();
529 if (selection
instanceof CallStackEntry
) {
530 CallStackEntry entry
= (CallStackEntry
) selection
;
531 if (entry
.getFunctionName().length() > 0) {
532 long startTime
= entry
.getStartTime();
533 long endTime
= entry
.getEndTime();
534 long spacingTime
= (long) ((endTime
- startTime
) * SPACING_RATIO
);
535 startTime
-= spacingTime
;
536 endTime
+= spacingTime
;
537 TmfTimeRange range
= new TmfTimeRange(new TmfNanoTimestamp(startTime
), new TmfNanoTimestamp(endTime
));
538 broadcast(new TmfRangeSynchSignal(CallStackView
.this, range
));
539 fTimeGraphCombo
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
540 startZoomThread(startTime
, endTime
);
546 fTimeGraphCombo
.getTimeGraphViewer().getTimeGraphControl().addMouseListener(new MouseAdapter() {
548 public void mouseDoubleClick(MouseEvent e
) {
549 TimeGraphControl timeGraphControl
= fTimeGraphCombo
.getTimeGraphViewer().getTimeGraphControl();
550 ISelection selection
= timeGraphControl
.getSelection();
551 if (selection
instanceof TimeGraphSelection
) {
552 Object o
= ((TimeGraphSelection
) selection
).getFirstElement();
553 if (o
instanceof CallStackEvent
) {
554 CallStackEvent event
= (CallStackEvent
) o
;
555 long startTime
= event
.getTime();
556 long endTime
= startTime
+ event
.getDuration();
557 long spacingTime
= (long) ((endTime
- startTime
) * SPACING_RATIO
);
558 startTime
-= spacingTime
;
559 endTime
+= spacingTime
;
560 TmfTimeRange range
= new TmfTimeRange(new TmfNanoTimestamp(startTime
), new TmfNanoTimestamp(endTime
));
561 broadcast(new TmfRangeSynchSignal(CallStackView
.this, range
));
562 fTimeGraphCombo
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
563 startZoomThread(startTime
, endTime
);
569 IStatusLineManager statusLineManager
= getViewSite().getActionBars().getStatusLineManager();
570 fTimeGraphCombo
.getTimeGraphViewer().getTimeGraphControl().setStatusLineManager(statusLineManager
);
572 // View Action Handling
574 contributeToActionBars();
576 IEditorPart editor
= getSite().getPage().getActiveEditor();
577 if (editor
instanceof ITmfTraceEditor
) {
578 ITmfTrace trace
= ((ITmfTraceEditor
) editor
).getTrace();
580 traceSelected(new TmfTraceSelectedSignal(this, trace
));
586 public void setFocus() {
587 fTimeGraphCombo
.setFocus();
590 // ------------------------------------------------------------------------
592 // ------------------------------------------------------------------------
594 * Handler for the trace opened signal.
596 * The incoming signal
600 public void traceOpened(TmfTraceOpenedSignal signal
) {
601 fTrace
= signal
.getTrace();
606 * Handler for the trace selected signal
609 * The incoming signal
612 public void traceSelected(final TmfTraceSelectedSignal signal
) {
613 if (signal
.getTrace() == fTrace
) {
616 fTrace
= signal
.getTrace();
621 * Trace is closed: clear the data structures and the view
623 * @param signal the signal received
626 public void traceClosed(final TmfTraceClosedSignal signal
) {
627 synchronized (fBuildThreadMap
) {
628 BuildThread buildThread
= fBuildThreadMap
.remove(signal
.getTrace());
629 if (buildThread
!= null) {
630 buildThread
.cancel();
633 synchronized (fEntryListMap
) {
634 fEntryListMap
.remove(signal
.getTrace());
636 fSelectedThreadMap
.remove(signal
.getTrace());
637 if (signal
.getTrace() == fTrace
) {
646 * Handler for the TimeSynch signal
649 * The incoming signal
652 public void synchToTime(final TmfTimeSynchSignal signal
) {
654 fSavedTimeSyncSignal
= isPinned() ?
new TmfTimeSynchSignal(signal
.getSource(), signal
.getBeginTime(), signal
.getEndTime()) : null;
656 if (signal
.getSource() == this || fTrace
== null || isPinned()) {
659 final long beginTime
= signal
.getBeginTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
660 final long endTime
= signal
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
661 Display
.getDefault().asyncExec(new Runnable() {
664 if (fTimeGraphCombo
.isDisposed()) {
667 if (beginTime
== endTime
) {
668 fTimeGraphCombo
.getTimeGraphViewer().setSelectedTime(beginTime
, true);
670 fTimeGraphCombo
.getTimeGraphViewer().setSelectionRange(beginTime
, endTime
);
672 selectTime(beginTime
);
673 startZoomThread(fTimeGraphCombo
.getTimeGraphViewer().getTime0(), fTimeGraphCombo
.getTimeGraphViewer().getTime1());
674 if (fEntryList
== null) {
677 TimeGraphViewer viewer
= fTimeGraphCombo
.getTimeGraphViewer();
678 for (ThreadEntry threadEntry
: fEntryList
) {
679 ITmfStateSystem ss
= threadEntry
.getTrace().getStateSystems().get(CallStackStateProvider
.ID
);
680 if (ss
== null || beginTime
< ss
.getStartTime() || beginTime
> ss
.getCurrentEndTime()) {
684 int quark
= ss
.getQuarkRelative(threadEntry
.getThreadQuark(), CallStackStateProvider
.CALL_STACK
);
685 ITmfStateInterval stackInterval
= ss
.querySingleState(beginTime
, quark
);
686 if (beginTime
== stackInterval
.getStartTime()) {
687 int stackLevel
= stackInterval
.getStateValue().unboxInt();
688 CallStackEntry selectedEntry
= threadEntry
.getChildren().get(Math
.max(0, stackLevel
- 1));
689 fTimeGraphCombo
.setSelection(selectedEntry
);
690 viewer
.getTimeGraphControl().fireSelectionChanged();
693 } catch (AttributeNotFoundException e
) {
694 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
695 } catch (TimeRangeException e
) {
696 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
697 } catch (StateSystemDisposedException e
) {
698 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
699 } catch (StateValueTypeException e
) {
700 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
708 * Handler for the RangeSynch signal
711 * The incoming signal
714 public void synchToRange(final TmfRangeSynchSignal signal
) {
717 fSavedRangeSyncSignal
=
718 new TmfRangeSynchSignal(signal
.getSource(), new TmfTimeRange(signal
.getCurrentRange().getStartTime(), signal
.getCurrentRange().getEndTime()));
720 fSavedTimeSyncSignal
= null;
723 if (signal
.getSource() == this || fTrace
== null || isPinned()) {
726 if (signal
.getCurrentRange().getIntersection(fTrace
.getTimeRange()) == null) {
729 final long startTime
= signal
.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
730 final long endTime
= signal
.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
731 Display
.getDefault().asyncExec(new Runnable() {
734 if (fTimeGraphCombo
.isDisposed()) {
737 fTimeGraphCombo
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
738 startZoomThread(startTime
, endTime
);
743 // ------------------------------------------------------------------------
745 // ------------------------------------------------------------------------
746 private void loadTrace() {
747 synchronized (fEntryListMap
) {
748 fEntryList
= fEntryListMap
.get(fTrace
);
749 if (fEntryList
== null) {
750 synchronized (fBuildThreadMap
) {
751 BuildThread buildThread
= new BuildThread(fTrace
);
752 fBuildThreadMap
.put(fTrace
, buildThread
);
756 fStartTime
= fTrace
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
757 fEndTime
= fTrace
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
763 private void buildThreadList(final ITmfTrace trace
, IProgressMonitor monitor
) {
764 fStartTime
= Long
.MAX_VALUE
;
765 fEndTime
= Long
.MIN_VALUE
;
767 if (trace
instanceof TmfExperiment
) {
768 TmfExperiment experiment
= (TmfExperiment
) trace
;
769 traces
= experiment
.getTraces();
771 traces
= new ITmfTrace
[] { trace
};
773 ArrayList
<ThreadEntry
> entryList
= new ArrayList
<ThreadEntry
>();
774 for (ITmfTrace aTrace
: traces
) {
775 if (monitor
.isCanceled()) {
778 ITmfStateSystem ss
= aTrace
.getStateSystems().get(CallStackStateProvider
.ID
);
779 if (ss
== null || !ss
.waitUntilBuilt()) {
780 String threadName
= Messages
.CallStackView_StackInfoNotAvailable
+ ' ' + '(' + aTrace
.getName() + ')';
781 ThreadEntry threadEntry
= new ThreadEntry(aTrace
, threadName
, -1, 0, 0);
782 entryList
.add(threadEntry
);
785 long startTime
= ss
.getStartTime();
786 long endTime
= ss
.getCurrentEndTime() + 1;
787 fStartTime
= Math
.min(fStartTime
, startTime
);
788 fEndTime
= Math
.max(fEndTime
, endTime
);
789 List
<Integer
> threadQuarks
= ss
.getQuarks(CallStackStateProvider
.THREADS
, "*"); //$NON-NLS-1$
790 for (int i
= 0; i
< threadQuarks
.size(); i
++) {
791 if (monitor
.isCanceled()) {
794 int threadQuark
= threadQuarks
.get(i
);
795 String thread
= ss
.getAttributeName(threadQuark
);
796 String threadEntryName
= thread
+ ' ' + '(' + aTrace
.getName() + ')';
797 ThreadEntry threadEntry
= new ThreadEntry(aTrace
, threadEntryName
, threadQuark
, startTime
, endTime
);
798 entryList
.add(threadEntry
);
801 eventStackQuark
= ss
.getQuarkRelative(threadQuark
, CallStackStateProvider
.CALL_STACK
);
803 for (int stackLevelQuark
: ss
.getSubAttributes(eventStackQuark
, false)) {
804 CallStackEntry callStackEntry
= new CallStackEntry(stackLevelQuark
, level
++, aTrace
);
805 threadEntry
.addChild(callStackEntry
);
807 } catch (AttributeNotFoundException e
) {
808 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
812 synchronized (fEntryListMap
) {
813 fEntryListMap
.put(trace
, new ArrayList
<ThreadEntry
>(entryList
));
815 if (trace
== fTrace
) {
818 for (ThreadEntry threadEntry
: entryList
) {
819 for (CallStackEntry callStackEntry
: threadEntry
.getChildren()) {
820 if (monitor
.isCanceled()) {
823 buildStatusEvents(trace
, callStackEntry
, monitor
);
828 private void buildStatusEvents(ITmfTrace trace
, CallStackEntry entry
, IProgressMonitor monitor
) {
829 ITmfStateSystem ss
= entry
.getTrace().getStateSystems().get(CallStackStateProvider
.ID
);
830 long start
= ss
.getStartTime();
831 long end
= ss
.getCurrentEndTime() + 1;
832 long resolution
= Math
.max(1, (end
- start
) / fDisplayWidth
);
833 List
<ITimeEvent
> eventList
= getEventList(entry
, start
, end
, resolution
, monitor
);
834 if (monitor
.isCanceled()) {
837 entry
.setEventList(eventList
);
838 if (trace
== fTrace
) {
843 private static List
<ITimeEvent
> getEventList(CallStackEntry entry
,
844 long startTime
, long endTime
, long resolution
,
845 IProgressMonitor monitor
) {
846 ITmfStateSystem ss
= entry
.getTrace().getStateSystems().get(CallStackStateProvider
.ID
);
847 long start
= Math
.max(startTime
, ss
.getStartTime());
848 long end
= Math
.min(endTime
, ss
.getCurrentEndTime() + 1);
852 List
<ITimeEvent
> eventList
= null;
854 List
<ITmfStateInterval
> stackIntervals
= ss
.queryHistoryRange(entry
.getQuark(), start
, end
- 1, resolution
, monitor
);
855 eventList
= new ArrayList
<ITimeEvent
>(stackIntervals
.size());
856 long lastEndTime
= -1;
857 boolean lastIsNull
= true;
858 for (ITmfStateInterval statusInterval
: stackIntervals
) {
859 if (monitor
.isCanceled()) {
862 long time
= statusInterval
.getStartTime();
863 long duration
= statusInterval
.getEndTime() - time
+ 1;
864 if (!statusInterval
.getStateValue().isNull()) {
865 final int modulo
= CallStackPresentationProvider
.NUM_COLORS
/ 2;
866 int value
= statusInterval
.getStateValue().toString().hashCode() % modulo
+ modulo
;
867 eventList
.add(new CallStackEvent(entry
, time
, duration
, value
));
870 if (lastEndTime
!= time
&& lastEndTime
!= -1 && lastIsNull
) {
871 eventList
.add(new TimeEvent(entry
, lastEndTime
, time
- lastEndTime
));
873 eventList
.add(new NullTimeEvent(entry
, time
, duration
));
876 lastEndTime
= time
+ duration
;
878 } catch (AttributeNotFoundException e
) {
879 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
880 } catch (TimeRangeException e
) {
881 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
882 } catch (StateSystemDisposedException e
) {
888 private void selectTime(long time
) {
889 if (fEntryList
== null) {
892 for (ThreadEntry threadEntry
: fEntryList
) {
893 ITmfStateSystem ss
= threadEntry
.fThreadTrace
.getStateSystems().get(CallStackStateProvider
.ID
);
894 if (ss
== null || !ss
.waitUntilBuilt()) {
897 long queryTime
= Math
.max(ss
.getStartTime(), Math
.min(ss
.getCurrentEndTime(), time
));
898 for (CallStackEntry callStackEntry
: threadEntry
.getChildren()) {
900 ITmfStateInterval stackLevelInterval
= ss
.querySingleState(queryTime
, callStackEntry
.getQuark());
901 ITmfStateValue nameValue
= stackLevelInterval
.getStateValue();
902 String name
= ""; //$NON-NLS-1$
904 if (nameValue
.getType() == Type
.STRING
) {
905 name
= nameValue
.unboxStr();
906 } else if (nameValue
.getType() == Type
.INTEGER
) {
907 name
= "0x" + Integer
.toHexString(nameValue
.unboxInt()); //$NON-NLS-1$
908 } else if (nameValue
.getType() == Type
.LONG
) {
909 name
= "0x" + Long
.toHexString(nameValue
.unboxLong()); //$NON-NLS-1$
911 } catch (StateValueTypeException e
) {
913 callStackEntry
.setFunctionName(name
);
914 if (name
.length() > 0) {
915 callStackEntry
.setStartTime(stackLevelInterval
.getStartTime());
916 callStackEntry
.setEndTime(stackLevelInterval
.getEndTime() + 1);
918 } catch (AttributeNotFoundException e
) {
919 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
920 } catch (TimeRangeException e
) {
921 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
922 } catch (StateSystemDisposedException e
) {
923 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
927 fTimeGraphCombo
.refresh();
930 private void refresh() {
931 Display
.getDefault().asyncExec(new Runnable() {
934 if (fTimeGraphCombo
.isDisposed()) {
937 ITimeGraphEntry
[] entries
= null;
938 synchronized (fEntryListMap
) {
939 fEntryList
= fEntryListMap
.get(fTrace
);
940 if (fEntryList
== null) {
941 fEntryList
= new ArrayList
<ThreadEntry
>();
943 entries
= fEntryList
.toArray(new ITimeGraphEntry
[0]);
945 fTimeGraphCombo
.setInput(entries
);
946 fTimeGraphCombo
.getTimeGraphViewer().setTimeBounds(fStartTime
, fEndTime
);
948 long selectionBeginTime
= fTrace
== null ?
0 : fTraceManager
.getSelectionBeginTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
949 long selectionEndTime
= fTrace
== null ?
0 : fTraceManager
.getSelectionEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
950 long startTime
= fTrace
== null ?
0 : fTraceManager
.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
951 long endTime
= fTrace
== null ?
0 : fTraceManager
.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
952 startTime
= Math
.max(startTime
, fStartTime
);
953 endTime
= Math
.min(endTime
, fEndTime
);
954 fTimeGraphCombo
.getTimeGraphViewer().setSelectionRange(selectionBeginTime
, selectionEndTime
);
955 selectTime(selectionBeginTime
);
956 fTimeGraphCombo
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
957 startZoomThread(startTime
, endTime
);
962 private void redraw() {
963 synchronized (fSyncObj
) {
964 if (fRedrawState
== State
.IDLE
) {
965 fRedrawState
= State
.BUSY
;
967 fRedrawState
= State
.PENDING
;
971 Display
.getDefault().asyncExec(new Runnable() {
974 if (fTimeGraphCombo
.isDisposed()) {
977 fTimeGraphCombo
.redraw();
978 fTimeGraphCombo
.update();
979 synchronized (fSyncObj
) {
980 if (fRedrawState
== State
.PENDING
) {
981 fRedrawState
= State
.IDLE
;
984 fRedrawState
= State
.IDLE
;
991 private void startZoomThread(long startTime
, long endTime
) {
992 if (fZoomThread
!= null) {
993 fZoomThread
.cancel();
995 fZoomThread
= new ZoomThread(fEntryList
, startTime
, endTime
);
999 private void makeActions() {
1000 fPreviousItemAction
= fTimeGraphCombo
.getTimeGraphViewer().getPreviousItemAction();
1001 fPreviousItemAction
.setText(Messages
.TmfTimeGraphViewer_PreviousItemActionNameText
);
1002 fPreviousItemAction
.setToolTipText(Messages
.TmfTimeGraphViewer_PreviousItemActionToolTipText
);
1003 fNextItemAction
= fTimeGraphCombo
.getTimeGraphViewer().getNextItemAction();
1004 fNextItemAction
.setText(Messages
.TmfTimeGraphViewer_NextItemActionNameText
);
1005 fNextItemAction
.setToolTipText(Messages
.TmfTimeGraphViewer_NextItemActionToolTipText
);
1008 private void contributeToActionBars() {
1009 IActionBars bars
= getViewSite().getActionBars();
1010 fillLocalToolBar(bars
.getToolBarManager());
1012 // Create pin action
1013 contributePinActionToToolBar();
1014 fPinAction
.addPropertyChangeListener(new IPropertyChangeListener(){
1016 public void propertyChange(PropertyChangeEvent event
) {
1017 if (IAction
.CHECKED
.equals(event
.getProperty()) && !isPinned()) {
1018 if (fSavedRangeSyncSignal
!= null) {
1019 synchToRange(fSavedRangeSyncSignal
);
1020 fSavedRangeSyncSignal
= null;
1023 if (fSavedTimeSyncSignal
!= null) {
1024 synchToTime(fSavedTimeSyncSignal
);
1025 fSavedTimeSyncSignal
= null;
1032 private void fillLocalToolBar(IToolBarManager manager
) {
1033 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getResetScaleAction());
1034 manager
.add(getPreviousEventAction());
1035 manager
.add(getNextEventAction());
1036 manager
.add(fPreviousItemAction
);
1037 manager
.add(fNextItemAction
);
1038 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getZoomInAction());
1039 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getZoomOutAction());
1040 manager
.add(new Separator());
1044 * Get the the next event action.
1046 * @return The action object
1048 private Action
getNextEventAction() {
1049 if (fNextEventAction
== null) {
1050 fNextEventAction
= new Action() {
1053 TimeGraphViewer viewer
= fTimeGraphCombo
.getTimeGraphViewer();
1054 ITimeGraphEntry entry
= viewer
.getSelection();
1055 if (entry
instanceof CallStackEntry
) {
1057 CallStackEntry callStackEntry
= (CallStackEntry
) entry
;
1058 ITmfTrace trace
= callStackEntry
.getTrace();
1059 ITmfStateSystem ss
= trace
.getStateSystems().get(CallStackStateProvider
.ID
);
1060 long time
= Math
.max(ss
.getStartTime(), Math
.min(ss
.getCurrentEndTime(), viewer
.getSelectionBegin()));
1061 ThreadEntry threadEntry
= (ThreadEntry
) callStackEntry
.getParent();
1062 int quark
= ss
.getQuarkRelative(threadEntry
.getThreadQuark(), CallStackStateProvider
.CALL_STACK
);
1063 ITmfStateInterval stackInterval
= ss
.querySingleState(time
, quark
);
1064 long newTime
= stackInterval
.getEndTime() + 1;
1065 viewer
.setSelectedTimeNotify(newTime
, true);
1066 stackInterval
= ss
.querySingleState(Math
.min(ss
.getCurrentEndTime(), newTime
), quark
);
1067 int stackLevel
= stackInterval
.getStateValue().unboxInt();
1068 CallStackEntry selectedEntry
= threadEntry
.getChildren().get(Math
.max(0, stackLevel
- 1));
1069 fTimeGraphCombo
.setSelection(selectedEntry
);
1070 viewer
.getTimeGraphControl().fireSelectionChanged();
1071 startZoomThread(viewer
.getTime0(), viewer
.getTime1());
1072 } catch (AttributeNotFoundException e
) {
1073 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1074 } catch (TimeRangeException e
) {
1075 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1076 } catch (StateSystemDisposedException e
) {
1077 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1078 } catch (StateValueTypeException e
) {
1079 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1085 fNextEventAction
.setText(Messages
.TmfTimeGraphViewer_NextEventActionNameText
);
1086 fNextEventAction
.setToolTipText(Messages
.TmfTimeGraphViewer_NextEventActionToolTipText
);
1087 fNextEventAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(ITmfImageConstants
.IMG_UI_NEXT_EVENT
));
1090 return fNextEventAction
;
1094 * Get the previous event action.
1096 * @return The Action object
1098 private Action
getPreviousEventAction() {
1099 if (fPrevEventAction
== null) {
1100 fPrevEventAction
= new Action() {
1103 TimeGraphViewer viewer
= fTimeGraphCombo
.getTimeGraphViewer();
1104 ITimeGraphEntry entry
= viewer
.getSelection();
1105 if (entry
instanceof CallStackEntry
) {
1107 CallStackEntry callStackEntry
= (CallStackEntry
) entry
;
1108 ITmfTrace trace
= callStackEntry
.getTrace();
1109 ITmfStateSystem ss
= trace
.getStateSystems().get(CallStackStateProvider
.ID
);
1110 long time
= Math
.max(ss
.getStartTime(), Math
.min(ss
.getCurrentEndTime(), viewer
.getSelectionBegin()));
1111 ThreadEntry threadEntry
= (ThreadEntry
) callStackEntry
.getParent();
1112 int quark
= ss
.getQuarkRelative(threadEntry
.getThreadQuark(), CallStackStateProvider
.CALL_STACK
);
1113 ITmfStateInterval stackInterval
= ss
.querySingleState(time
, quark
);
1114 if (stackInterval
.getStartTime() == time
&& time
> ss
.getStartTime()) {
1115 stackInterval
= ss
.querySingleState(time
- 1, quark
);
1117 viewer
.setSelectedTimeNotify(stackInterval
.getStartTime(), true);
1118 int stackLevel
= stackInterval
.getStateValue().unboxInt();
1119 CallStackEntry selectedEntry
= threadEntry
.getChildren().get(Math
.max(0, stackLevel
- 1));
1120 fTimeGraphCombo
.setSelection(selectedEntry
);
1121 viewer
.getTimeGraphControl().fireSelectionChanged();
1122 startZoomThread(viewer
.getTime0(), viewer
.getTime1());
1123 } catch (AttributeNotFoundException e
) {
1124 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1125 } catch (TimeRangeException e
) {
1126 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1127 } catch (StateSystemDisposedException e
) {
1128 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1129 } catch (StateValueTypeException e
) {
1130 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1136 fPrevEventAction
.setText(Messages
.TmfTimeGraphViewer_PreviousEventActionNameText
);
1137 fPrevEventAction
.setToolTipText(Messages
.TmfTimeGraphViewer_PreviousEventActionToolTipText
);
1138 fPrevEventAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(ITmfImageConstants
.IMG_UI_PREV_EVENT
));
1141 return fPrevEventAction
;