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