tmf: Introduce a central trace manager
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / views / callstack / CallStackView.java
CommitLineData
e8251298
PT
1/*******************************************************************************
2 * Copyright (c) 2013 Ericsson
3 *
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
8 *
9 * Contributors:
10 * Patrick Tasse - Initial API and implementation
11 *******************************************************************************/
12
13package org.eclipse.linuxtools.tmf.ui.views.callstack;
14
15import java.util.ArrayList;
16import java.util.HashMap;
17import java.util.Iterator;
18import java.util.List;
19
20import org.eclipse.core.runtime.IProgressMonitor;
21import org.eclipse.core.runtime.NullProgressMonitor;
22import org.eclipse.jface.action.Action;
23import org.eclipse.jface.action.IAction;
24import org.eclipse.jface.action.IToolBarManager;
25import org.eclipse.jface.action.Separator;
26import org.eclipse.jface.util.IPropertyChangeListener;
27import org.eclipse.jface.util.PropertyChangeEvent;
28import org.eclipse.jface.viewers.DoubleClickEvent;
29import org.eclipse.jface.viewers.IDoubleClickListener;
30import org.eclipse.jface.viewers.ILabelProviderListener;
31import org.eclipse.jface.viewers.ISelection;
32import org.eclipse.jface.viewers.IStructuredSelection;
33import org.eclipse.jface.viewers.ITableLabelProvider;
34import org.eclipse.jface.viewers.ITreeContentProvider;
35import org.eclipse.jface.viewers.Viewer;
36import org.eclipse.linuxtools.internal.tmf.ui.Activator;
37import org.eclipse.linuxtools.internal.tmf.ui.ITmfImageConstants;
38import org.eclipse.linuxtools.internal.tmf.ui.Messages;
39import org.eclipse.linuxtools.tmf.core.callstack.CallStackStateProvider;
40import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfTmfTimestamp;
41import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
42import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException;
43import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
44import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
45import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
46import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal;
47import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
48import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;
49import org.eclipse.linuxtools.tmf.core.signal.TmfTraceClosedSignal;
50import org.eclipse.linuxtools.tmf.core.signal.TmfTraceSelectedSignal;
51import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
52import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
53import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue.Type;
54import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
55import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
56import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
57import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestampDelta;
58import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
59import org.eclipse.linuxtools.tmf.core.trace.TmfExperiment;
60import org.eclipse.linuxtools.tmf.ui.editors.ITmfTraceEditor;
61import org.eclipse.linuxtools.tmf.ui.views.TmfView;
62import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphRangeListener;
63import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;
64import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphCombo;
65import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphRangeUpdateEvent;
66import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphTimeEvent;
67import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphViewer;
68import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeEvent;
69import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
70import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.NullTimeEvent;
71import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.TimeEvent;
72import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
73import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.TimeGraphSelection;
74import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
75import org.eclipse.swt.SWT;
76import org.eclipse.swt.events.ControlAdapter;
77import org.eclipse.swt.events.ControlEvent;
78import org.eclipse.swt.events.MouseAdapter;
79import org.eclipse.swt.events.MouseEvent;
80import org.eclipse.swt.graphics.Image;
81import org.eclipse.swt.widgets.Composite;
82import org.eclipse.swt.widgets.Display;
83import org.eclipse.ui.IActionBars;
84import org.eclipse.ui.IEditorPart;
85
86/**
87 * Main implementation for the Call Stack view
88 *
89 * @author Patrick Tasse
90 * @since 2.0
91 */
92public class CallStackView extends TmfView {
93
94 // ------------------------------------------------------------------------
95 // Constants
96 // ------------------------------------------------------------------------
97
98 /** View ID. */
99 public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.callstack"; //$NON-NLS-1$
100
101 /**
102 * Redraw state enum
103 */
104 private enum State { IDLE, BUSY, PENDING }
105
106 private final String[] COLUMN_NAMES = new String[] {
107 Messages.CallStackView_FunctionColumn,
108 Messages.CallStackView_DepthColumn,
109 Messages.CallStackView_EntryTimeColumn,
110 Messages.CallStackView_ExitTimeColumn,
111 Messages.CallStackView_DurationColumn
112 };
113
114 private static final Image THREAD_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/thread_obj.gif"); //$NON-NLS-1$
115 private static final Image STACKFRAME_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/stckframe_obj.gif"); //$NON-NLS-1$
116
117 // ------------------------------------------------------------------------
118 // Fields
119 // ------------------------------------------------------------------------
120
121 // The time graph combo
122 TimeGraphCombo fTimeGraphCombo;
123
124 // The selected trace
125 private ITmfTrace fTrace;
126
127 // The selected thread map
128 final private HashMap<ITmfTrace, String> fSelectedThreadMap = new HashMap<ITmfTrace, String>();
129
130 // The time graph entry list
131 private ArrayList<ThreadEntry> fEntryList;
132
133 // The trace to entry list hash map
134 final private HashMap<ITmfTrace, ArrayList<ThreadEntry>> fEntryListMap = new HashMap<ITmfTrace, ArrayList<ThreadEntry>>();
135
136 // The trace to build thread hash map
137 final private HashMap<ITmfTrace, BuildThread> fBuildThreadMap = new HashMap<ITmfTrace, BuildThread>();
138
139 // The start time
140 private long fStartTime;
141
142 // The end time
143 private long fEndTime;
144
145 // The display width
146 private int fDisplayWidth;
147
148 // The next event action
149 private Action fNextEventAction;
150
151 // The previous event action
152 private Action fPrevEventAction;
153
154 // The next item action
155 private Action fNextItemAction;
156
157 // The previous item action
158 private Action fPreviousItemAction;
159
160 // The zoom thread
161 private ZoomThread fZoomThread;
162
163 // The redraw state used to prevent unnecessary queuing of display runnables
164 private State fRedrawState = State.IDLE;
165
166 // The redraw synchronization object
167 final private Object fSyncObj = new Object();
168
169 // The saved time sync. signal used when switching off the pinning of a view
170 private TmfTimeSynchSignal fSavedTimeSyncSignal;
171
172 // The saved time range sync. signal used when switching off the pinning of a view
173 private TmfRangeSynchSignal fSavedRangeSyncSignal;
174
175 // ------------------------------------------------------------------------
176 // Classes
177 // ------------------------------------------------------------------------
178
179 private class ThreadEntry implements ITimeGraphEntry {
180 // The Trace
181 private final ITmfTrace fThreadTrace;
182 // The start time
183 private final long fTraceStartTime;
184 // The end time
185 private final long fTraceEndTime;
186 // The children of the entry
187 private ArrayList<CallStackEntry> fChildren;
188 // The name of entry
189 private final String fName;
190 // The thread attribute quark
191 private final int fThreadQuark;
192
193 public ThreadEntry(ITmfTrace trace, String name, int threadQuark, long startTime, long endTime) {
194 fThreadTrace = trace;
195 fChildren = new ArrayList<CallStackEntry>();
196 fName = name;
197 fTraceStartTime = startTime;
198 fTraceEndTime = endTime;
199 fThreadQuark = threadQuark;
200 }
201
202 @Override
203 public ITimeGraphEntry getParent() {
204 return null;
205 }
206
207 @Override
208 public boolean hasChildren() {
209 if (fChildren == null) {
210 ITmfStateSystem ss = fThreadTrace.getStateSystems().get(CallStackStateProvider.ID);
211 try {
212 int eventStackQuark = ss.getQuarkRelative(fThreadQuark, CallStackStateProvider.CALL_STACK);
213 ITmfStateInterval eventStackInterval = ss.querySingleState(ss.getStartTime(), eventStackQuark);
214 return ! eventStackInterval.getStateValue().isNull() || eventStackInterval.getEndTime() != ss.getCurrentEndTime();
215 } catch (AttributeNotFoundException e) {
216 e.printStackTrace();
217 } catch (TimeRangeException e) {
218 e.printStackTrace();
219 } catch (StateSystemDisposedException e) {
220 /* Ignored */
221 }
222 }
223 return fChildren != null && fChildren.size() > 0;
224 }
225
226 @Override
227 public List<CallStackEntry> getChildren() {
228 return fChildren;
229 }
230
231 @Override
232 public String getName() {
233 return fName;
234 }
235
236 @Override
237 public long getStartTime() {
238 return fTraceStartTime;
239 }
240
241 @Override
242 public long getEndTime() {
243 return fTraceEndTime;
244 }
245
246 @Override
247 public boolean hasTimeEvents() {
248 return false;
249 }
250
251 @Override
252 public Iterator<ITimeEvent> getTimeEventsIterator() {
253 return null;
254 }
255
256 @Override
257 public <T extends ITimeEvent> Iterator<T> getTimeEventsIterator(long startTime, long stopTime, long visibleDuration) {
258 return null;
259 }
260
261 public int getThreadQuark() {
262 return fThreadQuark;
263 }
264
265 public ITmfTrace getTrace() {
266 return fThreadTrace;
267 }
268
269 public void addChild(CallStackEntry entry) {
270 entry.setParent(this);
271 fChildren.add(entry);
272 }
273 }
274
275 private class TreeContentProvider implements ITreeContentProvider {
276
277 @Override
278 public void dispose() {
279 }
280
281 @Override
282 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
283 }
284
285 @Override
286 public Object[] getElements(Object inputElement) {
287 return (ITimeGraphEntry[]) inputElement;
288 }
289
290 @Override
291 public Object[] getChildren(Object parentElement) {
292 ITimeGraphEntry entry = (ITimeGraphEntry) parentElement;
293 return entry.getChildren().toArray();
294 }
295
296 @Override
297 public Object getParent(Object element) {
298 ITimeGraphEntry entry = (ITimeGraphEntry) element;
299 return entry.getParent();
300 }
301
302 @Override
303 public boolean hasChildren(Object element) {
304 ITimeGraphEntry entry = (ITimeGraphEntry) element;
305 return entry.hasChildren();
306 }
307
308 }
309
310 private class TreeLabelProvider implements ITableLabelProvider {
311
312 @Override
313 public void addListener(ILabelProviderListener listener) {
314 }
315
316 @Override
317 public void dispose() {
318 }
319
320 @Override
321 public boolean isLabelProperty(Object element, String property) {
322 return false;
323 }
324
325 @Override
326 public void removeListener(ILabelProviderListener listener) {
327 }
328
329 @Override
330 public Image getColumnImage(Object element, int columnIndex) {
331 if (columnIndex == 0) {
332 if (element instanceof ThreadEntry) {
333 return THREAD_IMAGE;
334 } else if (element instanceof CallStackEntry) {
335 CallStackEntry entry = (CallStackEntry) element;
336 if (entry.getFunctionName().length() > 0) {
337 return STACKFRAME_IMAGE;
338 }
339 }
340 }
341 return null;
342 }
343
344 @Override
345 public String getColumnText(Object element, int columnIndex) {
346 if (element instanceof ThreadEntry) {
347 if (columnIndex == 0) {
348 return ((ThreadEntry) element).getName();
349 }
350 } else if (element instanceof CallStackEntry) {
351 CallStackEntry entry = (CallStackEntry) element;
352 if (columnIndex == 0) {
353 return entry.getFunctionName();
354 } else if (columnIndex == 1) {
355 if (entry.getFunctionName().length() > 0) {
356 int depth = entry.getStackLevel();
357 return Integer.toString(depth);
358 }
359 } else if (columnIndex == 2) {
360 if (entry.getFunctionName().length() > 0) {
361 ITmfTimestamp ts = new TmfTimestamp(entry.getStartTime(), ITmfTimestamp.NANOSECOND_SCALE);
362 return ts.toString();
363 }
364 } else if (columnIndex == 3) {
365 if (entry.getFunctionName().length() > 0) {
366 ITmfTimestamp ts = new TmfTimestamp(entry.getEndTime(), ITmfTimestamp.NANOSECOND_SCALE);
367 return ts.toString();
368 }
369 } else if (columnIndex == 4) {
370 if (entry.getFunctionName().length() > 0) {
371 ITmfTimestamp ts = new TmfTimestampDelta(entry.getEndTime() - entry.getStartTime(), ITmfTimestamp.NANOSECOND_SCALE);
372 return ts.toString();
373 }
374 }
375 }
376 return ""; //$NON-NLS-1$
377 }
378
379 }
380
381 private class BuildThread extends Thread {
382 private final ITmfTrace fBuildTrace;
383 private final IProgressMonitor fMonitor;
384
385 public BuildThread(ITmfTrace trace) {
386 super("CallStackView build"); //$NON-NLS-1$
387 fBuildTrace = trace;
388 fMonitor = new NullProgressMonitor();
389 }
390
391 @Override
392 public void run() {
393 buildThreadList(fBuildTrace, fMonitor);
394 synchronized (fBuildThreadMap) {
395 fBuildThreadMap.remove(this);
396 }
397 }
398
399 public void cancel() {
400 fMonitor.setCanceled(true);
401 }
402 }
403
404 private class ZoomThread extends Thread {
405 private final ArrayList<ThreadEntry> fZoomEntryList;
406 private final long fZoomStartTime;
407 private final long fZoomEndTime;
408 private final IProgressMonitor fMonitor;
409
410 public ZoomThread(ArrayList<ThreadEntry> entryList, long startTime, long endTime) {
411 super("ResourcesView zoom"); //$NON-NLS-1$
412 fZoomEntryList = entryList;
413 fZoomStartTime = startTime;
414 fZoomEndTime = endTime;
415 fMonitor = new NullProgressMonitor();
416 }
417
418 @Override
419 public void run() {
420 if (fZoomEntryList == null) {
421 return;
422 }
423 long resolution = Math.max(1, (fZoomEndTime - fZoomStartTime) / fDisplayWidth);
424 for (ThreadEntry threadEntry : fZoomEntryList) {
425 ITmfStateSystem ss = threadEntry.fThreadTrace.getStateSystems().get(CallStackStateProvider.ID);
426 if (ss == null || !ss.waitUntilBuilt()) {
427 continue;
428 }
429 for (ITimeGraphEntry child : threadEntry.getChildren()) {
430 if (fMonitor.isCanceled()) {
431 break;
432 }
433 CallStackEntry entry = (CallStackEntry) child;
434 if (fZoomStartTime <= fStartTime && fZoomEndTime >= fEndTime) {
435 entry.setZoomedEventList(null);
436 } else {
437 List<ITimeEvent> zoomedEventList = getEventList(entry, fZoomStartTime, fZoomEndTime, resolution, fMonitor);
438 if (zoomedEventList != null) {
439 entry.setZoomedEventList(zoomedEventList);
440 }
441 }
442 redraw();
443 }
444 }
445 }
446
447 public void cancel() {
448 fMonitor.setCanceled(true);
449 }
450 }
451
452 // ------------------------------------------------------------------------
453 // Constructors
454 // ------------------------------------------------------------------------
455
456 /**
457 * Default constructor
458 */
459 public CallStackView() {
460 super(ID);
461 fDisplayWidth = Display.getDefault().getBounds().width;
462 }
463
464 // ------------------------------------------------------------------------
465 // ViewPart
466 // ------------------------------------------------------------------------
467
468 @Override
469 public void createPartControl(Composite parent) {
470 fTimeGraphCombo = new TimeGraphCombo(parent, SWT.NONE);
471
472 fTimeGraphCombo.setTreeContentProvider(new TreeContentProvider());
473
474 fTimeGraphCombo.setTreeLabelProvider(new TreeLabelProvider());
475
476 fTimeGraphCombo.setTreeColumns(COLUMN_NAMES);
477
478 fTimeGraphCombo.getTreeViewer().getTree().getColumn(0).setWidth(200);
479 fTimeGraphCombo.getTreeViewer().getTree().getColumn(1).setWidth(50);
480 fTimeGraphCombo.getTreeViewer().getTree().getColumn(2).setWidth(120);
481 fTimeGraphCombo.getTreeViewer().getTree().getColumn(3).setWidth(120);
482 fTimeGraphCombo.getTreeViewer().getTree().getColumn(4).setWidth(120);
483
484 fTimeGraphCombo.setTimeGraphProvider(new CallStackPresentationProvider());
485 fTimeGraphCombo.getTimeGraphViewer().setTimeFormat(TimeFormat.CALENDAR);
486
487 fTimeGraphCombo.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
488 @Override
489 public void timeRangeUpdated(TimeGraphRangeUpdateEvent event) {
490 long startTime = event.getStartTime();
491 long endTime = event.getEndTime();
492 TmfTimeRange range = new TmfTimeRange(new CtfTmfTimestamp(startTime), new CtfTmfTimestamp(endTime));
493 TmfTimestamp time = new CtfTmfTimestamp(fTimeGraphCombo.getTimeGraphViewer().getSelectedTime());
494 broadcast(new TmfRangeSynchSignal(CallStackView.this, range, time));
495 startZoomThread(startTime, endTime);
496 }
497 });
498
499 fTimeGraphCombo.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
500 @Override
501 public void timeSelected(TimeGraphTimeEvent event) {
502 long time = event.getTime();
503 selectTime(time);
504 broadcast(new TmfTimeSynchSignal(CallStackView.this, new CtfTmfTimestamp(time)));
505 }
506 });
507
508 fTimeGraphCombo.getTimeGraphViewer().getControl().addControlListener(new ControlAdapter() {
509 @Override
510 public void controlResized(ControlEvent e) {
511 fDisplayWidth = fTimeGraphCombo.getTimeGraphViewer().getControl().getSize().x;
512 if (fEntryList != null) {
513 startZoomThread(fTimeGraphCombo.getTimeGraphViewer().getTime0(), fTimeGraphCombo.getTimeGraphViewer().getTime1());
514 }
515 }
516 });
517
518 fTimeGraphCombo.getTreeViewer().addDoubleClickListener(new IDoubleClickListener() {
519 @Override
520 public void doubleClick(DoubleClickEvent event) {
521 Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
522 if (selection instanceof CallStackEntry) {
523 CallStackEntry entry = (CallStackEntry) selection;
524 if (entry.getFunctionName().length() > 0) {
525 long startTime = entry.getStartTime();
526 long endTime = entry.getEndTime();
527 long spacingTime = (long) ((endTime - startTime) * 0.01);
528 startTime -= spacingTime;
529 endTime += spacingTime;
530 TmfTimeRange range = new TmfTimeRange(new CtfTmfTimestamp(startTime), new CtfTmfTimestamp(endTime));
531 TmfTimestamp time = new CtfTmfTimestamp(fTimeGraphCombo.getTimeGraphViewer().getSelectedTime());
532 broadcast(new TmfRangeSynchSignal(CallStackView.this, range, time));
533 fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
534 startZoomThread(startTime, endTime);
535 }
536 }
537 }
538 });
539
540 fTimeGraphCombo.getTimeGraphViewer().getTimeGraphControl().addMouseListener(new MouseAdapter() {
541 @Override
542 public void mouseDoubleClick(MouseEvent e) {
543 TimeGraphControl timeGraphControl = fTimeGraphCombo.getTimeGraphViewer().getTimeGraphControl();
544 ISelection selection = timeGraphControl.getSelection();
545 if (selection instanceof TimeGraphSelection) {
546 Object o = ((TimeGraphSelection) selection).getFirstElement();
547 if (o instanceof CallStackEvent) {
548 CallStackEvent event = (CallStackEvent) o;
549 long startTime = event.getTime();
550 long endTime = startTime + event.getDuration();
551 long spacingTime = (long) ((endTime - startTime) * 0.01);
552 startTime -= spacingTime;
553 endTime += spacingTime;
554 TmfTimeRange range = new TmfTimeRange(new CtfTmfTimestamp(startTime), new CtfTmfTimestamp(endTime));
555 TmfTimestamp time = new CtfTmfTimestamp(fTimeGraphCombo.getTimeGraphViewer().getSelectedTime());
556 broadcast(new TmfRangeSynchSignal(CallStackView.this, range, time));
557 fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
558 startZoomThread(startTime, endTime);
559 }
560 }
561 }
562 });
563
564 // View Action Handling
565 makeActions();
566 contributeToActionBars();
567
568 IEditorPart editor = getSite().getPage().getActiveEditor();
569 if (editor instanceof ITmfTraceEditor) {
570 ITmfTrace trace = ((ITmfTraceEditor) editor).getTrace();
571 if (trace != null) {
572 traceSelected(new TmfTraceSelectedSignal(this, trace));
573 }
574 }
575 }
576
577 @Override
578 public void setFocus() {
579 fTimeGraphCombo.setFocus();
580 }
581
582 // ------------------------------------------------------------------------
583 // Signal handlers
584 // ------------------------------------------------------------------------
585
586 /**
587 * Handler for the trace selected signal
588 *
589 * @param signal
590 * The incoming signal
591 */
592 @TmfSignalHandler
593 public void traceSelected(final TmfTraceSelectedSignal signal) {
594 if (signal.getTrace() == fTrace) {
595 return;
596 }
597 fTrace = signal.getTrace();
598
599 synchronized (fEntryListMap) {
600 fEntryList = fEntryListMap.get(fTrace);
601 if (fEntryList == null) {
602 synchronized (fBuildThreadMap) {
603 BuildThread buildThread = new BuildThread(fTrace);
604 fBuildThreadMap.put(fTrace, buildThread);
605 buildThread.start();
606 }
607 } else {
608 fStartTime = fTrace.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
609 fEndTime = fTrace.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
610 refresh();
611 }
612 }
613 }
614
615 /**
616 * Trace is closed: clear the data structures and the view
617 *
618 * @param signal the signal received
619 */
620 @TmfSignalHandler
621 public void traceClosed(final TmfTraceClosedSignal signal) {
622 synchronized (fBuildThreadMap) {
623 BuildThread buildThread = fBuildThreadMap.remove(signal.getTrace());
624 if (buildThread != null) {
625 buildThread.cancel();
626 }
627 }
628 synchronized (fEntryListMap) {
629 fEntryListMap.remove(signal.getTrace());
630 }
631 fSelectedThreadMap.remove(signal.getTrace());
632 if (signal.getTrace() == fTrace) {
633 fTrace = null;
634 fStartTime = 0;
635 fEndTime = 0;
636 refresh();
637 }
638 }
639
640 /**
641 * Handler for the TimeSynch signal
642 *
643 * @param signal
644 * The incoming signal
645 */
646 @TmfSignalHandler
647 public void synchToTime(final TmfTimeSynchSignal signal) {
648
649 fSavedTimeSyncSignal = isPinned() ? new TmfTimeSynchSignal(signal.getSource(), signal.getCurrentTime()) : null;
650
651 if (signal.getSource() == this || fTrace == null || isPinned()) {
652 return;
653 }
654 final long time = signal.getCurrentTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
655 Display.getDefault().asyncExec(new Runnable() {
656 @Override
657 public void run() {
658 if (fTimeGraphCombo.isDisposed()) {
659 return;
660 }
661 selectTime(time);
662 startZoomThread(fTimeGraphCombo.getTimeGraphViewer().getTime0(), fTimeGraphCombo.getTimeGraphViewer().getTime1());
663 if (fEntryList == null) {
664 return;
665 }
666 TimeGraphViewer viewer = fTimeGraphCombo.getTimeGraphViewer();
667 for (ThreadEntry threadEntry : fEntryList) {
668 ITmfStateSystem ss = threadEntry.getTrace().getStateSystems().get(CallStackStateProvider.ID);
669 if (ss == null || time < ss.getStartTime() || time > ss.getCurrentEndTime()) {
670 continue;
671 }
672 try {
673 int quark = ss.getQuarkRelative(threadEntry.getThreadQuark(), CallStackStateProvider.CALL_STACK);
674 ITmfStateInterval stackInterval = ss.querySingleState(time, quark);
675 if (time == stackInterval.getStartTime()) {
676 int stackLevel = stackInterval.getStateValue().unboxInt();
677 CallStackEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
678 fTimeGraphCombo.setSelection(selectedEntry);
679 viewer.getTimeGraphControl().fireSelectionChanged();
680 break;
681 }
682 } catch (AttributeNotFoundException e) {
683 e.printStackTrace();
684 } catch (TimeRangeException e) {
685 e.printStackTrace();
686 } catch (StateSystemDisposedException e) {
687 e.printStackTrace();
688 } catch (StateValueTypeException e) {
689 e.printStackTrace();
690 }
691 }
692 }
693 });
694 }
695
696 /**
697 * Handler for the RangeSynch signal
698 *
699 * @param signal
700 * The incoming signal
701 */
702 @TmfSignalHandler
703 public void synchToRange(final TmfRangeSynchSignal signal) {
704
705 if (isPinned()) {
706 fSavedRangeSyncSignal =
707 new TmfRangeSynchSignal(signal.getSource(), new TmfTimeRange(signal.getCurrentRange().getStartTime(), signal.getCurrentRange().getEndTime()), signal.getCurrentTime());
708
709 fSavedTimeSyncSignal = null;
710 }
711
712 if (signal.getSource() == this || fTrace == null || isPinned()) {
713 return;
714 }
715 if (signal.getCurrentRange().getIntersection(fTrace.getTimeRange()) == null) {
716 return;
717 }
718 final long startTime = signal.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
719 final long endTime = signal.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
720 final long time = signal.getCurrentTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
721 Display.getDefault().asyncExec(new Runnable() {
722 @Override
723 public void run() {
724 if (fTimeGraphCombo.isDisposed()) {
725 return;
726 }
727 fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
728 fTimeGraphCombo.getTimeGraphViewer().setSelectedTime(time, false);
729 startZoomThread(startTime, endTime);
730 }
731 });
732 }
733
734 // ------------------------------------------------------------------------
735 // Internal
736 // ------------------------------------------------------------------------
737
738 private void buildThreadList(final ITmfTrace trace, IProgressMonitor monitor) {
739 fStartTime = Long.MAX_VALUE;
740 fEndTime = Long.MIN_VALUE;
741 ITmfTrace[] traces;
742 if (trace instanceof TmfExperiment) {
743 TmfExperiment experiment = (TmfExperiment) trace;
744 traces = experiment.getTraces();
745 } else {
746 traces = new ITmfTrace[] { trace };
747 }
748 ArrayList<ThreadEntry> entryList = new ArrayList<ThreadEntry>();
749 for (ITmfTrace aTrace : traces) {
750 if (monitor.isCanceled()) {
751 return;
752 }
753 ITmfStateSystem ss = aTrace.getStateSystems().get(CallStackStateProvider.ID);
754 if (ss == null || !ss.waitUntilBuilt()) {
755 String threadName = Messages.CallStackView_StackInfoNotAvailable + ' ' + '(' + aTrace.getName() + ')';
756 ThreadEntry threadEntry = new ThreadEntry(aTrace, threadName, -1, 0, 0);
757 entryList.add(threadEntry);
758 continue;
759 }
760 long startTime = ss.getStartTime();
761 long endTime = ss.getCurrentEndTime() + 1;
762 fStartTime = Math.min(fStartTime, startTime);
763 fEndTime = Math.max(fEndTime, endTime);
764 List<Integer> threadQuarks = ss.getQuarks(CallStackStateProvider.THREADS, "*"); //$NON-NLS-1$
765 for (int i = 0; i < threadQuarks.size(); i++) {
766 if (monitor.isCanceled()) {
767 return;
768 }
769 int threadQuark = threadQuarks.get(i);
770 String thread = ss.getAttributeName(threadQuark);
771 String threadEntryName = thread + ' ' + '(' + aTrace.getName() + ')';
772 ThreadEntry threadEntry = new ThreadEntry(aTrace, threadEntryName, threadQuark, startTime, endTime);
773 entryList.add(threadEntry);
774 int eventStackQuark;
775 try {
776 eventStackQuark = ss.getQuarkRelative(threadQuark, CallStackStateProvider.CALL_STACK);
777 int level = 1;
778 for (int stackLevelQuark : ss.getSubAttributes(eventStackQuark, false)) {
779 CallStackEntry callStackEntry = new CallStackEntry(stackLevelQuark, level++, aTrace);
780 threadEntry.addChild(callStackEntry);
781 }
782 } catch (AttributeNotFoundException e) {
783 e.printStackTrace();
784 }
785 }
786 }
787 synchronized (fEntryListMap) {
788 fEntryListMap.put(trace, (ArrayList<ThreadEntry>) entryList.clone());
789 }
790 if (trace == fTrace) {
791 refresh();
792 }
793 for (ThreadEntry threadEntry : entryList) {
794 for (CallStackEntry callStackEntry : threadEntry.getChildren()) {
795 if (monitor.isCanceled()) {
796 return;
797 }
798 buildStatusEvents(trace, callStackEntry, monitor);
799 }
800 }
801 }
802
803 private void buildStatusEvents(ITmfTrace trace, CallStackEntry entry, IProgressMonitor monitor) {
804 ITmfStateSystem ss = entry.getTrace().getStateSystems().get(CallStackStateProvider.ID);
805 long start = ss.getStartTime();
806 long end = ss.getCurrentEndTime() + 1;
807 long resolution = Math.max(1, (end - start) / fDisplayWidth);
808 List<ITimeEvent> eventList = getEventList(entry, start, end, resolution, monitor);
809 if (monitor.isCanceled()) {
810 return;
811 }
812 entry.setEventList(eventList);
813 if (trace == fTrace) {
814 redraw();
815 }
816 }
817
818 private static List<ITimeEvent> getEventList(CallStackEntry entry,
819 long startTime, long endTime, long resolution,
820 IProgressMonitor monitor) {
821 ITmfStateSystem ss = entry.getTrace().getStateSystems().get(CallStackStateProvider.ID);
822 long start = Math.max(startTime, ss.getStartTime());
823 long end = Math.min(endTime, ss.getCurrentEndTime() + 1);
824 if (end <= start) {
825 return null;
826 }
827 List<ITimeEvent> eventList = null;
828 try {
829 List<ITmfStateInterval> stackIntervals = ss.queryHistoryRange(entry.getQuark(), start, end - 1, resolution, monitor);
830 eventList = new ArrayList<ITimeEvent>(stackIntervals.size());
831 long lastEndTime = -1;
832 boolean lastIsNull = true;
833 for (ITmfStateInterval statusInterval : stackIntervals) {
834 if (monitor.isCanceled()) {
835 return null;
836 }
837 long time = statusInterval.getStartTime();
838 long duration = statusInterval.getEndTime() - time + 1;
839 if (!statusInterval.getStateValue().isNull()) {
840 final int MODULO = CallStackPresentationProvider.NUM_COLORS / 2;
841 int value = statusInterval.getStateValue().toString().hashCode() % MODULO + MODULO;
842 eventList.add(new CallStackEvent(entry, time, duration, value));
843 lastIsNull = false;
844 } else {
845 if (lastEndTime != time && lastEndTime != -1 && lastIsNull) {
846 eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime));
847 }
848 eventList.add(new NullTimeEvent(entry, time, duration));
849 lastIsNull = true;
850 }
851 lastEndTime = time + duration;
852 }
853 } catch (AttributeNotFoundException e) {
854 e.printStackTrace();
855 } catch (TimeRangeException e) {
856 e.printStackTrace();
857 } catch (StateSystemDisposedException e) {
858 /* Ignored */
859 }
860 return eventList;
861 }
862
863 private void selectTime(long time) {
864 if (fEntryList == null) {
865 return;
866 }
867 fTimeGraphCombo.getTimeGraphViewer().setSelectedTime(time, true);
868 for (ThreadEntry threadEntry : fEntryList) {
869 ITmfStateSystem ss = threadEntry.fThreadTrace.getStateSystems().get(CallStackStateProvider.ID);
870 if (ss == null || !ss.waitUntilBuilt()) {
871 continue;
872 }
873 long queryTime = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), time));
874 for (CallStackEntry callStackEntry : threadEntry.getChildren()) {
875 try {
876 ITmfStateInterval stackLevelInterval = ss.querySingleState(queryTime, callStackEntry.getQuark());
877 ITmfStateValue nameValue = stackLevelInterval.getStateValue();
878 String name = ""; //$NON-NLS-1$
879 try {
880 if (nameValue.getType() == Type.STRING) {
881 name = nameValue.unboxStr();
882 } else if (nameValue.getType() == Type.INTEGER) {
883 name = "0x" + Integer.toHexString(nameValue.unboxInt()); //$NON-NLS-1$
884 } else if (nameValue.getType() == Type.LONG) {
885 name = "0x" + Long.toHexString(nameValue.unboxLong()); //$NON-NLS-1$
886 }
887 } catch (StateValueTypeException e) {
888 }
889 callStackEntry.setFunctionName(name);
890 if (name.length() > 0) {
891 callStackEntry.setStartTime(stackLevelInterval.getStartTime());
892 callStackEntry.setEndTime(stackLevelInterval.getEndTime() + 1);
893 }
894 } catch (AttributeNotFoundException e) {
895 e.printStackTrace();
896 } catch (TimeRangeException e) {
897 e.printStackTrace();
898 } catch (StateSystemDisposedException e) {
899 e.printStackTrace();
900 }
901 }
902 }
903 fTimeGraphCombo.refresh();
904 fTimeGraphCombo.getTimeGraphViewer().setSelectedTime(time, true);
905 }
906
907 private void refresh() {
908 Display.getDefault().asyncExec(new Runnable() {
909 @Override
910 public void run() {
911 if (fTimeGraphCombo.isDisposed()) {
912 return;
913 }
914 ITimeGraphEntry[] entries = null;
915 synchronized (fEntryListMap) {
916 fEntryList = fEntryListMap.get(fTrace);
917 if (fEntryList == null) {
918 fEntryList = new ArrayList<ThreadEntry>();
919 }
920 entries = fEntryList.toArray(new ITimeGraphEntry[0]);
921 }
922 fTimeGraphCombo.setInput(entries);
923 fTimeGraphCombo.getTimeGraphViewer().setTimeBounds(fStartTime, fEndTime);
924
925 long timestamp = fTrace == null ? 0 : fTrace.getCurrentTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
926 long startTime = fTrace == null ? 0 : fTrace.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
927 long endTime = fTrace == null ? 0 : fTrace.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
928 startTime = Math.max(startTime, fStartTime);
929 endTime = Math.min(endTime, fEndTime);
930 selectTime(timestamp);
931 fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
932 startZoomThread(startTime, endTime);
933 }
934 });
935 }
936
937 private void redraw() {
938 synchronized (fSyncObj) {
939 if (fRedrawState == State.IDLE) {
940 fRedrawState = State.BUSY;
941 } else {
942 fRedrawState = State.PENDING;
943 return;
944 }
945 }
946 Display.getDefault().asyncExec(new Runnable() {
947 @Override
948 public void run() {
949 if (fTimeGraphCombo.isDisposed()) {
950 return;
951 }
952 fTimeGraphCombo.redraw();
953 fTimeGraphCombo.update();
954 synchronized (fSyncObj) {
955 if (fRedrawState == State.PENDING) {
956 fRedrawState = State.IDLE;
957 redraw();
958 } else {
959 fRedrawState = State.IDLE;
960 }
961 }
962 }
963 });
964 }
965
966 private void startZoomThread(long startTime, long endTime) {
967 if (fZoomThread != null) {
968 fZoomThread.cancel();
969 }
970 fZoomThread = new ZoomThread(fEntryList, startTime, endTime);
971 fZoomThread.start();
972 }
973
974 private void makeActions() {
975 fPreviousItemAction = fTimeGraphCombo.getTimeGraphViewer().getPreviousItemAction();
976 fPreviousItemAction.setText(Messages.TmfTimeGraphViewer_PreviousItemActionNameText);
977 fPreviousItemAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousItemActionToolTipText);
978 fNextItemAction = fTimeGraphCombo.getTimeGraphViewer().getNextItemAction();
979 fNextItemAction.setText(Messages.TmfTimeGraphViewer_NextItemActionNameText);
980 fNextItemAction.setToolTipText(Messages.TmfTimeGraphViewer_NextItemActionToolTipText);
981 }
982
983 private void contributeToActionBars() {
984 IActionBars bars = getViewSite().getActionBars();
985 fillLocalToolBar(bars.getToolBarManager());
986
987 // Create pin action
988 contributePinActionToToolBar();
989 fPinAction.addPropertyChangeListener(new IPropertyChangeListener(){
990 @Override
991 public void propertyChange(PropertyChangeEvent event) {
992 if (IAction.CHECKED.equals(event.getProperty())) {
993 if (!isPinned()) {
994 if (fSavedRangeSyncSignal != null) {
995 synchToRange(fSavedRangeSyncSignal);
996 fSavedRangeSyncSignal = null;
997 }
998
999 if (fSavedTimeSyncSignal != null) {
1000 synchToTime(fSavedTimeSyncSignal);
1001 fSavedTimeSyncSignal = null;
1002 }
1003 }
1004 }
1005 }
1006 });
1007 }
1008
1009 private void fillLocalToolBar(IToolBarManager manager) {
1010 manager.add(fTimeGraphCombo.getTimeGraphViewer().getResetScaleAction());
1011 manager.add(getPreviousEventAction());
1012 manager.add(getNextEventAction());
1013 manager.add(fPreviousItemAction);
1014 manager.add(fNextItemAction);
1015 manager.add(fTimeGraphCombo.getTimeGraphViewer().getZoomInAction());
1016 manager.add(fTimeGraphCombo.getTimeGraphViewer().getZoomOutAction());
1017 manager.add(new Separator());
1018 }
1019
1020 /**
1021 * Get the the next event action.
1022 *
1023 * @return The action object
1024 */
1025 private Action getNextEventAction() {
1026 if (fNextEventAction == null) {
1027 fNextEventAction = new Action() {
1028 @Override
1029 public void run() {
1030 TimeGraphViewer viewer = fTimeGraphCombo.getTimeGraphViewer();
1031 ITimeGraphEntry entry = viewer.getSelection();
1032 if (entry instanceof CallStackEntry) {
1033 try {
1034 CallStackEntry callStackEntry = (CallStackEntry) entry;
1035 ITmfTrace trace = callStackEntry.getTrace();
1036 ITmfStateSystem ss = trace.getStateSystems().get(CallStackStateProvider.ID);
1037 long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectedTime()));
1038 ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
1039 int quark = ss.getQuarkRelative(threadEntry.getThreadQuark(), CallStackStateProvider.CALL_STACK);
1040 ITmfStateInterval stackInterval = ss.querySingleState(time, quark);
1041 long newTime = stackInterval.getEndTime() + 1;
1042 viewer.setSelectedTimeNotify(newTime, true);
1043 stackInterval = ss.querySingleState(Math.min(ss.getCurrentEndTime(), newTime), quark);
1044 int stackLevel = stackInterval.getStateValue().unboxInt();
1045 CallStackEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
1046 fTimeGraphCombo.setSelection(selectedEntry);
1047 viewer.getTimeGraphControl().fireSelectionChanged();
1048 startZoomThread(viewer.getTime0(), viewer.getTime1());
1049 } catch (AttributeNotFoundException e) {
1050 e.printStackTrace();
1051 } catch (TimeRangeException e) {
1052 e.printStackTrace();
1053 } catch (StateSystemDisposedException e) {
1054 e.printStackTrace();
1055 } catch (StateValueTypeException e) {
1056 e.printStackTrace();
1057 }
1058 }
1059 }
1060 };
1061
1062 fNextEventAction.setText(Messages.TmfTimeGraphViewer_NextEventActionNameText);
1063 fNextEventAction.setToolTipText(Messages.TmfTimeGraphViewer_NextEventActionToolTipText);
1064 fNextEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_EVENT));
1065 }
1066
1067 return fNextEventAction;
1068 }
1069
1070 /**
1071 * Get the previous event action.
1072 *
1073 * @return The Action object
1074 */
1075 private Action getPreviousEventAction() {
1076 if (fPrevEventAction == null) {
1077 fPrevEventAction = new Action() {
1078 @Override
1079 public void run() {
1080 TimeGraphViewer viewer = fTimeGraphCombo.getTimeGraphViewer();
1081 ITimeGraphEntry entry = viewer.getSelection();
1082 if (entry instanceof CallStackEntry) {
1083 try {
1084 CallStackEntry callStackEntry = (CallStackEntry) entry;
1085 ITmfTrace trace = callStackEntry.getTrace();
1086 ITmfStateSystem ss = trace.getStateSystems().get(CallStackStateProvider.ID);
1087 long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectedTime()));
1088 ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
1089 int quark = ss.getQuarkRelative(threadEntry.getThreadQuark(), CallStackStateProvider.CALL_STACK);
1090 ITmfStateInterval stackInterval = ss.querySingleState(time, quark);
1091 if (stackInterval.getStartTime() == time && time > ss.getStartTime()) {
1092 stackInterval = ss.querySingleState(time - 1, quark);
1093 }
1094 viewer.setSelectedTimeNotify(stackInterval.getStartTime(), true);
1095 int stackLevel = stackInterval.getStateValue().unboxInt();
1096 CallStackEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
1097 fTimeGraphCombo.setSelection(selectedEntry);
1098 viewer.getTimeGraphControl().fireSelectionChanged();
1099 startZoomThread(viewer.getTime0(), viewer.getTime1());
1100 } catch (AttributeNotFoundException e) {
1101 e.printStackTrace();
1102 } catch (TimeRangeException e) {
1103 e.printStackTrace();
1104 } catch (StateSystemDisposedException e) {
1105 e.printStackTrace();
1106 } catch (StateValueTypeException e) {
1107 e.printStackTrace();
1108 }
1109 }
1110 }
1111 };
1112
1113 fPrevEventAction.setText(Messages.TmfTimeGraphViewer_PreviousEventActionNameText);
1114 fPrevEventAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousEventActionToolTipText);
1115 fPrevEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_EVENT));
1116 }
1117
1118 return fPrevEventAction;
1119 }
1120
1121}
This page took 0.065693 seconds and 5 git commands to generate.