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