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