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