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