lttng: Add Eclipse 4.4 target
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / views / callstack / CallStackView.java
CommitLineData
e8251298 1/*******************************************************************************
60ae41e1 2 * Copyright (c) 2013, 2014 Ericsson
e8251298
PT
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
fec1ac0b 11 * Bernd Hufmann - Updated signal handling
e8251298
PT
12 *******************************************************************************/
13
14package org.eclipse.linuxtools.tmf.ui.views.callstack;
15
5da83da5 16import java.io.File;
e8251298 17import java.util.ArrayList;
46cc1ade 18import java.util.Comparator;
e8251298
PT
19import java.util.HashMap;
20import java.util.Iterator;
21import java.util.List;
52974e38 22import java.util.Map;
e8251298
PT
23
24import org.eclipse.core.runtime.IProgressMonitor;
5da83da5 25import org.eclipse.core.runtime.IStatus;
e8251298 26import org.eclipse.core.runtime.NullProgressMonitor;
5da83da5
AM
27import org.eclipse.core.runtime.Status;
28import org.eclipse.core.runtime.jobs.Job;
50659279 29import org.eclipse.jdt.annotation.Nullable;
e8251298
PT
30import org.eclipse.jface.action.Action;
31import org.eclipse.jface.action.IAction;
0fcf3b09 32import org.eclipse.jface.action.IStatusLineManager;
e8251298 33import org.eclipse.jface.action.IToolBarManager;
46cc1ade 34import org.eclipse.jface.action.MenuManager;
e8251298 35import org.eclipse.jface.action.Separator;
46cc1ade
PT
36import org.eclipse.jface.dialogs.IDialogSettings;
37import org.eclipse.jface.resource.ImageDescriptor;
e8251298
PT
38import org.eclipse.jface.util.IPropertyChangeListener;
39import org.eclipse.jface.util.PropertyChangeEvent;
40import org.eclipse.jface.viewers.DoubleClickEvent;
41import org.eclipse.jface.viewers.IDoubleClickListener;
42import org.eclipse.jface.viewers.ILabelProviderListener;
43import org.eclipse.jface.viewers.ISelection;
44import org.eclipse.jface.viewers.IStructuredSelection;
45import org.eclipse.jface.viewers.ITableLabelProvider;
46import org.eclipse.jface.viewers.ITreeContentProvider;
47import org.eclipse.jface.viewers.Viewer;
48import org.eclipse.linuxtools.internal.tmf.ui.Activator;
49import org.eclipse.linuxtools.internal.tmf.ui.ITmfImageConstants;
50import org.eclipse.linuxtools.internal.tmf.ui.Messages;
bcec0116
AM
51import org.eclipse.linuxtools.statesystem.core.ITmfStateSystem;
52import org.eclipse.linuxtools.statesystem.core.exceptions.AttributeNotFoundException;
53import org.eclipse.linuxtools.statesystem.core.exceptions.StateSystemDisposedException;
54import org.eclipse.linuxtools.statesystem.core.exceptions.StateValueTypeException;
55import org.eclipse.linuxtools.statesystem.core.exceptions.TimeRangeException;
56import org.eclipse.linuxtools.statesystem.core.interval.ITmfStateInterval;
57import org.eclipse.linuxtools.statesystem.core.statevalue.ITmfStateValue;
58import org.eclipse.linuxtools.statesystem.core.statevalue.ITmfStateValue.Type;
e8251298
PT
59import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal;
60import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
61import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;
62import org.eclipse.linuxtools.tmf.core.signal.TmfTraceClosedSignal;
fec1ac0b 63import org.eclipse.linuxtools.tmf.core.signal.TmfTraceOpenedSignal;
e8251298 64import org.eclipse.linuxtools.tmf.core.signal.TmfTraceSelectedSignal;
e8251298 65import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
f566d40a 66import org.eclipse.linuxtools.tmf.core.timestamp.TmfNanoTimestamp;
e8251298
PT
67import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
68import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
69import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestampDelta;
70import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
07b1111f 71import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
e8251298
PT
72import org.eclipse.linuxtools.tmf.ui.editors.ITmfTraceEditor;
73import org.eclipse.linuxtools.tmf.ui.views.TmfView;
74import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphRangeListener;
75import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;
76import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphCombo;
77import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphRangeUpdateEvent;
78import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphTimeEvent;
79import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphViewer;
80import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeEvent;
81import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
82import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.NullTimeEvent;
83import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.TimeEvent;
60b4d44c 84import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
e8251298
PT
85import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
86import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.TimeGraphSelection;
87import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
88import org.eclipse.swt.SWT;
89import org.eclipse.swt.events.ControlAdapter;
90import org.eclipse.swt.events.ControlEvent;
91import org.eclipse.swt.events.MouseAdapter;
92import org.eclipse.swt.events.MouseEvent;
93import org.eclipse.swt.graphics.Image;
94import org.eclipse.swt.widgets.Composite;
95import org.eclipse.swt.widgets.Display;
5da83da5 96import org.eclipse.swt.widgets.FileDialog;
46cc1ade
PT
97import org.eclipse.swt.widgets.Menu;
98import org.eclipse.swt.widgets.Tree;
e8251298
PT
99import org.eclipse.ui.IActionBars;
100import org.eclipse.ui.IEditorPart;
101
102/**
103 * Main implementation for the Call Stack view
104 *
105 * @author Patrick Tasse
106 * @since 2.0
107 */
108public class CallStackView extends TmfView {
109
110 // ------------------------------------------------------------------------
111 // Constants
112 // ------------------------------------------------------------------------
113
114 /** View ID. */
115 public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.callstack"; //$NON-NLS-1$
116
117 /**
118 * Redraw state enum
119 */
120 private enum State { IDLE, BUSY, PENDING }
121
46cc1ade 122 private static final String[] COLUMN_TIMES = new String[] {
e8251298
PT
123 Messages.CallStackView_FunctionColumn,
124 Messages.CallStackView_DepthColumn,
125 Messages.CallStackView_EntryTimeColumn,
126 Messages.CallStackView_ExitTimeColumn,
127 Messages.CallStackView_DurationColumn
128 };
129
52974e38
PT
130 private static final int[] COLUMN_WIDTHS = new int[] {
131 200,
132 50,
133 120,
134 120,
135 120
136 };
137
138 // Fraction of a function duration to be added as spacing
139 private static final double SPACING_RATIO = 0.01;
140
e8251298
PT
141 private static final Image THREAD_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/thread_obj.gif"); //$NON-NLS-1$
142 private static final Image STACKFRAME_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/stckframe_obj.gif"); //$NON-NLS-1$
143
5da83da5
AM
144 private static final String IMPORT_MAPPING_ICON_PATH = "icons/etool16/import.gif"; //$NON-NLS-1$
145
46cc1ade
PT
146 private static final ImageDescriptor SORT_BY_NAME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha.gif"); //$NON-NLS-1$
147 private static final ImageDescriptor SORT_BY_NAME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha_rev.gif"); //$NON-NLS-1$
148 private static final ImageDescriptor SORT_BY_ID_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num.gif"); //$NON-NLS-1$
149 private static final ImageDescriptor SORT_BY_ID_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num_rev.gif"); //$NON-NLS-1$
150 private static final ImageDescriptor SORT_BY_TIME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_time.gif"); //$NON-NLS-1$
151 private static final ImageDescriptor SORT_BY_TIME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_time_rev.gif"); //$NON-NLS-1$
152 private static final String SORT_OPTION_KEY = "sort.option"; //$NON-NLS-1$
153 private enum SortOption { BY_NAME, BY_NAME_REV, BY_ID, BY_ID_REV, BY_TIME, BY_TIME_REV }
154 private SortOption fSortOption;
155 private Comparator<ITimeGraphEntry> fThreadComparator = null;
156 private Action fSortByNameAction;
157 private Action fSortByIdAction;
158 private Action fSortByTimeAction;
159
e8251298
PT
160 // ------------------------------------------------------------------------
161 // Fields
162 // ------------------------------------------------------------------------
163
164 // The time graph combo
52974e38 165 private TimeGraphCombo fTimeGraphCombo;
e8251298
PT
166
167 // The selected trace
168 private ITmfTrace fTrace;
169
170 // The selected thread map
507b1336 171 private final Map<ITmfTrace, String> fSelectedThreadMap = new HashMap<>();
e8251298
PT
172
173 // The time graph entry list
60b4d44c 174 private List<TraceEntry> fEntryList;
e8251298
PT
175
176 // The trace to entry list hash map
60b4d44c 177 private final Map<ITmfTrace, ArrayList<TraceEntry>> fEntryListMap = new HashMap<>();
e8251298
PT
178
179 // The trace to build thread hash map
507b1336 180 private final Map<ITmfTrace, BuildThread> fBuildThreadMap = new HashMap<>();
e8251298 181
5da83da5
AM
182 /** The map to map function addresses to function names */
183 private Map<String, String> fNameMapping;
184
e8251298
PT
185 // The start time
186 private long fStartTime;
187
188 // The end time
189 private long fEndTime;
190
191 // The display width
192 private int fDisplayWidth;
193
194 // The next event action
195 private Action fNextEventAction;
196
197 // The previous event action
198 private Action fPrevEventAction;
199
200 // The next item action
201 private Action fNextItemAction;
202
203 // The previous item action
204 private Action fPreviousItemAction;
205
5da83da5
AM
206 /** The action to import a function-name mapping file */
207 private Action fImportMappingAction;
208
e8251298
PT
209 // The zoom thread
210 private ZoomThread fZoomThread;
211
212 // The redraw state used to prevent unnecessary queuing of display runnables
213 private State fRedrawState = State.IDLE;
214
215 // The redraw synchronization object
52974e38 216 private final Object fSyncObj = new Object();
e8251298
PT
217
218 // The saved time sync. signal used when switching off the pinning of a view
219 private TmfTimeSynchSignal fSavedTimeSyncSignal;
220
221 // The saved time range sync. signal used when switching off the pinning of a view
222 private TmfRangeSynchSignal fSavedRangeSyncSignal;
223
224 // ------------------------------------------------------------------------
225 // Classes
226 // ------------------------------------------------------------------------
227
60b4d44c
PT
228 private class TraceEntry extends TimeGraphEntry {
229 public TraceEntry(String name, long startTime, long endTime) {
230 super(name, startTime, endTime);
231 }
232
233 @Override
234 public boolean hasTimeEvents() {
235 return false;
236 }
237 }
238
239 private class ThreadEntry extends TimeGraphEntry {
da27e43a
PT
240 // The call stack quark
241 private final int fCallStackQuark;
50659279
AM
242 // The state system from which this entry comes
243 private final ITmfStateSystem fSS;
46cc1ade
PT
244 // The thread id
245 private final long fThreadId;
e8251298 246
46cc1ade 247 public ThreadEntry(ITmfStateSystem ss, String name, long threadId, int callStackQuark, long startTime, long endTime) {
60b4d44c 248 super(name, startTime, endTime);
da27e43a 249 fCallStackQuark = callStackQuark;
46cc1ade 250 fThreadId = threadId;
da27e43a 251 fSS = ss;
e8251298
PT
252 }
253
e8251298
PT
254 @Override
255 public boolean hasTimeEvents() {
256 return false;
257 }
258
da27e43a
PT
259 public int getCallStackQuark() {
260 return fCallStackQuark;
e8251298
PT
261 }
262
46cc1ade
PT
263 public long getThreadId() {
264 return fThreadId;
265 }
266
50659279
AM
267 @Nullable
268 public ITmfStateSystem getStateSystem() {
269 return fSS;
e8251298 270 }
e8251298
PT
271 }
272
46cc1ade
PT
273 private class ThreadNameComparator implements Comparator<ITimeGraphEntry> {
274 private boolean reverse;
275 public ThreadNameComparator(boolean reverse) {
276 this.reverse = reverse;
277 }
278 @Override
279 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
280 return reverse ? o2.getName().compareTo(o1.getName()) :
281 o1.getName().compareTo(o2.getName());
282 }
283 }
284
285 private class ThreadIdComparator implements Comparator<ITimeGraphEntry> {
286 private boolean reverse;
287 public ThreadIdComparator(boolean reverse) {
288 this.reverse = reverse;
289 }
290 @Override
291 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
292 ThreadEntry t1 = (ThreadEntry) o1;
293 ThreadEntry t2 = (ThreadEntry) o2;
294 return reverse ? Long.compare(t2.getThreadId(), t1.getThreadId()) :
295 Long.compare(t1.getThreadId(), t2.getThreadId());
296 }
297 }
298
299 private class ThreadTimeComparator implements Comparator<ITimeGraphEntry> {
300 private boolean reverse;
301 public ThreadTimeComparator(boolean reverse) {
302 this.reverse = reverse;
303 }
304 @Override
305 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
306 return reverse ? Long.compare(o2.getStartTime(), o1.getStartTime()) :
307 Long.compare(o1.getStartTime(), o2.getStartTime());
308 }
309 }
310
e8251298
PT
311 private class TreeContentProvider implements ITreeContentProvider {
312
313 @Override
314 public void dispose() {
315 }
316
317 @Override
318 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
319 }
320
321 @Override
322 public Object[] getElements(Object inputElement) {
323 return (ITimeGraphEntry[]) inputElement;
324 }
325
326 @Override
327 public Object[] getChildren(Object parentElement) {
328 ITimeGraphEntry entry = (ITimeGraphEntry) parentElement;
329 return entry.getChildren().toArray();
330 }
331
332 @Override
333 public Object getParent(Object element) {
334 ITimeGraphEntry entry = (ITimeGraphEntry) element;
335 return entry.getParent();
336 }
337
338 @Override
339 public boolean hasChildren(Object element) {
340 ITimeGraphEntry entry = (ITimeGraphEntry) element;
341 return entry.hasChildren();
342 }
343
344 }
345
346 private class TreeLabelProvider implements ITableLabelProvider {
347
348 @Override
349 public void addListener(ILabelProviderListener listener) {
350 }
351
352 @Override
353 public void dispose() {
354 }
355
356 @Override
357 public boolean isLabelProperty(Object element, String property) {
358 return false;
359 }
360
361 @Override
362 public void removeListener(ILabelProviderListener listener) {
363 }
364
365 @Override
366 public Image getColumnImage(Object element, int columnIndex) {
367 if (columnIndex == 0) {
368 if (element instanceof ThreadEntry) {
369 return THREAD_IMAGE;
370 } else if (element instanceof CallStackEntry) {
371 CallStackEntry entry = (CallStackEntry) element;
372 if (entry.getFunctionName().length() > 0) {
373 return STACKFRAME_IMAGE;
374 }
375 }
376 }
377 return null;
378 }
379
380 @Override
381 public String getColumnText(Object element, int columnIndex) {
60b4d44c 382 if (element instanceof CallStackEntry) {
e8251298
PT
383 CallStackEntry entry = (CallStackEntry) element;
384 if (columnIndex == 0) {
385 return entry.getFunctionName();
52974e38
PT
386 } else if (columnIndex == 1 && entry.getFunctionName().length() > 0) {
387 int depth = entry.getStackLevel();
388 return Integer.toString(depth);
389 } else if (columnIndex == 2 && entry.getFunctionName().length() > 0) {
60b4d44c 390 ITmfTimestamp ts = new TmfTimestamp(entry.getFunctionEntryTime(), ITmfTimestamp.NANOSECOND_SCALE);
52974e38
PT
391 return ts.toString();
392 } else if (columnIndex == 3 && entry.getFunctionName().length() > 0) {
60b4d44c 393 ITmfTimestamp ts = new TmfTimestamp(entry.getFunctionExitTime(), ITmfTimestamp.NANOSECOND_SCALE);
52974e38
PT
394 return ts.toString();
395 } else if (columnIndex == 4 && entry.getFunctionName().length() > 0) {
60b4d44c 396 ITmfTimestamp ts = new TmfTimestampDelta(entry.getFunctionExitTime() - entry.getFunctionEntryTime(), ITmfTimestamp.NANOSECOND_SCALE);
52974e38 397 return ts.toString();
e8251298 398 }
60b4d44c
PT
399 } else if (element instanceof ITimeGraphEntry) {
400 if (columnIndex == 0) {
401 return ((ITimeGraphEntry) element).getName();
402 }
e8251298
PT
403 }
404 return ""; //$NON-NLS-1$
405 }
406
407 }
408
409 private class BuildThread extends Thread {
410 private final ITmfTrace fBuildTrace;
411 private final IProgressMonitor fMonitor;
412
413 public BuildThread(ITmfTrace trace) {
414 super("CallStackView build"); //$NON-NLS-1$
415 fBuildTrace = trace;
416 fMonitor = new NullProgressMonitor();
417 }
418
419 @Override
420 public void run() {
421 buildThreadList(fBuildTrace, fMonitor);
422 synchronized (fBuildThreadMap) {
423 fBuildThreadMap.remove(this);
424 }
425 }
426
427 public void cancel() {
428 fMonitor.setCanceled(true);
429 }
430 }
431
432 private class ZoomThread extends Thread {
60b4d44c 433 private final List<TraceEntry> fZoomEntryList;
e8251298
PT
434 private final long fZoomStartTime;
435 private final long fZoomEndTime;
436 private final IProgressMonitor fMonitor;
437
60b4d44c
PT
438 public ZoomThread(List<TraceEntry> entryList, long startTime, long endTime) {
439 super("CallStackView zoom"); //$NON-NLS-1$
e8251298
PT
440 fZoomEntryList = entryList;
441 fZoomStartTime = startTime;
442 fZoomEndTime = endTime;
443 fMonitor = new NullProgressMonitor();
444 }
445
446 @Override
447 public void run() {
448 if (fZoomEntryList == null) {
449 return;
450 }
451 long resolution = Math.max(1, (fZoomEndTime - fZoomStartTime) / fDisplayWidth);
60b4d44c
PT
452 for (TraceEntry traceEntry : fZoomEntryList) {
453 for (ITimeGraphEntry threadEntry : traceEntry.getChildren()) {
454 ITmfStateSystem ss = ((ThreadEntry) threadEntry).getStateSystem();
455 if (ss == null) {
456 continue;
e8251298 457 }
60b4d44c
PT
458 ss.waitUntilBuilt();
459 if (ss.isCancelled()) {
460 continue;
461 }
462 for (ITimeGraphEntry child : threadEntry.getChildren()) {
463 if (fMonitor.isCanceled()) {
464 break;
465 }
466 CallStackEntry entry = (CallStackEntry) child;
467 if (fZoomStartTime <= fStartTime && fZoomEndTime >= fEndTime) {
468 entry.setZoomedEventList(null);
469 } else {
470 List<ITimeEvent> zoomedEventList = getEventList(entry, fZoomStartTime, fZoomEndTime, resolution, fMonitor);
471 if (zoomedEventList != null) {
472 entry.setZoomedEventList(zoomedEventList);
473 }
e8251298 474 }
60b4d44c 475 redraw();
e8251298 476 }
e8251298
PT
477 }
478 }
479 }
480
481 public void cancel() {
482 fMonitor.setCanceled(true);
483 }
484 }
485
486 // ------------------------------------------------------------------------
487 // Constructors
488 // ------------------------------------------------------------------------
489
490 /**
491 * Default constructor
492 */
493 public CallStackView() {
494 super(ID);
495 fDisplayWidth = Display.getDefault().getBounds().width;
496 }
497
498 // ------------------------------------------------------------------------
499 // ViewPart
500 // ------------------------------------------------------------------------
501
502 @Override
503 public void createPartControl(Composite parent) {
504 fTimeGraphCombo = new TimeGraphCombo(parent, SWT.NONE);
505
506 fTimeGraphCombo.setTreeContentProvider(new TreeContentProvider());
507
508 fTimeGraphCombo.setTreeLabelProvider(new TreeLabelProvider());
509
46cc1ade 510 fTimeGraphCombo.setTreeColumns(COLUMN_TIMES);
e8251298 511
52974e38
PT
512 fTimeGraphCombo.getTreeViewer().getTree().getColumn(0).setWidth(COLUMN_WIDTHS[0]);
513 fTimeGraphCombo.getTreeViewer().getTree().getColumn(1).setWidth(COLUMN_WIDTHS[1]);
514 fTimeGraphCombo.getTreeViewer().getTree().getColumn(2).setWidth(COLUMN_WIDTHS[2]);
515 fTimeGraphCombo.getTreeViewer().getTree().getColumn(3).setWidth(COLUMN_WIDTHS[3]);
516 fTimeGraphCombo.getTreeViewer().getTree().getColumn(4).setWidth(COLUMN_WIDTHS[4]);
e8251298 517
5da83da5 518 fTimeGraphCombo.setTimeGraphProvider(new CallStackPresentationProvider(this));
e8251298
PT
519 fTimeGraphCombo.getTimeGraphViewer().setTimeFormat(TimeFormat.CALENDAR);
520
521 fTimeGraphCombo.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
522 @Override
523 public void timeRangeUpdated(TimeGraphRangeUpdateEvent event) {
524 long startTime = event.getStartTime();
525 long endTime = event.getEndTime();
f566d40a 526 TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(startTime), new TmfNanoTimestamp(endTime));
0fcf3b09 527 broadcast(new TmfRangeSynchSignal(CallStackView.this, range));
e8251298
PT
528 startZoomThread(startTime, endTime);
529 }
530 });
531
532 fTimeGraphCombo.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
533 @Override
534 public void timeSelected(TimeGraphTimeEvent event) {
0fcf3b09
PT
535 long beginTime = event.getBeginTime();
536 long endTime = event.getEndTime();
537 selectTime(beginTime);
f566d40a 538 broadcast(new TmfTimeSynchSignal(CallStackView.this, new TmfNanoTimestamp(beginTime), new TmfNanoTimestamp(endTime)));
e8251298
PT
539 }
540 });
541
542 fTimeGraphCombo.getTimeGraphViewer().getControl().addControlListener(new ControlAdapter() {
543 @Override
544 public void controlResized(ControlEvent e) {
545 fDisplayWidth = fTimeGraphCombo.getTimeGraphViewer().getControl().getSize().x;
546 if (fEntryList != null) {
547 startZoomThread(fTimeGraphCombo.getTimeGraphViewer().getTime0(), fTimeGraphCombo.getTimeGraphViewer().getTime1());
548 }
549 }
550 });
551
552 fTimeGraphCombo.getTreeViewer().addDoubleClickListener(new IDoubleClickListener() {
553 @Override
554 public void doubleClick(DoubleClickEvent event) {
555 Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
556 if (selection instanceof CallStackEntry) {
557 CallStackEntry entry = (CallStackEntry) selection;
558 if (entry.getFunctionName().length() > 0) {
60b4d44c
PT
559 long entryTime = entry.getFunctionEntryTime();
560 long exitTime = entry.getFunctionExitTime();
561 long spacingTime = (long) ((exitTime - entryTime) * SPACING_RATIO);
562 entryTime -= spacingTime;
563 exitTime += spacingTime;
564 TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(entryTime), new TmfNanoTimestamp(exitTime));
0fcf3b09 565 broadcast(new TmfRangeSynchSignal(CallStackView.this, range));
60b4d44c
PT
566 fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(entryTime, exitTime);
567 startZoomThread(entryTime, exitTime);
e8251298
PT
568 }
569 }
570 }
571 });
572
573 fTimeGraphCombo.getTimeGraphViewer().getTimeGraphControl().addMouseListener(new MouseAdapter() {
574 @Override
575 public void mouseDoubleClick(MouseEvent e) {
576 TimeGraphControl timeGraphControl = fTimeGraphCombo.getTimeGraphViewer().getTimeGraphControl();
577 ISelection selection = timeGraphControl.getSelection();
578 if (selection instanceof TimeGraphSelection) {
579 Object o = ((TimeGraphSelection) selection).getFirstElement();
580 if (o instanceof CallStackEvent) {
581 CallStackEvent event = (CallStackEvent) o;
582 long startTime = event.getTime();
583 long endTime = startTime + event.getDuration();
52974e38 584 long spacingTime = (long) ((endTime - startTime) * SPACING_RATIO);
e8251298
PT
585 startTime -= spacingTime;
586 endTime += spacingTime;
f566d40a 587 TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(startTime), new TmfNanoTimestamp(endTime));
0fcf3b09 588 broadcast(new TmfRangeSynchSignal(CallStackView.this, range));
e8251298
PT
589 fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
590 startZoomThread(startTime, endTime);
591 }
592 }
593 }
594 });
595
0fcf3b09
PT
596 IStatusLineManager statusLineManager = getViewSite().getActionBars().getStatusLineManager();
597 fTimeGraphCombo.getTimeGraphViewer().getTimeGraphControl().setStatusLineManager(statusLineManager);
598
e8251298
PT
599 // View Action Handling
600 makeActions();
601 contributeToActionBars();
46cc1ade
PT
602 createContextMenu();
603 loadSortOption();
e8251298
PT
604
605 IEditorPart editor = getSite().getPage().getActiveEditor();
606 if (editor instanceof ITmfTraceEditor) {
607 ITmfTrace trace = ((ITmfTraceEditor) editor).getTrace();
608 if (trace != null) {
609 traceSelected(new TmfTraceSelectedSignal(this, trace));
610 }
611 }
612 }
613
614 @Override
615 public void setFocus() {
616 fTimeGraphCombo.setFocus();
617 }
618
619 // ------------------------------------------------------------------------
620 // Signal handlers
621 // ------------------------------------------------------------------------
fec1ac0b
BH
622 /**
623 * Handler for the trace opened signal.
624 * @param signal
625 * The incoming signal
626 * @since 2.0
627 */
628 @TmfSignalHandler
629 public void traceOpened(TmfTraceOpenedSignal signal) {
630 fTrace = signal.getTrace();
631 loadTrace();
632 }
e8251298
PT
633
634 /**
635 * Handler for the trace selected signal
636 *
637 * @param signal
638 * The incoming signal
639 */
640 @TmfSignalHandler
641 public void traceSelected(final TmfTraceSelectedSignal signal) {
642 if (signal.getTrace() == fTrace) {
643 return;
644 }
645 fTrace = signal.getTrace();
fec1ac0b 646 loadTrace();
e8251298
PT
647 }
648
649 /**
650 * Trace is closed: clear the data structures and the view
651 *
652 * @param signal the signal received
653 */
654 @TmfSignalHandler
655 public void traceClosed(final TmfTraceClosedSignal signal) {
656 synchronized (fBuildThreadMap) {
657 BuildThread buildThread = fBuildThreadMap.remove(signal.getTrace());
658 if (buildThread != null) {
659 buildThread.cancel();
660 }
661 }
662 synchronized (fEntryListMap) {
663 fEntryListMap.remove(signal.getTrace());
664 }
665 fSelectedThreadMap.remove(signal.getTrace());
666 if (signal.getTrace() == fTrace) {
667 fTrace = null;
668 fStartTime = 0;
669 fEndTime = 0;
670 refresh();
671 }
672 }
673
674 /**
675 * Handler for the TimeSynch signal
676 *
677 * @param signal
678 * The incoming signal
679 */
680 @TmfSignalHandler
681 public void synchToTime(final TmfTimeSynchSignal signal) {
682
0fcf3b09 683 fSavedTimeSyncSignal = isPinned() ? new TmfTimeSynchSignal(signal.getSource(), signal.getBeginTime(), signal.getEndTime()) : null;
e8251298
PT
684
685 if (signal.getSource() == this || fTrace == null || isPinned()) {
686 return;
687 }
0fcf3b09
PT
688 final long beginTime = signal.getBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
689 final long endTime = signal.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
e8251298
PT
690 Display.getDefault().asyncExec(new Runnable() {
691 @Override
692 public void run() {
693 if (fTimeGraphCombo.isDisposed()) {
694 return;
695 }
0fcf3b09
PT
696 if (beginTime == endTime) {
697 fTimeGraphCombo.getTimeGraphViewer().setSelectedTime(beginTime, true);
698 } else {
699 fTimeGraphCombo.getTimeGraphViewer().setSelectionRange(beginTime, endTime);
700 }
701 selectTime(beginTime);
e8251298
PT
702 startZoomThread(fTimeGraphCombo.getTimeGraphViewer().getTime0(), fTimeGraphCombo.getTimeGraphViewer().getTime1());
703 if (fEntryList == null) {
704 return;
705 }
706 TimeGraphViewer viewer = fTimeGraphCombo.getTimeGraphViewer();
60b4d44c
PT
707 for (TraceEntry traceEntry : fEntryList) {
708 for (ITimeGraphEntry child : traceEntry.getChildren()) {
709 ThreadEntry threadEntry = (ThreadEntry) child;
710 ITmfStateSystem ss = threadEntry.getStateSystem();
711 if (ss == null || beginTime < ss.getStartTime() || beginTime > ss.getCurrentEndTime()) {
712 continue;
713 }
714 try {
715 int quark = threadEntry.getCallStackQuark();
716 ITmfStateInterval stackInterval = ss.querySingleState(beginTime, quark);
717 if (beginTime == stackInterval.getStartTime()) {
718 int stackLevel = stackInterval.getStateValue().unboxInt();
719 ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
720 fTimeGraphCombo.setSelection(selectedEntry);
721 viewer.getTimeGraphControl().fireSelectionChanged();
722 break;
723 }
724 } catch (AttributeNotFoundException e) {
725 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
726 } catch (TimeRangeException e) {
727 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
728 } catch (StateSystemDisposedException e) {
729 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
730 } catch (StateValueTypeException e) {
731 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298 732 }
e8251298
PT
733 }
734 }
735 }
736 });
737 }
738
739 /**
740 * Handler for the RangeSynch signal
741 *
742 * @param signal
743 * The incoming signal
744 */
745 @TmfSignalHandler
746 public void synchToRange(final TmfRangeSynchSignal signal) {
747
748 if (isPinned()) {
749 fSavedRangeSyncSignal =
0fcf3b09 750 new TmfRangeSynchSignal(signal.getSource(), new TmfTimeRange(signal.getCurrentRange().getStartTime(), signal.getCurrentRange().getEndTime()));
e8251298
PT
751
752 fSavedTimeSyncSignal = null;
753 }
754
755 if (signal.getSource() == this || fTrace == null || isPinned()) {
756 return;
757 }
758 if (signal.getCurrentRange().getIntersection(fTrace.getTimeRange()) == null) {
759 return;
760 }
761 final long startTime = signal.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
762 final long endTime = signal.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
e8251298
PT
763 Display.getDefault().asyncExec(new Runnable() {
764 @Override
765 public void run() {
766 if (fTimeGraphCombo.isDisposed()) {
767 return;
768 }
769 fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
e8251298
PT
770 startZoomThread(startTime, endTime);
771 }
772 });
773 }
774
775 // ------------------------------------------------------------------------
776 // Internal
777 // ------------------------------------------------------------------------
5da83da5 778
fec1ac0b
BH
779 private void loadTrace() {
780 synchronized (fEntryListMap) {
781 fEntryList = fEntryListMap.get(fTrace);
782 if (fEntryList == null) {
783 synchronized (fBuildThreadMap) {
784 BuildThread buildThread = new BuildThread(fTrace);
785 fBuildThreadMap.put(fTrace, buildThread);
786 buildThread.start();
787 }
788 } else {
789 fStartTime = fTrace.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
790 fEndTime = fTrace.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
791 refresh();
792 }
793 }
794 }
e8251298
PT
795
796 private void buildThreadList(final ITmfTrace trace, IProgressMonitor monitor) {
797 fStartTime = Long.MAX_VALUE;
798 fEndTime = Long.MIN_VALUE;
07b1111f 799 ITmfTrace[] traces = TmfTraceManager.getTraceSet(trace);
60b4d44c 800 ArrayList<TraceEntry> entryList = new ArrayList<>();
e8251298
PT
801 for (ITmfTrace aTrace : traces) {
802 if (monitor.isCanceled()) {
803 return;
804 }
da27e43a
PT
805 AbstractCallStackAnalysis module = getCallStackModule(trace);
806 if (module == null) {
807 return;
808 }
809 ITmfStateSystem ss = module.getStateSystem();
2002c638
AM
810 if (ss == null) {
811 addUnavailableEntry(aTrace, entryList);
812 continue;
813 }
814 ss.waitUntilBuilt();
815 if (ss.isCancelled()) {
816 addUnavailableEntry(aTrace, entryList);
e8251298
PT
817 continue;
818 }
819 long startTime = ss.getStartTime();
820 long endTime = ss.getCurrentEndTime() + 1;
821 fStartTime = Math.min(fStartTime, startTime);
822 fEndTime = Math.max(fEndTime, endTime);
da27e43a
PT
823 String[] threadPaths = module.getThreadsPattern();
824 List<Integer> threadQuarks = ss.getQuarks(threadPaths);
60b4d44c 825 TraceEntry traceEntry = new TraceEntry(trace.getName(), startTime, endTime);
46cc1ade 826 traceEntry.sortChildren(fThreadComparator);
60b4d44c 827 entryList.add(traceEntry);
e8251298
PT
828 for (int i = 0; i < threadQuarks.size(); i++) {
829 if (monitor.isCanceled()) {
830 return;
831 }
832 int threadQuark = threadQuarks.get(i);
e8251298 833 try {
da27e43a
PT
834 String[] callStackPath = module.getCallStackPath();
835 int callStackQuark = ss.getQuarkRelative(threadQuark, callStackPath);
60b4d44c 836 String threadName = ss.getAttributeName(threadQuark);
46cc1ade
PT
837 long threadId = ss.querySingleState(ss.getCurrentEndTime() , threadQuark).getStateValue().unboxLong();
838 long start = startTime;
839 ITmfStateInterval startInterval = ss.querySingleState(startTime, callStackQuark);
840 if (startInterval.getStateValue().isNull()) {
841 start = Math.min(startInterval.getEndTime() + 1, endTime);
842 }
843 long end = endTime;
844 ITmfStateInterval endInterval = ss.querySingleState(ss.getCurrentEndTime(), callStackQuark);
845 if (endInterval.getStateValue().isNull()) {
846 end = endInterval.getStartTime() == startTime ? endTime : endInterval.getStartTime();
847 }
848 ThreadEntry threadEntry = new ThreadEntry(ss, threadName, threadId, callStackQuark, start, end);
60b4d44c 849 traceEntry.addChild(threadEntry);
e8251298 850 int level = 1;
da27e43a 851 for (int stackLevelQuark : ss.getSubAttributes(callStackQuark, false)) {
60b4d44c 852 CallStackEntry callStackEntry = new CallStackEntry(threadName, stackLevelQuark, level++, aTrace, ss);
e8251298
PT
853 threadEntry.addChild(callStackEntry);
854 }
855 } catch (AttributeNotFoundException e) {
52974e38 856 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
46cc1ade
PT
857 } catch (StateSystemDisposedException e) {
858 /* Ignored */
e8251298
PT
859 }
860 }
861 }
862 synchronized (fEntryListMap) {
507b1336 863 fEntryListMap.put(trace, new ArrayList<>(entryList));
e8251298
PT
864 }
865 if (trace == fTrace) {
866 refresh();
867 }
60b4d44c
PT
868 for (TraceEntry traceEntry : entryList) {
869 for (ITimeGraphEntry threadEntry : traceEntry.getChildren()) {
870 for (ITimeGraphEntry callStackEntry : threadEntry.getChildren()) {
871 if (monitor.isCanceled()) {
872 return;
873 }
874 buildStatusEvents(trace, (CallStackEntry) callStackEntry, monitor);
e8251298 875 }
e8251298
PT
876 }
877 }
878 }
879
60b4d44c
PT
880 private void addUnavailableEntry(ITmfTrace trace, List<TraceEntry> list) {
881 String name = Messages.CallStackView_StackInfoNotAvailable + ' ' + '(' + trace.getName() + ')';
882 TraceEntry unavailableEntry = new TraceEntry(name, 0, 0);
883 list.add(unavailableEntry);
2002c638
AM
884 }
885
e8251298 886 private void buildStatusEvents(ITmfTrace trace, CallStackEntry entry, IProgressMonitor monitor) {
da27e43a 887 ITmfStateSystem ss = entry.getStateSystem();
e8251298
PT
888 long start = ss.getStartTime();
889 long end = ss.getCurrentEndTime() + 1;
890 long resolution = Math.max(1, (end - start) / fDisplayWidth);
891 List<ITimeEvent> eventList = getEventList(entry, start, end, resolution, monitor);
892 if (monitor.isCanceled()) {
893 return;
894 }
895 entry.setEventList(eventList);
896 if (trace == fTrace) {
897 redraw();
898 }
899 }
900
901 private static List<ITimeEvent> getEventList(CallStackEntry entry,
902 long startTime, long endTime, long resolution,
903 IProgressMonitor monitor) {
da27e43a 904 ITmfStateSystem ss = entry.getStateSystem();
e8251298
PT
905 long start = Math.max(startTime, ss.getStartTime());
906 long end = Math.min(endTime, ss.getCurrentEndTime() + 1);
907 if (end <= start) {
908 return null;
909 }
910 List<ITimeEvent> eventList = null;
911 try {
912 List<ITmfStateInterval> stackIntervals = ss.queryHistoryRange(entry.getQuark(), start, end - 1, resolution, monitor);
507b1336 913 eventList = new ArrayList<>(stackIntervals.size());
e8251298
PT
914 long lastEndTime = -1;
915 boolean lastIsNull = true;
916 for (ITmfStateInterval statusInterval : stackIntervals) {
917 if (monitor.isCanceled()) {
918 return null;
919 }
920 long time = statusInterval.getStartTime();
921 long duration = statusInterval.getEndTime() - time + 1;
922 if (!statusInterval.getStateValue().isNull()) {
52974e38
PT
923 final int modulo = CallStackPresentationProvider.NUM_COLORS / 2;
924 int value = statusInterval.getStateValue().toString().hashCode() % modulo + modulo;
e8251298
PT
925 eventList.add(new CallStackEvent(entry, time, duration, value));
926 lastIsNull = false;
927 } else {
beb1b921
PT
928 if (lastEndTime == -1) {
929 // add null event if it intersects the start time
930 eventList.add(new NullTimeEvent(entry, time, duration));
931 } else {
932 if (lastEndTime != time && lastIsNull) {
933 // add unknown event if between two null states
934 eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime));
935 }
936 if (time + duration >= endTime) {
937 // add null event if it intersects the end time
938 eventList.add(new NullTimeEvent(entry, time, duration));
939 }
e8251298 940 }
e8251298
PT
941 lastIsNull = true;
942 }
943 lastEndTime = time + duration;
944 }
945 } catch (AttributeNotFoundException e) {
52974e38 946 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298 947 } catch (TimeRangeException e) {
52974e38 948 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298
PT
949 } catch (StateSystemDisposedException e) {
950 /* Ignored */
951 }
952 return eventList;
953 }
954
955 private void selectTime(long time) {
956 if (fEntryList == null) {
957 return;
958 }
60b4d44c
PT
959 for (TraceEntry traceEntry : fEntryList) {
960 for (ITimeGraphEntry threadEntry : traceEntry.getChildren()) {
961 ITmfStateSystem ss = ((ThreadEntry) threadEntry).getStateSystem();
962 if (ss == null) {
963 continue;
964 }
965 ss.waitUntilBuilt();
966 if (ss.isCancelled()) {
967 continue;
968 }
969 long queryTime = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), time));
970 for (ITimeGraphEntry child : threadEntry.getChildren()) {
971 CallStackEntry callStackEntry = (CallStackEntry) child;
e8251298 972 try {
60b4d44c
PT
973 ITmfStateInterval stackLevelInterval = ss.querySingleState(queryTime, callStackEntry.getQuark());
974 ITmfStateValue nameValue = stackLevelInterval.getStateValue();
975 String name = ""; //$NON-NLS-1$
976 try {
977 if (nameValue.getType() == Type.STRING) {
978 String address = nameValue.unboxStr();
979 name = getFunctionName(address);
980 } else if (nameValue.getType() == Type.INTEGER) {
981 name = "0x" + Integer.toHexString(nameValue.unboxInt()); //$NON-NLS-1$
982 } else if (nameValue.getType() == Type.LONG) {
983 name = "0x" + Long.toHexString(nameValue.unboxLong()); //$NON-NLS-1$
984 }
985 } catch (StateValueTypeException e) {
e8251298 986 }
60b4d44c
PT
987 callStackEntry.setFunctionName(name);
988 if (name.length() > 0) {
989 callStackEntry.setFunctionEntryTime(stackLevelInterval.getStartTime());
990 callStackEntry.setFunctionExitTime(stackLevelInterval.getEndTime() + 1);
991 }
992 } catch (AttributeNotFoundException e) {
993 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
994 } catch (TimeRangeException e) {
995 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
996 } catch (StateSystemDisposedException e) {
997 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298 998 }
e8251298
PT
999 }
1000 }
1001 }
1002 fTimeGraphCombo.refresh();
e8251298
PT
1003 }
1004
1005 private void refresh() {
1006 Display.getDefault().asyncExec(new Runnable() {
1007 @Override
1008 public void run() {
1009 if (fTimeGraphCombo.isDisposed()) {
1010 return;
1011 }
1012 ITimeGraphEntry[] entries = null;
1013 synchronized (fEntryListMap) {
1014 fEntryList = fEntryListMap.get(fTrace);
1015 if (fEntryList == null) {
507b1336 1016 fEntryList = new ArrayList<>();
e8251298
PT
1017 }
1018 entries = fEntryList.toArray(new ITimeGraphEntry[0]);
46cc1ade
PT
1019 for (TraceEntry traceEntry : fEntryList) {
1020 traceEntry.sortChildren(fThreadComparator);
1021 }
e8251298
PT
1022 }
1023 fTimeGraphCombo.setInput(entries);
1024 fTimeGraphCombo.getTimeGraphViewer().setTimeBounds(fStartTime, fEndTime);
1025
0fcf3b09
PT
1026 long selectionBeginTime = fTrace == null ? 0 : fTraceManager.getSelectionBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1027 long selectionEndTime = fTrace == null ? 0 : fTraceManager.getSelectionEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
248af329
AM
1028 long startTime = fTrace == null ? 0 : fTraceManager.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1029 long endTime = fTrace == null ? 0 : fTraceManager.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
e8251298
PT
1030 startTime = Math.max(startTime, fStartTime);
1031 endTime = Math.min(endTime, fEndTime);
0fcf3b09
PT
1032 fTimeGraphCombo.getTimeGraphViewer().setSelectionRange(selectionBeginTime, selectionEndTime);
1033 selectTime(selectionBeginTime);
e8251298
PT
1034 fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
1035 startZoomThread(startTime, endTime);
1036 }
1037 });
1038 }
1039
1040 private void redraw() {
1041 synchronized (fSyncObj) {
1042 if (fRedrawState == State.IDLE) {
1043 fRedrawState = State.BUSY;
1044 } else {
1045 fRedrawState = State.PENDING;
1046 return;
1047 }
1048 }
1049 Display.getDefault().asyncExec(new Runnable() {
1050 @Override
1051 public void run() {
1052 if (fTimeGraphCombo.isDisposed()) {
1053 return;
1054 }
1055 fTimeGraphCombo.redraw();
1056 fTimeGraphCombo.update();
1057 synchronized (fSyncObj) {
1058 if (fRedrawState == State.PENDING) {
1059 fRedrawState = State.IDLE;
1060 redraw();
1061 } else {
1062 fRedrawState = State.IDLE;
1063 }
1064 }
1065 }
1066 });
1067 }
1068
1069 private void startZoomThread(long startTime, long endTime) {
1070 if (fZoomThread != null) {
1071 fZoomThread.cancel();
1072 }
1073 fZoomThread = new ZoomThread(fEntryList, startTime, endTime);
1074 fZoomThread.start();
1075 }
1076
1077 private void makeActions() {
1078 fPreviousItemAction = fTimeGraphCombo.getTimeGraphViewer().getPreviousItemAction();
1079 fPreviousItemAction.setText(Messages.TmfTimeGraphViewer_PreviousItemActionNameText);
1080 fPreviousItemAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousItemActionToolTipText);
1081 fNextItemAction = fTimeGraphCombo.getTimeGraphViewer().getNextItemAction();
1082 fNextItemAction.setText(Messages.TmfTimeGraphViewer_NextItemActionNameText);
1083 fNextItemAction.setToolTipText(Messages.TmfTimeGraphViewer_NextItemActionToolTipText);
1084 }
1085
1086 private void contributeToActionBars() {
1087 IActionBars bars = getViewSite().getActionBars();
1088 fillLocalToolBar(bars.getToolBarManager());
1089
1090 // Create pin action
1091 contributePinActionToToolBar();
1092 fPinAction.addPropertyChangeListener(new IPropertyChangeListener(){
1093 @Override
1094 public void propertyChange(PropertyChangeEvent event) {
52974e38
PT
1095 if (IAction.CHECKED.equals(event.getProperty()) && !isPinned()) {
1096 if (fSavedRangeSyncSignal != null) {
1097 synchToRange(fSavedRangeSyncSignal);
1098 fSavedRangeSyncSignal = null;
1099 }
e8251298 1100
52974e38
PT
1101 if (fSavedTimeSyncSignal != null) {
1102 synchToTime(fSavedTimeSyncSignal);
1103 fSavedTimeSyncSignal = null;
e8251298
PT
1104 }
1105 }
1106 }
1107 });
1108 }
1109
1110 private void fillLocalToolBar(IToolBarManager manager) {
5da83da5 1111 manager.add(getImportMappingAction());
46cc1ade
PT
1112 manager.add(new Separator());
1113 manager.add(getSortByNameAction());
1114 manager.add(getSortByIdAction());
1115 manager.add(getSortByTimeAction());
1116 manager.add(new Separator());
e8251298
PT
1117 manager.add(fTimeGraphCombo.getTimeGraphViewer().getResetScaleAction());
1118 manager.add(getPreviousEventAction());
1119 manager.add(getNextEventAction());
1120 manager.add(fPreviousItemAction);
1121 manager.add(fNextItemAction);
1122 manager.add(fTimeGraphCombo.getTimeGraphViewer().getZoomInAction());
1123 manager.add(fTimeGraphCombo.getTimeGraphViewer().getZoomOutAction());
1124 manager.add(new Separator());
1125 }
1126
46cc1ade
PT
1127 private void createContextMenu() {
1128 final MenuManager contextMenu = new MenuManager();
1129 contextMenu.add(getSortByNameAction());
1130 contextMenu.add(getSortByIdAction());
1131 contextMenu.add(getSortByTimeAction());
1132
1133 Tree tree = fTimeGraphCombo.getTreeViewer().getTree();
1134 Menu menu = contextMenu.createContextMenu(tree);
1135 tree.setMenu(menu);
1136 }
1137
e8251298
PT
1138 /**
1139 * Get the the next event action.
1140 *
1141 * @return The action object
1142 */
1143 private Action getNextEventAction() {
1144 if (fNextEventAction == null) {
1145 fNextEventAction = new Action() {
1146 @Override
1147 public void run() {
1148 TimeGraphViewer viewer = fTimeGraphCombo.getTimeGraphViewer();
1149 ITimeGraphEntry entry = viewer.getSelection();
1150 if (entry instanceof CallStackEntry) {
1151 try {
1152 CallStackEntry callStackEntry = (CallStackEntry) entry;
da27e43a 1153 ITmfStateSystem ss = callStackEntry.getStateSystem();
0fcf3b09 1154 long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectionBegin()));
e8251298 1155 ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
da27e43a 1156 int quark = ss.getParentAttributeQuark(callStackEntry.getQuark());
e8251298
PT
1157 ITmfStateInterval stackInterval = ss.querySingleState(time, quark);
1158 long newTime = stackInterval.getEndTime() + 1;
1159 viewer.setSelectedTimeNotify(newTime, true);
1160 stackInterval = ss.querySingleState(Math.min(ss.getCurrentEndTime(), newTime), quark);
1161 int stackLevel = stackInterval.getStateValue().unboxInt();
a3188982 1162 ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
e8251298
PT
1163 fTimeGraphCombo.setSelection(selectedEntry);
1164 viewer.getTimeGraphControl().fireSelectionChanged();
1165 startZoomThread(viewer.getTime0(), viewer.getTime1());
50659279 1166
e8251298 1167 } catch (AttributeNotFoundException e) {
52974e38 1168 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298 1169 } catch (TimeRangeException e) {
52974e38 1170 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298 1171 } catch (StateSystemDisposedException e) {
52974e38 1172 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298 1173 } catch (StateValueTypeException e) {
52974e38 1174 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298
PT
1175 }
1176 }
1177 }
1178 };
1179
1180 fNextEventAction.setText(Messages.TmfTimeGraphViewer_NextEventActionNameText);
1181 fNextEventAction.setToolTipText(Messages.TmfTimeGraphViewer_NextEventActionToolTipText);
1182 fNextEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_EVENT));
1183 }
1184
1185 return fNextEventAction;
1186 }
1187
1188 /**
1189 * Get the previous event action.
1190 *
1191 * @return The Action object
1192 */
1193 private Action getPreviousEventAction() {
1194 if (fPrevEventAction == null) {
1195 fPrevEventAction = new Action() {
1196 @Override
1197 public void run() {
1198 TimeGraphViewer viewer = fTimeGraphCombo.getTimeGraphViewer();
1199 ITimeGraphEntry entry = viewer.getSelection();
1200 if (entry instanceof CallStackEntry) {
1201 try {
1202 CallStackEntry callStackEntry = (CallStackEntry) entry;
da27e43a 1203 ITmfStateSystem ss = callStackEntry.getStateSystem();
0fcf3b09 1204 long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectionBegin()));
e8251298 1205 ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
da27e43a 1206 int quark = ss.getParentAttributeQuark(callStackEntry.getQuark());
e8251298
PT
1207 ITmfStateInterval stackInterval = ss.querySingleState(time, quark);
1208 if (stackInterval.getStartTime() == time && time > ss.getStartTime()) {
1209 stackInterval = ss.querySingleState(time - 1, quark);
1210 }
1211 viewer.setSelectedTimeNotify(stackInterval.getStartTime(), true);
1212 int stackLevel = stackInterval.getStateValue().unboxInt();
a3188982 1213 ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
e8251298
PT
1214 fTimeGraphCombo.setSelection(selectedEntry);
1215 viewer.getTimeGraphControl().fireSelectionChanged();
1216 startZoomThread(viewer.getTime0(), viewer.getTime1());
50659279 1217
e8251298 1218 } catch (AttributeNotFoundException e) {
52974e38 1219 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298 1220 } catch (TimeRangeException e) {
52974e38 1221 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298 1222 } catch (StateSystemDisposedException e) {
52974e38 1223 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298 1224 } catch (StateValueTypeException e) {
52974e38 1225 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298
PT
1226 }
1227 }
1228 }
1229 };
1230
1231 fPrevEventAction.setText(Messages.TmfTimeGraphViewer_PreviousEventActionNameText);
1232 fPrevEventAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousEventActionToolTipText);
1233 fPrevEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_EVENT));
1234 }
1235
1236 return fPrevEventAction;
1237 }
1238
da27e43a 1239 private static @Nullable AbstractCallStackAnalysis getCallStackModule(ITmfTrace trace) {
50659279
AM
1240 /*
1241 * Since we cannot know the exact analysis ID (in separate plugins), we
1242 * will search using the analysis type.
1243 */
1244 Iterable<AbstractCallStackAnalysis> modules =
1245 trace.getAnalysisModulesOfClass(AbstractCallStackAnalysis.class);
1246 Iterator<AbstractCallStackAnalysis> it = modules.iterator();
1247 if (!it.hasNext()) {
1248 /* This trace does not provide a call-stack analysis */
1249 return null;
1250 }
1251
1252 /*
1253 * We only look at the first module we find.
1254 *
1255 * TODO Handle the advanced case where one trace provides more than one
1256 * call-stack analysis.
1257 */
1258 AbstractCallStackAnalysis module = it.next();
1259 /* This analysis is not automatic, we need to schedule it on-demand */
1260 module.schedule();
1261 module.waitForInitialization();
da27e43a 1262 return module;
50659279
AM
1263 }
1264
5da83da5
AM
1265 // ------------------------------------------------------------------------
1266 // Methods related to function name mapping
1267 // ------------------------------------------------------------------------
1268
1269 /**
1270 * Toolbar icon to import the function address-to-name mapping file.
1271 */
1272 private Action getImportMappingAction() {
1273 if (fImportMappingAction != null) {
1274 return fImportMappingAction;
1275 }
1276 fImportMappingAction = new Action() {
1277 @Override
1278 public void run() {
1279 FileDialog dialog = new FileDialog(getViewSite().getShell());
1280 dialog.setText(Messages.CallStackView_ImportMappingDialogTitle);
1281 String filePath = dialog.open();
1282 if (filePath == null) {
1283 /* No file was selected, don't change anything */
1284 return;
1285 }
1286 /*
1287 * Start the mapping import in a separate thread (we do not want
1288 * to UI thread to do this).
1289 */
1290 Job job = new ImportMappingJob(new File(filePath));
1291 job.schedule();
1292 }
1293 };
1294
1295 fImportMappingAction.setText(Messages.CallStackView_ImportMappingButtonText);
1296 fImportMappingAction.setToolTipText(Messages.CallStackView_ImportMappingButtonTooltip);
1297 fImportMappingAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(IMPORT_MAPPING_ICON_PATH));
1298
1299 return fImportMappingAction;
1300 }
1301
46cc1ade
PT
1302 private Action getSortByNameAction() {
1303 if (fSortByNameAction == null) {
1304 fSortByNameAction = new Action(Messages.CallStackView_SortByThreadName, IAction.AS_CHECK_BOX) {
1305 @Override
1306 public void run() {
1307 if (fSortOption == SortOption.BY_NAME) {
1308 saveSortOption(SortOption.BY_NAME_REV);
1309 } else {
1310 saveSortOption(SortOption.BY_NAME);
1311 }
1312 }
1313 };
1314 fSortByNameAction.setToolTipText(Messages.CallStackView_SortByThreadName);
1315 }
1316 return fSortByNameAction;
1317 }
1318
1319 private Action getSortByIdAction() {
1320 if (fSortByIdAction == null) {
1321 fSortByIdAction = new Action(Messages.CallStackView_SortByThreadId, IAction.AS_CHECK_BOX) {
1322 @Override
1323 public void run() {
1324 if (fSortOption == SortOption.BY_ID) {
1325 saveSortOption(SortOption.BY_ID_REV);
1326 } else {
1327 saveSortOption(SortOption.BY_ID);
1328 }
1329 }
1330 };
1331 fSortByIdAction.setToolTipText(Messages.CallStackView_SortByThreadId);
1332 }
1333 return fSortByIdAction;
1334 }
1335
1336 private Action getSortByTimeAction() {
1337 if (fSortByTimeAction == null) {
1338 fSortByTimeAction = new Action(Messages.CallStackView_SortByThreadTime, IAction.AS_CHECK_BOX) {
1339 @Override
1340 public void run() {
1341 if (fSortOption == SortOption.BY_TIME) {
1342 saveSortOption(SortOption.BY_TIME_REV);
1343 } else {
1344 saveSortOption(SortOption.BY_TIME);
1345 }
1346 }
1347 };
1348 fSortByTimeAction.setToolTipText(Messages.CallStackView_SortByThreadTime);
1349 }
1350 return fSortByTimeAction;
1351 }
1352
1353 private void loadSortOption() {
1354 IDialogSettings settings = Activator.getDefault().getDialogSettings();
1355 IDialogSettings section = settings.getSection(getClass().getName());
1356 if (section == null) {
1357 return;
1358 }
1359 String sortOption = section.get(SORT_OPTION_KEY);
1360
1361 // reset defaults
1362 getSortByNameAction().setChecked(false);
1363 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_ICON);
1364 getSortByIdAction().setChecked(false);
1365 getSortByIdAction().setImageDescriptor(SORT_BY_ID_ICON);
1366 getSortByTimeAction().setChecked(false);
1367 getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_ICON);
1368
1369 if (sortOption.equals(SortOption.BY_NAME.name())) {
1370 fSortOption = SortOption.BY_NAME;
1371 fThreadComparator = new ThreadNameComparator(false);
1372 getSortByNameAction().setChecked(true);
1373 } else if (sortOption.equals(SortOption.BY_NAME_REV.name())) {
1374 fSortOption = SortOption.BY_NAME_REV;
1375 fThreadComparator = new ThreadNameComparator(true);
1376 getSortByNameAction().setChecked(true);
1377 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_REV_ICON);
1378 } else if (sortOption.equals(SortOption.BY_ID.name())) {
1379 fSortOption = SortOption.BY_ID;
1380 fThreadComparator = new ThreadIdComparator(false);
1381 getSortByIdAction().setChecked(true);
1382 } else if (sortOption.equals(SortOption.BY_ID_REV.name())) {
1383 fSortOption = SortOption.BY_ID_REV;
1384 fThreadComparator = new ThreadIdComparator(true);
1385 getSortByIdAction().setChecked(true);
1386 getSortByIdAction().setImageDescriptor(SORT_BY_ID_REV_ICON);
1387 } else if (sortOption.equals(SortOption.BY_TIME.name())) {
1388 fSortOption = SortOption.BY_TIME;
1389 fThreadComparator = new ThreadTimeComparator(false);
1390 getSortByTimeAction().setChecked(true);
1391 } else if (sortOption.equals(SortOption.BY_TIME_REV.name())) {
1392 fSortOption = SortOption.BY_TIME_REV;
1393 fThreadComparator = new ThreadTimeComparator(true);
1394 getSortByTimeAction().setChecked(true);
1395 getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_REV_ICON);
1396 }
1397 }
1398
1399 private void saveSortOption(SortOption sortOption) {
1400 IDialogSettings settings = Activator.getDefault().getDialogSettings();
1401 IDialogSettings section = settings.getSection(getClass().getName());
1402 if (section == null) {
1403 section = settings.addNewSection(getClass().getName());
1404 }
1405 section.put(SORT_OPTION_KEY, sortOption.name());
1406 loadSortOption();
1407 if (fEntryList == null) {
1408 return;
1409 }
1410 for (TraceEntry traceEntry : fEntryList) {
1411 traceEntry.sortChildren(fThreadComparator);
1412 }
1413 refresh();
1414 }
1415
5da83da5
AM
1416 private class ImportMappingJob extends Job {
1417 private final File fMappingFile;
1418
1419 public ImportMappingJob(File mappingFile) {
1420 super(Messages.CallStackView_ImportMappingJobName);
1421 fMappingFile = mappingFile;
1422 }
1423
1424 @Override
1425 public IStatus run(IProgressMonitor monitor) {
1426 fNameMapping = FunctionNameMapper.mapFromNmTextFile(fMappingFile);
1427
1428 /* Refresh the time graph and the list of entries */
1429 buildThreadList(fTrace, new NullProgressMonitor());
1430 redraw();
1431
1432 return Status.OK_STATUS;
1433 }
1434 }
1435
1436 String getFunctionName(String address) {
1437 if (fNameMapping == null) {
1438 /* No mapping available, just print the addresses */
1439 return address;
1440 }
1441 String ret = fNameMapping.get(address);
1442 if (ret == null) {
1443 /* We didn't find this address in the mapping file, just use the address */
1444 return address;
1445 }
1446 return ret;
1447 }
1448
e8251298 1449}
This page took 0.162955 seconds and 5 git commands to generate.