tmf: Make Callstack View pass timestamps and PIDs to symbol provider
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / views / callstack / CallStackView.java
1 /*******************************************************************************
2 * Copyright (c) 2013, 2016 Ericsson and others.
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Patrick Tasse - Initial API and implementation
11 * Bernd Hufmann - Updated signal handling
12 * Marc-Andre Laperle - Map from binary file
13 *******************************************************************************/
14
15 package org.eclipse.tracecompass.tmf.ui.views.callstack;
16
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.Comparator;
20 import java.util.HashMap;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map;
24
25 import org.eclipse.core.runtime.IProgressMonitor;
26 import org.eclipse.jdt.annotation.NonNull;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.eclipse.jface.action.Action;
29 import org.eclipse.jface.action.GroupMarker;
30 import org.eclipse.jface.action.IAction;
31 import org.eclipse.jface.action.IMenuManager;
32 import org.eclipse.jface.action.IToolBarManager;
33 import org.eclipse.jface.action.Separator;
34 import org.eclipse.jface.dialogs.IDialogConstants;
35 import org.eclipse.jface.dialogs.IDialogSettings;
36 import org.eclipse.jface.resource.ImageDescriptor;
37 import org.eclipse.jface.util.IPropertyChangeListener;
38 import org.eclipse.jface.util.PropertyChangeEvent;
39 import org.eclipse.jface.viewers.DoubleClickEvent;
40 import org.eclipse.jface.viewers.IDoubleClickListener;
41 import org.eclipse.jface.viewers.ISelection;
42 import org.eclipse.jface.viewers.IStructuredSelection;
43 import org.eclipse.swt.SWT;
44 import org.eclipse.swt.events.MouseAdapter;
45 import org.eclipse.swt.events.MouseEvent;
46 import org.eclipse.swt.graphics.Image;
47 import org.eclipse.swt.widgets.Composite;
48 import org.eclipse.swt.widgets.Display;
49 import org.eclipse.tracecompass.internal.tmf.ui.Activator;
50 import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
51 import org.eclipse.tracecompass.internal.tmf.ui.Messages;
52 import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
53 import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
54 import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
55 import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
56 import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
57 import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
58 import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
59 import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
60 import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue.Type;
61 import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal;
62 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
63 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
64 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
65 import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
66 import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
67 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
68 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampDelta;
69 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
70 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
71 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
72 import org.eclipse.tracecompass.tmf.ui.editors.ITmfTraceEditor;
73 import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProvider;
74 import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProviderPreferencePage;
75 import org.eclipse.tracecompass.tmf.ui.symbols.SymbolProviderConfigDialog;
76 import org.eclipse.tracecompass.tmf.ui.symbols.SymbolProviderManager;
77 import org.eclipse.tracecompass.tmf.ui.views.timegraph.AbstractTimeGraphView;
78 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;
79 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphContentProvider;
80 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphTimeEvent;
81 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphViewer;
82 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
83 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
84 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.NullTimeEvent;
85 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeEvent;
86 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
87 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
88 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphSelection;
89 import org.eclipse.ui.IEditorPart;
90 import org.eclipse.ui.IWorkbenchActionConstants;
91
92 /**
93 * Main implementation for the Call Stack view
94 *
95 * @author Patrick Tasse
96 */
97 public class CallStackView extends AbstractTimeGraphView {
98
99 // ------------------------------------------------------------------------
100 // Constants
101 // ------------------------------------------------------------------------
102
103 /** View ID. */
104 public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.callstack"; //$NON-NLS-1$
105
106 private static final String[] COLUMN_NAMES = new String[] {
107 Messages.CallStackView_FunctionColumn,
108 Messages.CallStackView_DepthColumn,
109 Messages.CallStackView_EntryTimeColumn,
110 Messages.CallStackView_ExitTimeColumn,
111 Messages.CallStackView_DurationColumn
112 };
113
114 private static final String[] FILTER_COLUMN_NAMES = new String[] {
115 Messages.CallStackView_ThreadColumn
116 };
117
118 /** Timeout between updates in the build thread in ms */
119 private static final long BUILD_UPDATE_TIMEOUT = 500;
120
121 // Fraction of a function duration to be added as spacing
122 private static final double SPACING_RATIO = 0.01;
123
124 private static final Image THREAD_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/thread_obj.gif"); //$NON-NLS-1$
125 private static final Image STACKFRAME_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/stckframe_obj.gif"); //$NON-NLS-1$
126
127 private static final String IMPORT_BINARY_ICON_PATH = "icons/obj16/binaries_obj.gif"; //$NON-NLS-1$
128
129 private static final ImageDescriptor SORT_BY_NAME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha.gif"); //$NON-NLS-1$
130 private static final ImageDescriptor SORT_BY_NAME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha_rev.gif"); //$NON-NLS-1$
131 private static final ImageDescriptor SORT_BY_ID_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num.gif"); //$NON-NLS-1$
132 private static final ImageDescriptor SORT_BY_ID_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num_rev.gif"); //$NON-NLS-1$
133 private static final ImageDescriptor SORT_BY_TIME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_time.gif"); //$NON-NLS-1$
134 private static final ImageDescriptor SORT_BY_TIME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_time_rev.gif"); //$NON-NLS-1$
135 private static final String SORT_OPTION_KEY = "sort.option"; //$NON-NLS-1$
136
137 private enum SortOption {
138 BY_NAME, BY_NAME_REV, BY_ID, BY_ID_REV, BY_TIME, BY_TIME_REV
139 }
140
141 private @NonNull SortOption fSortOption = SortOption.BY_NAME;
142 private @NonNull Comparator<ITimeGraphEntry> fThreadComparator = new ThreadNameComparator(false);
143 private Action fSortByNameAction;
144 private Action fSortByIdAction;
145 private Action fSortByTimeAction;
146
147 // ------------------------------------------------------------------------
148 // Fields
149 // ------------------------------------------------------------------------
150
151 private final Map<ITmfTrace, ISymbolProvider> fSymbolProviders = new HashMap<>();
152
153 // The next event action
154 private Action fNextEventAction;
155
156 // The previous event action
157 private Action fPrevEventAction;
158
159 // The next item action
160 private Action fNextItemAction;
161
162 // The previous item action
163 private Action fPreviousItemAction;
164
165 // The action to import a binary file mapping */
166 private Action fConfigureSymbolsAction;
167
168 // The saved time sync. signal used when switching off the pinning of a view
169 private TmfSelectionRangeUpdatedSignal fSavedTimeSyncSignal;
170
171 // The saved window range signal used when switching off the pinning of
172 // a view
173 private TmfWindowRangeUpdatedSignal fSavedRangeSyncSignal;
174
175 // ------------------------------------------------------------------------
176 // Classes
177 // ------------------------------------------------------------------------
178
179 private static class TraceEntry extends TimeGraphEntry {
180 public TraceEntry(String name, long startTime, long endTime) {
181 super(name, startTime, endTime);
182 }
183
184 @Override
185 public boolean hasTimeEvents() {
186 return false;
187 }
188 }
189
190 private static class ProcessEntry extends TimeGraphEntry {
191
192 private final int fProcessId;
193
194 public ProcessEntry(String name, int processId, long startTime, long endTime) {
195 super(name, startTime, endTime);
196 fProcessId = processId;
197 }
198
199 public int getProcessId() {
200 return fProcessId;
201 }
202
203 @Override
204 public boolean hasTimeEvents() {
205 return false;
206 }
207 }
208
209 private static class ThreadEntry extends TimeGraphEntry {
210 // The call stack quark
211 private final int fCallStackQuark;
212 // The state system from which this entry comes
213 private final ITmfStateSystem fSS;
214 // The thread id
215 private final long fThreadId;
216
217 public ThreadEntry(ITmfStateSystem ss, String name, long threadId, int callStackQuark, long startTime, long endTime) {
218 super(name, startTime, endTime);
219 fCallStackQuark = callStackQuark;
220 fThreadId = threadId;
221 fSS = ss;
222 }
223
224 @Override
225 public boolean hasTimeEvents() {
226 return false;
227 }
228
229 public int getCallStackQuark() {
230 return fCallStackQuark;
231 }
232
233 public long getThreadId() {
234 return fThreadId;
235 }
236
237 @Nullable
238 public ITmfStateSystem getStateSystem() {
239 return fSS;
240 }
241 }
242
243 private class CallStackComparator implements Comparator<ITimeGraphEntry> {
244 @Override
245 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
246 if (o1 instanceof ThreadEntry && o2 instanceof ThreadEntry) {
247 return fThreadComparator.compare(o1, o2);
248 } else if (o1 instanceof ProcessEntry && o2 instanceof ProcessEntry) {
249 return Integer.compare(((ProcessEntry) o1).fProcessId, ((ProcessEntry) o2).fProcessId);
250 }
251 return 0;
252 }
253 }
254
255 private static class ThreadNameComparator implements Comparator<ITimeGraphEntry> {
256 private boolean reverse;
257
258 public ThreadNameComparator(boolean reverse) {
259 this.reverse = reverse;
260 }
261
262 @Override
263 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
264 return reverse ? o2.getName().compareTo(o1.getName()) :
265 o1.getName().compareTo(o2.getName());
266 }
267 }
268
269 private static class ThreadIdComparator implements Comparator<ITimeGraphEntry> {
270 private boolean reverse;
271
272 public ThreadIdComparator(boolean reverse) {
273 this.reverse = reverse;
274 }
275
276 @Override
277 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
278 ThreadEntry t1 = (ThreadEntry) o1;
279 ThreadEntry t2 = (ThreadEntry) o2;
280 return reverse ? Long.compare(t2.getThreadId(), t1.getThreadId()) :
281 Long.compare(t1.getThreadId(), t2.getThreadId());
282 }
283 }
284
285 private static class ThreadTimeComparator implements Comparator<ITimeGraphEntry> {
286 private boolean reverse;
287
288 public ThreadTimeComparator(boolean reverse) {
289 this.reverse = reverse;
290 }
291
292 @Override
293 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
294 return reverse ? Long.compare(o2.getStartTime(), o1.getStartTime()) :
295 Long.compare(o1.getStartTime(), o2.getStartTime());
296 }
297 }
298
299 private static class CallStackTreeLabelProvider extends TreeLabelProvider {
300
301 @Override
302 public Image getColumnImage(Object element, int columnIndex) {
303 if (columnIndex == 0) {
304 if (element instanceof ThreadEntry) {
305 return THREAD_IMAGE;
306 } else if (element instanceof CallStackEntry) {
307 CallStackEntry entry = (CallStackEntry) element;
308 if (entry.getFunctionName().length() > 0) {
309 return STACKFRAME_IMAGE;
310 }
311 }
312 }
313 return null;
314 }
315
316 @Override
317 public String getColumnText(Object element, int columnIndex) {
318 if (element instanceof CallStackEntry) {
319 CallStackEntry entry = (CallStackEntry) element;
320 if (columnIndex == 0) {
321 return entry.getFunctionName();
322 } else if (columnIndex == 1 && entry.getFunctionName().length() > 0) {
323 int depth = entry.getStackLevel();
324 return Integer.toString(depth);
325 } else if (columnIndex == 2 && entry.getFunctionName().length() > 0) {
326 ITmfTimestamp ts = TmfTimestamp.fromNanos(entry.getFunctionEntryTime());
327 return ts.toString();
328 } else if (columnIndex == 3 && entry.getFunctionName().length() > 0) {
329 ITmfTimestamp ts = TmfTimestamp.fromNanos(entry.getFunctionExitTime());
330 return ts.toString();
331 } else if (columnIndex == 4 && entry.getFunctionName().length() > 0) {
332 ITmfTimestamp ts = new TmfTimestampDelta(entry.getFunctionExitTime() - entry.getFunctionEntryTime(), ITmfTimestamp.NANOSECOND_SCALE);
333 return ts.toString();
334 }
335 } else if (element instanceof ITimeGraphEntry) {
336 if (columnIndex == 0) {
337 return ((ITimeGraphEntry) element).getName();
338 }
339 }
340 return ""; //$NON-NLS-1$
341 }
342
343 }
344
345 private class CallStackFilterContentProvider extends TimeGraphContentProvider {
346 @Override
347 public boolean hasChildren(Object element) {
348 if (element instanceof TraceEntry) {
349 return super.hasChildren(element);
350 }
351 return false;
352 }
353
354 @Override
355 public ITimeGraphEntry[] getChildren(Object parentElement) {
356 if (parentElement instanceof TraceEntry) {
357 return super.getChildren(parentElement);
358 }
359 return new ITimeGraphEntry[0];
360 }
361 }
362
363 // ------------------------------------------------------------------------
364 // Constructors
365 // ------------------------------------------------------------------------
366
367 /**
368 * Default constructor
369 */
370 public CallStackView() {
371 super(ID, new CallStackPresentationProvider());
372 ((CallStackPresentationProvider) getPresentationProvider()).setCallStackView(this);
373 setTreeColumns(COLUMN_NAMES);
374 setTreeLabelProvider(new CallStackTreeLabelProvider());
375 setEntryComparator(new CallStackComparator());
376 setFilterColumns(FILTER_COLUMN_NAMES);
377 setFilterContentProvider(new CallStackFilterContentProvider());
378 setFilterLabelProvider(new CallStackTreeLabelProvider());
379 }
380
381 // ------------------------------------------------------------------------
382 // ViewPart
383 // ------------------------------------------------------------------------
384
385 @Override
386 public void createPartControl(Composite parent) {
387 super.createPartControl(parent);
388
389 getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
390 @Override
391 public void timeSelected(TimeGraphTimeEvent event) {
392 synchingToTime(event.getBeginTime());
393 }
394 });
395
396 getTimeGraphCombo().getTreeViewer().addDoubleClickListener(new IDoubleClickListener() {
397 @Override
398 public void doubleClick(DoubleClickEvent event) {
399 Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
400 if (selection instanceof CallStackEntry) {
401 CallStackEntry entry = (CallStackEntry) selection;
402 if (entry.getFunctionName().length() > 0) {
403 long entryTime = entry.getFunctionEntryTime();
404 long exitTime = entry.getFunctionExitTime();
405 long spacingTime = (long) ((exitTime - entryTime) * SPACING_RATIO);
406 entryTime -= spacingTime;
407 exitTime += spacingTime;
408 TmfTimeRange range = new TmfTimeRange(TmfTimestamp.fromNanos(entryTime), TmfTimestamp.fromNanos(exitTime));
409 broadcast(new TmfWindowRangeUpdatedSignal(CallStackView.this, range));
410 getTimeGraphViewer().setStartFinishTime(entryTime, exitTime);
411 startZoomThread(entryTime, exitTime);
412 }
413 }
414 }
415 });
416
417 getTimeGraphViewer().getTimeGraphControl().addMouseListener(new MouseAdapter() {
418 @Override
419 public void mouseDoubleClick(MouseEvent e) {
420 TimeGraphControl timeGraphControl = getTimeGraphViewer().getTimeGraphControl();
421 ISelection selection = timeGraphControl.getSelection();
422 if (selection instanceof TimeGraphSelection) {
423 Object o = ((TimeGraphSelection) selection).getFirstElement();
424 if (o instanceof CallStackEvent) {
425 CallStackEvent event = (CallStackEvent) o;
426 long startTime = event.getTime();
427 long endTime = startTime + event.getDuration();
428 long spacingTime = (long) ((endTime - startTime) * SPACING_RATIO);
429 startTime -= spacingTime;
430 endTime += spacingTime;
431 TmfTimeRange range = new TmfTimeRange(TmfTimestamp.fromNanos(startTime), TmfTimestamp.fromNanos(endTime));
432 broadcast(new TmfWindowRangeUpdatedSignal(CallStackView.this, range));
433 getTimeGraphViewer().setStartFinishTime(startTime, endTime);
434 startZoomThread(startTime, endTime);
435 }
436 }
437 }
438 });
439
440 contributeToActionBars();
441 loadSortOption();
442
443 IEditorPart editor = getSite().getPage().getActiveEditor();
444 if (editor instanceof ITmfTraceEditor) {
445 ITmfTrace trace = ((ITmfTraceEditor) editor).getTrace();
446 if (trace != null) {
447 traceSelected(new TmfTraceSelectedSignal(this, trace));
448 }
449 }
450 }
451
452 /**
453 * Handler for the selection range signal.
454 *
455 * @param signal
456 * The incoming signal
457 * @since 1.0
458 */
459 @Override
460 @TmfSignalHandler
461 public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal) {
462
463 fSavedTimeSyncSignal = isPinned() ? new TmfSelectionRangeUpdatedSignal(signal.getSource(), signal.getBeginTime(), signal.getEndTime()) : null;
464
465 if (signal.getSource() == this || getTrace() == null || isPinned()) {
466 return;
467 }
468 final long beginTime = signal.getBeginTime().toNanos();
469 final long endTime = signal.getEndTime().toNanos();
470 Display.getDefault().asyncExec(new Runnable() {
471 @Override
472 public void run() {
473 if (getTimeGraphCombo().isDisposed()) {
474 return;
475 }
476 if (beginTime == endTime) {
477 getTimeGraphViewer().setSelectedTime(beginTime, true);
478 } else {
479 getTimeGraphViewer().setSelectionRange(beginTime, endTime, true);
480 }
481 synchingToTime(beginTime);
482 startZoomThread(getTimeGraphViewer().getTime0(), getTimeGraphViewer().getTime1());
483 List<TimeGraphEntry> traceEntries = getEntryList(getTrace());
484 if (traceEntries == null) {
485 return;
486 }
487 TimeGraphViewer viewer = getTimeGraphViewer();
488 for (TimeGraphEntry traceEntry : traceEntries) {
489 for (ITimeGraphEntry processEntry : traceEntry.getChildren()) {
490 for (ITimeGraphEntry aThreadEntry : processEntry.getChildren()) {
491 ThreadEntry threadEntry = (ThreadEntry) aThreadEntry;
492 ITmfStateSystem ss = threadEntry.getStateSystem();
493 if (ss == null || beginTime < ss.getStartTime() || beginTime > ss.getCurrentEndTime()) {
494 continue;
495 }
496 try {
497 int quark = threadEntry.getCallStackQuark();
498 ITmfStateInterval stackInterval = ss.querySingleState(beginTime, quark);
499 if (beginTime == stackInterval.getStartTime()) {
500 int stackLevel = stackInterval.getStateValue().unboxInt();
501 ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
502 getTimeGraphCombo().setSelection(selectedEntry);
503 viewer.getTimeGraphControl().fireSelectionChanged();
504 break;
505 }
506 } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
507 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
508 }
509 }
510 }
511 }
512 }
513 });
514
515 }
516
517 /**
518 * @since 2.0
519 */
520 @Override
521 @TmfSignalHandler
522 public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal) {
523
524 if (isPinned()) {
525 fSavedRangeSyncSignal = new TmfWindowRangeUpdatedSignal(signal.getSource(), signal.getCurrentRange());
526 fSavedTimeSyncSignal = null;
527 }
528
529 if ((signal.getSource() == this) || isPinned()) {
530 return;
531 }
532 super.windowRangeUpdated(signal);
533 }
534
535 // ------------------------------------------------------------------------
536 // Internal
537 // ------------------------------------------------------------------------
538
539 @Override
540 @TmfSignalHandler
541 public void traceClosed(TmfTraceClosedSignal signal) {
542 super.traceClosed(signal);
543 synchronized(fSymbolProviders){
544 for(ITmfTrace trace : getTracesToBuild(signal.getTrace())){
545 fSymbolProviders.remove(trace);
546 }
547 }
548 }
549
550 /**
551 * @since 2.0
552 */
553 @Override
554 protected void refresh() {
555 super.refresh();
556 updateConfigureSymbolsAction();
557 }
558
559 @Override
560 protected void buildEntryList(final ITmfTrace trace, final ITmfTrace parentTrace, final IProgressMonitor monitor) {
561 if (monitor.isCanceled()) {
562 return;
563 }
564 AbstractCallStackAnalysis module = getCallStackModule(trace);
565 if (module == null) {
566 addUnavailableEntry(trace, parentTrace);
567 return;
568 }
569 ITmfStateSystem ss = module.getStateSystem();
570 if (ss == null) {
571 addUnavailableEntry(trace, parentTrace);
572 return;
573 }
574
575 Map<ITmfTrace, TraceEntry> traceEntryMap = new HashMap<>();
576 Map<Integer, ProcessEntry> processEntryMap = new HashMap<>();
577 Map<Integer, ThreadEntry> threadEntryMap = new HashMap<>();
578
579 long start = ss.getStartTime();
580
581 boolean complete = false;
582 while (!complete) {
583 if (monitor.isCanceled()) {
584 return;
585 }
586 complete = ss.waitUntilBuilt(BUILD_UPDATE_TIMEOUT);
587 if (ss.isCancelled()) {
588 return;
589 }
590 long end = ss.getCurrentEndTime();
591 if (start == end && !complete) { // when complete execute one last time regardless of end time
592 continue;
593 }
594
595 ISymbolProvider provider = fSymbolProviders.get(trace);
596 if (provider == null) {
597 provider = SymbolProviderManager.getInstance().getSymbolProvider(trace);
598 provider.loadConfiguration(monitor);
599 fSymbolProviders.put(trace, provider);
600 }
601
602 getConfigureSymbolsAction().setEnabled(true);
603
604
605 TraceEntry traceEntry = traceEntryMap.get(trace);
606 if (traceEntry == null) {
607 traceEntry = new TraceEntry(trace.getName(), start, end + 1);
608 traceEntryMap.put(trace, traceEntry);
609 traceEntry.sortChildren(fThreadComparator);
610 addToEntryList(parentTrace, Collections.singletonList(traceEntry));
611 } else {
612 traceEntry.updateEndTime(end);
613 }
614
615 List<Integer> processQuarks = ss.getQuarks(module.getProcessesPattern());
616 for (Integer processQuark : processQuarks) {
617
618 /* Create the entry for the process */
619 ProcessEntry processEntry = processEntryMap.get(processQuark);
620 if (processEntry == null) {
621 String name = ss.getAttributeName(processQuark.intValue());
622 /* The attribute name should already be parseable to integer */
623 int processId = Integer.parseInt(name);
624 processEntry = new ProcessEntry(name, processId, start, end);
625 processEntryMap.put(processQuark, processEntry);
626 traceEntry.addChild(processEntry);
627 } else {
628 processEntry.updateEndTime(end);
629 }
630
631 /* Create the threads under the process */
632 try {
633 List<Integer> threadQuarks = ss.getSubAttributes(processQuark, false, module.getThreadsForProcessPattern());
634
635 /*
636 * Only query startStates if necessary (threadEntry == null)
637 */
638 List<ITmfStateInterval> startStates = null;
639 List<ITmfStateInterval> endStates = ss.queryFullState(ss.getCurrentEndTime());
640 for (int i = 0; i < threadQuarks.size(); i++) {
641 if (monitor.isCanceled()) {
642 return;
643 }
644 int threadQuark = threadQuarks.get(i);
645
646 String[] callStackPath = module.getCallStackPathForThread();
647 int callStackQuark = ss.getQuarkRelative(threadQuark, callStackPath);
648 String threadName = ss.getAttributeName(threadQuark);
649 long threadEnd = end + 1;
650 ITmfStateInterval endInterval = endStates.get(callStackQuark);
651 if (endInterval.getStateValue().isNull() && endInterval.getStartTime() != ss.getStartTime()) {
652 threadEnd = endInterval.getStartTime();
653 }
654 ThreadEntry threadEntry = threadEntryMap.get(threadQuark);
655 if (threadEntry == null) {
656 if (startStates == null) {
657 startStates = ss.queryFullState(ss.getStartTime());
658 }
659 long threadId = endInterval.getStateValue().unboxLong();
660 long threadStart = start;
661 ITmfStateInterval startInterval = startStates.get(callStackQuark);
662 if (startInterval.getStateValue().isNull()) {
663 threadStart = Math.min(startInterval.getEndTime() + 1, end + 1);
664 }
665 threadEntry = new ThreadEntry(ss, threadName, threadId, callStackQuark, threadStart, threadEnd);
666 threadEntryMap.put(threadQuark, threadEntry);
667 processEntry.addChild(threadEntry);
668 } else {
669 threadEntry.updateEndTime(threadEnd);
670 }
671 int level = 1;
672 for (int stackLevelQuark : ss.getSubAttributes(callStackQuark, false)) {
673 if (level > threadEntry.getChildren().size()) {
674 int processId = processEntry.getProcessId();
675 CallStackEntry callStackEntry = new CallStackEntry(threadName, stackLevelQuark, level, processId, trace, ss);
676 threadEntry.addChild(callStackEntry);
677 }
678 level++;
679 }
680 }
681 } catch (AttributeNotFoundException e) {
682 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
683 } catch (StateSystemDisposedException e) {
684 /* Ignored */
685 }
686 }
687
688 if (parentTrace == getTrace()) {
689 synchronized (this) {
690 setStartTime(getStartTime() == SWT.DEFAULT ? start : Math.min(getStartTime(), start));
691 setEndTime(getEndTime() == SWT.DEFAULT ? end + 1 : Math.max(getEndTime(), end + 1));
692 }
693 synchingToTime(getTimeGraphViewer().getSelectionBegin());
694 refresh();
695 }
696
697 for (ITimeGraphEntry processEntry : traceEntry.getChildren()) {
698 for (ITimeGraphEntry threadEntry : processEntry.getChildren()) {
699 for (ITimeGraphEntry callStackEntry : threadEntry.getChildren()) {
700 if (monitor.isCanceled()) {
701 return;
702 }
703 buildStatusEvents(parentTrace, (CallStackEntry) callStackEntry, monitor, ss.getStartTime(), end);
704 }
705 }
706 }
707 start = end;
708 }
709 }
710
711 private void addUnavailableEntry(ITmfTrace trace, ITmfTrace parentTrace) {
712 String name = Messages.CallStackView_StackInfoNotAvailable + ' ' + '(' + trace.getName() + ')';
713 TraceEntry unavailableEntry = new TraceEntry(name, 0, 0);
714 addToEntryList(parentTrace, Collections.singletonList(unavailableEntry));
715 if (parentTrace == getTrace()) {
716 refresh();
717 }
718 }
719
720 private void buildStatusEvents(ITmfTrace trace, CallStackEntry entry, @NonNull IProgressMonitor monitor, long start, long end) {
721 ITmfStateSystem ss = entry.getStateSystem();
722 long resolution = Math.max(1, (end - ss.getStartTime()) / getDisplayWidth());
723 List<ITimeEvent> eventList = getEventList(entry, start, end + 1, resolution, monitor);
724 if (eventList != null) {
725 entry.setEventList(eventList);
726 }
727 if (trace == getTrace()) {
728 redraw();
729 }
730 }
731
732 /**
733 * @since 2.0
734 */
735 @Override
736 protected final List<ITimeEvent> getEventList(TimeGraphEntry tgentry, long startTime, long endTime, long resolution, IProgressMonitor monitor) {
737 if (!(tgentry instanceof CallStackEntry)) {
738 return null;
739 }
740 CallStackEntry entry = (CallStackEntry) tgentry;
741 ITmfStateSystem ss = entry.getStateSystem();
742 long start = Math.max(startTime, ss.getStartTime());
743 long end = Math.min(endTime, ss.getCurrentEndTime() + 1);
744 if (end <= start) {
745 return null;
746 }
747 boolean isZoomThread = Thread.currentThread() instanceof ZoomThread;
748 List<ITimeEvent> eventList = null;
749 try {
750 List<ITmfStateInterval> stackIntervals = StateSystemUtils.queryHistoryRange(ss, entry.getQuark(), start, end - 1, resolution, monitor);
751 eventList = new ArrayList<>(stackIntervals.size());
752 long lastEndTime = -1;
753 boolean lastIsNull = true;
754 for (ITmfStateInterval statusInterval : stackIntervals) {
755 if (monitor.isCanceled()) {
756 return null;
757 }
758 long time = statusInterval.getStartTime();
759 long duration = statusInterval.getEndTime() - time + 1;
760 if (!statusInterval.getStateValue().isNull()) {
761 final int modulo = CallStackPresentationProvider.NUM_COLORS / 2;
762 int value = statusInterval.getStateValue().toString().hashCode() % modulo + modulo;
763 eventList.add(new CallStackEvent(entry, time, duration, value));
764 lastIsNull = false;
765 } else {
766 if (lastEndTime == -1 && isZoomThread) {
767 // add null event if it intersects the start time
768 eventList.add(new NullTimeEvent(entry, time, duration));
769 } else {
770 if (lastEndTime != time && lastIsNull) {
771 // add unknown event if between two null states
772 eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime));
773 }
774 if (time + duration >= endTime && isZoomThread) {
775 // add null event if it intersects the end time
776 eventList.add(new NullTimeEvent(entry, time, duration));
777 }
778 }
779 lastIsNull = true;
780 }
781 lastEndTime = time + duration;
782 }
783 } catch (AttributeNotFoundException e) {
784 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
785 } catch (TimeRangeException e) {
786 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
787 } catch (StateSystemDisposedException e) {
788 /* Ignored */
789 }
790 return eventList;
791 }
792
793 /**
794 * @since 2.0
795 */
796 @Override
797 protected void synchingToTime(long time) {
798 List<TimeGraphEntry> entryList = getEntryList(getTrace());
799 if (entryList == null) {
800 return;
801 }
802 for (TimeGraphEntry traceEntry : entryList) {
803 for (ITimeGraphEntry processEntry : traceEntry.getChildren()) {
804 /* The entries should all be parseable to an integer. */
805 int pid = Integer.parseInt(processEntry.getName());
806
807 for (ITimeGraphEntry threadEntry : processEntry.getChildren()) {
808 ITmfStateSystem ss = ((ThreadEntry) threadEntry).getStateSystem();
809 if (ss == null) {
810 continue;
811 }
812 if (ss.isCancelled()) {
813 continue;
814 }
815 if (time < ss.getStartTime() || time > ss.getCurrentEndTime()) {
816 continue;
817 }
818 for (ITimeGraphEntry child : threadEntry.getChildren()) {
819 CallStackEntry callStackEntry = (CallStackEntry) child;
820 ITmfTrace trace = callStackEntry.getTrace();
821 try {
822 ITmfStateInterval stackLevelInterval = ss.querySingleState(time, callStackEntry.getQuark());
823 ITmfStateValue nameValue = stackLevelInterval.getStateValue();
824
825 String name = getFunctionName(trace, pid, time, nameValue);
826 callStackEntry.setFunctionName(name);
827 if (name.length() > 0) {
828 callStackEntry.setFunctionEntryTime(stackLevelInterval.getStartTime());
829 callStackEntry.setFunctionExitTime(stackLevelInterval.getEndTime() + 1);
830 }
831 } catch (AttributeNotFoundException e) {
832 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
833 } catch (StateSystemDisposedException e) {
834 /* Ignored */
835 }
836 }
837 }
838 }
839 }
840 if (Display.getCurrent() != null) {
841 getTimeGraphCombo().refresh();
842 }
843 }
844
845 String getFunctionName(ITmfTrace trace, int processId, long timestamp, ITmfStateValue nameValue) {
846 long address = Long.MAX_VALUE;
847 String name = ""; //$NON-NLS-1$
848 try {
849 if (nameValue.getType() == Type.STRING) {
850 name = nameValue.unboxStr();
851 try {
852 address = Long.parseLong(name, 16);
853 } catch (NumberFormatException e) {
854 // ignore
855 }
856 } else if (nameValue.getType() == Type.INTEGER) {
857 name = "0x" + Integer.toHexString(nameValue.unboxInt()); //$NON-NLS-1$
858 address = nameValue.unboxInt();
859 } else if (nameValue.getType() == Type.LONG) {
860 name = "0x" + Long.toHexString(nameValue.unboxLong()); //$NON-NLS-1$
861 address = nameValue.unboxLong();
862 }
863 } catch (StateValueTypeException e) {
864 }
865 if (address != Long.MAX_VALUE) {
866 ISymbolProvider provider = fSymbolProviders.get(trace);
867 if (provider != null) {
868 String symbol = provider.getSymbolText(processId, timestamp, address);
869 if (symbol != null) {
870 name = symbol;
871 }
872 }
873 }
874 return name;
875 }
876
877 private void makeActions() {
878 fPreviousItemAction = getTimeGraphViewer().getPreviousItemAction();
879 fPreviousItemAction.setText(Messages.TmfTimeGraphViewer_PreviousItemActionNameText);
880 fPreviousItemAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousItemActionToolTipText);
881 fNextItemAction = getTimeGraphViewer().getNextItemAction();
882 fNextItemAction.setText(Messages.TmfTimeGraphViewer_NextItemActionNameText);
883 fNextItemAction.setToolTipText(Messages.TmfTimeGraphViewer_NextItemActionToolTipText);
884 }
885
886 private void contributeToActionBars() {
887 // Create pin action
888 contributePinActionToToolBar();
889 fPinAction.addPropertyChangeListener(new IPropertyChangeListener() {
890 @Override
891 public void propertyChange(PropertyChangeEvent event) {
892 if (IAction.CHECKED.equals(event.getProperty()) && !isPinned()) {
893 if (fSavedRangeSyncSignal != null) {
894 windowRangeUpdated(fSavedRangeSyncSignal);
895 fSavedRangeSyncSignal = null;
896 }
897
898 if (fSavedTimeSyncSignal != null) {
899 selectionRangeUpdated(fSavedTimeSyncSignal);
900 fSavedTimeSyncSignal = null;
901 }
902 }
903 }
904 });
905 }
906
907 /**
908 * @since 2.0
909 */
910 @Override
911 protected void fillLocalToolBar(IToolBarManager manager) {
912 makeActions();
913 manager.add(getConfigureSymbolsAction());
914 manager.add(new Separator());
915 manager.add(getSortByNameAction());
916 manager.add(getSortByIdAction());
917 manager.add(getSortByTimeAction());
918 manager.add(new Separator());
919 manager.add(getTimeGraphCombo().getShowFilterDialogAction());
920 manager.add(new Separator());
921 manager.add(getTimeGraphViewer().getResetScaleAction());
922 manager.add(getPreviousEventAction());
923 manager.add(getNextEventAction());
924 manager.add(new Separator());
925 manager.add(getTimeGraphViewer().getToggleBookmarkAction());
926 manager.add(getTimeGraphViewer().getPreviousMarkerAction());
927 manager.add(getTimeGraphViewer().getNextMarkerAction());
928 manager.add(new Separator());
929 manager.add(fPreviousItemAction);
930 manager.add(fNextItemAction);
931 manager.add(getTimeGraphViewer().getZoomInAction());
932 manager.add(getTimeGraphViewer().getZoomOutAction());
933 }
934
935 /**
936 * @since 2.0
937 */
938 @Override
939 protected void fillTimeGraphEntryContextMenu(IMenuManager contextMenu) {
940 contextMenu.add(new GroupMarker(IWorkbenchActionConstants.GROUP_REORGANIZE));
941 contextMenu.add(getSortByNameAction());
942 contextMenu.add(getSortByIdAction());
943 contextMenu.add(getSortByTimeAction());
944 }
945
946 /**
947 * Get the the next event action.
948 *
949 * @return The action object
950 */
951 private Action getNextEventAction() {
952 if (fNextEventAction == null) {
953 fNextEventAction = new Action() {
954 @Override
955 public void run() {
956 TimeGraphViewer viewer = getTimeGraphViewer();
957 ITimeGraphEntry entry = viewer.getSelection();
958 if (entry instanceof CallStackEntry) {
959 try {
960 CallStackEntry callStackEntry = (CallStackEntry) entry;
961 ITmfStateSystem ss = callStackEntry.getStateSystem();
962 long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectionBegin()));
963 ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
964 int quark = ss.getParentAttributeQuark(callStackEntry.getQuark());
965 ITmfStateInterval stackInterval = ss.querySingleState(time, quark);
966 long newTime = stackInterval.getEndTime() + 1;
967 viewer.setSelectedTimeNotify(newTime, true);
968 stackInterval = ss.querySingleState(Math.min(ss.getCurrentEndTime(), newTime), quark);
969 int stackLevel = stackInterval.getStateValue().unboxInt();
970 ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
971 getTimeGraphCombo().setSelection(selectedEntry);
972 viewer.getTimeGraphControl().fireSelectionChanged();
973 startZoomThread(viewer.getTime0(), viewer.getTime1());
974
975 } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
976 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
977 }
978 }
979 }
980 };
981
982 fNextEventAction.setText(Messages.TmfTimeGraphViewer_NextEventActionNameText);
983 fNextEventAction.setToolTipText(Messages.TmfTimeGraphViewer_NextEventActionToolTipText);
984 fNextEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_EVENT));
985 }
986
987 return fNextEventAction;
988 }
989
990 /**
991 * Get the previous event action.
992 *
993 * @return The Action object
994 */
995 private Action getPreviousEventAction() {
996 if (fPrevEventAction == null) {
997 fPrevEventAction = new Action() {
998 @Override
999 public void run() {
1000 TimeGraphViewer viewer = getTimeGraphCombo().getTimeGraphViewer();
1001 ITimeGraphEntry entry = viewer.getSelection();
1002 if (entry instanceof CallStackEntry) {
1003 try {
1004 CallStackEntry callStackEntry = (CallStackEntry) entry;
1005 ITmfStateSystem ss = callStackEntry.getStateSystem();
1006 long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectionBegin()));
1007 ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
1008 int quark = ss.getParentAttributeQuark(callStackEntry.getQuark());
1009 ITmfStateInterval stackInterval = ss.querySingleState(time, quark);
1010 if (stackInterval.getStartTime() == time && time > ss.getStartTime()) {
1011 stackInterval = ss.querySingleState(time - 1, quark);
1012 }
1013 viewer.setSelectedTimeNotify(stackInterval.getStartTime(), true);
1014 int stackLevel = stackInterval.getStateValue().unboxInt();
1015 ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
1016 getTimeGraphCombo().setSelection(selectedEntry);
1017 viewer.getTimeGraphControl().fireSelectionChanged();
1018 startZoomThread(viewer.getTime0(), viewer.getTime1());
1019
1020 } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
1021 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
1022 }
1023 }
1024 }
1025 };
1026
1027 fPrevEventAction.setText(Messages.TmfTimeGraphViewer_PreviousEventActionNameText);
1028 fPrevEventAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousEventActionToolTipText);
1029 fPrevEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_EVENT));
1030 }
1031
1032 return fPrevEventAction;
1033 }
1034
1035 private static @Nullable AbstractCallStackAnalysis getCallStackModule(@NonNull ITmfTrace trace) {
1036 /*
1037 * Since we cannot know the exact analysis ID (in separate plugins), we
1038 * will search using the analysis type.
1039 */
1040 Iterable<AbstractCallStackAnalysis> modules =
1041 TmfTraceUtils.getAnalysisModulesOfClass(trace, AbstractCallStackAnalysis.class);
1042 Iterator<AbstractCallStackAnalysis> it = modules.iterator();
1043 if (!it.hasNext()) {
1044 /* This trace does not provide a call-stack analysis */
1045 return null;
1046 }
1047
1048 /*
1049 * We only look at the first module we find.
1050 *
1051 * TODO Handle the advanced case where one trace provides more than one
1052 * call-stack analysis.
1053 */
1054 AbstractCallStackAnalysis module = it.next();
1055 /* This analysis is not automatic, we need to schedule it on-demand */
1056 module.schedule();
1057 if (!module.waitForInitialization()) {
1058 /* The initialization did not succeed */
1059 return null;
1060 }
1061 return module;
1062 }
1063
1064 // ------------------------------------------------------------------------
1065 // Methods related to function name mapping
1066 // ------------------------------------------------------------------------
1067
1068 private Action getSortByNameAction() {
1069 if (fSortByNameAction == null) {
1070 fSortByNameAction = new Action(Messages.CallStackView_SortByThreadName, IAction.AS_CHECK_BOX) {
1071 @Override
1072 public void run() {
1073 if (fSortOption == SortOption.BY_NAME) {
1074 saveSortOption(SortOption.BY_NAME_REV);
1075 } else {
1076 saveSortOption(SortOption.BY_NAME);
1077 }
1078 }
1079 };
1080 fSortByNameAction.setToolTipText(Messages.CallStackView_SortByThreadName);
1081 fSortByNameAction.setImageDescriptor(SORT_BY_NAME_ICON);
1082 }
1083 return fSortByNameAction;
1084 }
1085
1086 private Action getSortByIdAction() {
1087 if (fSortByIdAction == null) {
1088 fSortByIdAction = new Action(Messages.CallStackView_SortByThreadId, IAction.AS_CHECK_BOX) {
1089 @Override
1090 public void run() {
1091 if (fSortOption == SortOption.BY_ID) {
1092 saveSortOption(SortOption.BY_ID_REV);
1093 } else {
1094 saveSortOption(SortOption.BY_ID);
1095 }
1096 }
1097 };
1098 fSortByIdAction.setToolTipText(Messages.CallStackView_SortByThreadId);
1099 fSortByIdAction.setImageDescriptor(SORT_BY_ID_ICON);
1100 }
1101 return fSortByIdAction;
1102 }
1103
1104 private Action getSortByTimeAction() {
1105 if (fSortByTimeAction == null) {
1106 fSortByTimeAction = new Action(Messages.CallStackView_SortByThreadTime, IAction.AS_CHECK_BOX) {
1107 @Override
1108 public void run() {
1109 if (fSortOption == SortOption.BY_TIME) {
1110 saveSortOption(SortOption.BY_TIME_REV);
1111 } else {
1112 saveSortOption(SortOption.BY_TIME);
1113 }
1114 }
1115 };
1116 fSortByTimeAction.setToolTipText(Messages.CallStackView_SortByThreadTime);
1117 fSortByTimeAction.setImageDescriptor(SORT_BY_TIME_ICON);
1118 }
1119 return fSortByTimeAction;
1120 }
1121
1122 private void loadSortOption() {
1123 IDialogSettings settings = Activator.getDefault().getDialogSettings();
1124 IDialogSettings section = settings.getSection(getClass().getName());
1125 if (section == null) {
1126 return;
1127 }
1128 String sortOption = section.get(SORT_OPTION_KEY);
1129 if (sortOption == null) {
1130 return;
1131 }
1132
1133 // reset defaults
1134 getSortByNameAction().setChecked(false);
1135 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_ICON);
1136 getSortByIdAction().setChecked(false);
1137 getSortByIdAction().setImageDescriptor(SORT_BY_ID_ICON);
1138 getSortByTimeAction().setChecked(false);
1139 getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_ICON);
1140
1141 if (sortOption.equals(SortOption.BY_NAME.name())) {
1142 fSortOption = SortOption.BY_NAME;
1143 fThreadComparator = new ThreadNameComparator(false);
1144 getSortByNameAction().setChecked(true);
1145 } else if (sortOption.equals(SortOption.BY_NAME_REV.name())) {
1146 fSortOption = SortOption.BY_NAME_REV;
1147 fThreadComparator = new ThreadNameComparator(true);
1148 getSortByNameAction().setChecked(true);
1149 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_REV_ICON);
1150 } else if (sortOption.equals(SortOption.BY_ID.name())) {
1151 fSortOption = SortOption.BY_ID;
1152 fThreadComparator = new ThreadIdComparator(false);
1153 getSortByIdAction().setChecked(true);
1154 } else if (sortOption.equals(SortOption.BY_ID_REV.name())) {
1155 fSortOption = SortOption.BY_ID_REV;
1156 fThreadComparator = new ThreadIdComparator(true);
1157 getSortByIdAction().setChecked(true);
1158 getSortByIdAction().setImageDescriptor(SORT_BY_ID_REV_ICON);
1159 } else if (sortOption.equals(SortOption.BY_TIME.name())) {
1160 fSortOption = SortOption.BY_TIME;
1161 fThreadComparator = new ThreadTimeComparator(false);
1162 getSortByTimeAction().setChecked(true);
1163 } else if (sortOption.equals(SortOption.BY_TIME_REV.name())) {
1164 fSortOption = SortOption.BY_TIME_REV;
1165 fThreadComparator = new ThreadTimeComparator(true);
1166 getSortByTimeAction().setChecked(true);
1167 getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_REV_ICON);
1168 }
1169 }
1170
1171 private void saveSortOption(SortOption sortOption) {
1172 IDialogSettings settings = Activator.getDefault().getDialogSettings();
1173 IDialogSettings section = settings.getSection(getClass().getName());
1174 if (section == null) {
1175 section = settings.addNewSection(getClass().getName());
1176 }
1177 section.put(SORT_OPTION_KEY, sortOption.name());
1178 loadSortOption();
1179 List<TimeGraphEntry> entryList = getEntryList(getTrace());
1180 if (entryList == null) {
1181 return;
1182 }
1183 for (TimeGraphEntry traceEntry : entryList) {
1184 traceEntry.sortChildren(fThreadComparator);
1185 }
1186 refresh();
1187 }
1188
1189 private Action getConfigureSymbolsAction() {
1190 if (fConfigureSymbolsAction != null) {
1191 return fConfigureSymbolsAction;
1192 }
1193
1194 fConfigureSymbolsAction = new Action(Messages.CallStackView_ConfigureSymbolProvidersText) {
1195 @Override
1196 public void run() {
1197 SymbolProviderConfigDialog dialog = new SymbolProviderConfigDialog(getSite().getShell(), getProviderPages());
1198 if (dialog.open() == IDialogConstants.OK_ID) {
1199 refresh();
1200 }
1201 }
1202 };
1203
1204 fConfigureSymbolsAction.setToolTipText(Messages.CallStackView_ConfigureSymbolProvidersTooltip);
1205 fConfigureSymbolsAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(IMPORT_BINARY_ICON_PATH));
1206 fConfigureSymbolsAction.setEnabled(false);
1207
1208 return fConfigureSymbolsAction;
1209 }
1210
1211 /**
1212 * @return an array of {@link ISymbolProviderPreferencePage} that will
1213 * configure the current traces
1214 */
1215 private ISymbolProviderPreferencePage[] getProviderPages() {
1216 List<ISymbolProviderPreferencePage> pages = new ArrayList<>();
1217 ITmfTrace trace = getTrace();
1218 if (trace != null) {
1219 for (ITmfTrace subTrace : getTracesToBuild(trace)) {
1220 ISymbolProvider provider = fSymbolProviders.get(subTrace);
1221 if (provider != null) {
1222 ISymbolProviderPreferencePage page = provider.createPreferencePage();
1223 if (page != null) {
1224 pages.add(page);
1225 }
1226 }
1227 }
1228 }
1229 return pages.toArray(new ISymbolProviderPreferencePage[pages.size()]);
1230 }
1231
1232 /**
1233 * Update the enable status of the configure symbols action
1234 */
1235 private void updateConfigureSymbolsAction() {
1236 ISymbolProviderPreferencePage[] providerPages = getProviderPages();
1237 getConfigureSymbolsAction().setEnabled(providerPages.length > 0);
1238 }
1239
1240 }
This page took 0.189103 seconds and 5 git commands to generate.