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