1 /*******************************************************************************
2 * Copyright (c) 2016 Ericsson
4 * All rights reserved. This program and the accompanying materials are made
5 * 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
11 *******************************************************************************/
12 package org
.eclipse
.tracecompass
.internal
.analysis
.timing
.ui
.flamegraph
;
14 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
15 import org
.eclipse
.core
.runtime
.IStatus
;
16 import org
.eclipse
.core
.runtime
.Status
;
17 import org
.eclipse
.core
.runtime
.jobs
.Job
;
18 import org
.eclipse
.jdt
.annotation
.NonNull
;
19 import org
.eclipse
.jface
.action
.Action
;
20 import org
.eclipse
.jface
.action
.GroupMarker
;
21 import org
.eclipse
.jface
.action
.IAction
;
22 import org
.eclipse
.jface
.action
.IMenuListener
;
23 import org
.eclipse
.jface
.action
.IMenuManager
;
24 import org
.eclipse
.jface
.action
.IToolBarManager
;
25 import org
.eclipse
.jface
.action
.MenuManager
;
26 import org
.eclipse
.jface
.action
.Separator
;
27 import org
.eclipse
.jface
.dialogs
.IDialogSettings
;
28 import org
.eclipse
.jface
.resource
.ImageDescriptor
;
29 import org
.eclipse
.jface
.viewers
.ISelection
;
30 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
31 import org
.eclipse
.swt
.SWT
;
32 import org
.eclipse
.swt
.events
.MenuDetectEvent
;
33 import org
.eclipse
.swt
.events
.MenuDetectListener
;
34 import org
.eclipse
.swt
.widgets
.Composite
;
35 import org
.eclipse
.swt
.widgets
.Display
;
36 import org
.eclipse
.swt
.widgets
.Menu
;
37 import org
.eclipse
.tracecompass
.internal
.analysis
.timing
.core
.callgraph
.CallGraphAnalysis
;
38 import org
.eclipse
.tracecompass
.internal
.analysis
.timing
.ui
.Activator
;
39 import org
.eclipse
.tracecompass
.internal
.analysis
.timing
.ui
.callgraph
.CallGraphAnalysisUI
;
40 import org
.eclipse
.tracecompass
.segmentstore
.core
.ISegment
;
41 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSelectionRangeUpdatedSignal
;
42 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
43 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceClosedSignal
;
44 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
45 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
46 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestamp
;
47 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
48 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceUtils
;
49 import org
.eclipse
.tracecompass
.tmf
.ui
.editors
.ITmfTraceEditor
;
50 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.TmfView
;
51 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphPresentationProvider
;
52 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphViewer
;
53 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphControl
;
54 import org
.eclipse
.ui
.IActionBars
;
55 import org
.eclipse
.ui
.IEditorPart
;
56 import org
.eclipse
.ui
.IWorkbenchActionConstants
;
59 * View to display the flame graph .This uses the flameGraphNode tree generated
60 * by CallGraphAnalysisUI.
62 * @author Sonia Farrah
64 public class FlameGraphView
extends TmfView
{
69 public static final String ID
= FlameGraphView
.class.getPackage().getName() + ".flamegraphView"; //$NON-NLS-1$
71 private static final String SORT_OPTION_KEY
= "sort.option"; //$NON-NLS-1$
72 private static final ImageDescriptor SORT_BY_NAME_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha.gif"); //$NON-NLS-1$
73 private static final ImageDescriptor SORT_BY_NAME_REV_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha_rev.gif"); //$NON-NLS-1$
74 private static final ImageDescriptor SORT_BY_ID_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_num.gif"); //$NON-NLS-1$
75 private static final ImageDescriptor SORT_BY_ID_REV_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_num_rev.gif"); //$NON-NLS-1$
78 private TimeGraphViewer fTimeGraphViewer
;
80 private FlameGraphContentProvider fTimeGraphContentProvider
;
82 private TimeGraphPresentationProvider fPresentationProvider
;
84 private ITmfTrace fTrace
;
86 private final @NonNull MenuManager fEventMenuManager
= new MenuManager();
87 private Action fSortByNameAction
;
88 private Action fSortByIdAction
;
93 public FlameGraphView() {
98 public void createPartControl(Composite parent
) {
99 super.createPartControl(parent
);
100 fTimeGraphViewer
= new TimeGraphViewer(parent
, SWT
.NONE
);
101 fTimeGraphContentProvider
= new FlameGraphContentProvider();
102 fPresentationProvider
= new FlameGraphPresentationProvider();
103 fTimeGraphViewer
.setTimeGraphContentProvider(fTimeGraphContentProvider
);
104 fTimeGraphViewer
.setTimeGraphProvider(fPresentationProvider
);
105 IEditorPart editor
= getSite().getPage().getActiveEditor();
106 if (editor
instanceof ITmfTraceEditor
) {
107 ITmfTrace trace
= ((ITmfTraceEditor
) editor
).getTrace();
109 traceSelected(new TmfTraceSelectedSignal(this, trace
));
112 contributeToActionBars();
115 getSite().setSelectionProvider(fTimeGraphViewer
.getSelectionProvider());
116 createTimeEventContextMenu();
121 * Handler for the trace opened signal
124 * The incoming signal
127 public void TraceOpened(TmfTraceOpenedSignal signal
) {
128 fTrace
= signal
.getTrace();
129 if (fTrace
!= null) {
130 CallGraphAnalysis flamegraphModule
= TmfTraceUtils
.getAnalysisModuleOfClass(fTrace
, CallGraphAnalysis
.class, CallGraphAnalysisUI
.ID
);
131 buildFlameGraph(flamegraphModule
);
136 * Handler for the trace selected signal
139 * The incoming signal
142 public void traceSelected(final TmfTraceSelectedSignal signal
) {
143 fTrace
= signal
.getTrace();
144 if (fTrace
!= null) {
145 CallGraphAnalysis flamegraphModule
= TmfTraceUtils
.getAnalysisModuleOfClass(fTrace
, CallGraphAnalysis
.class, CallGraphAnalysisUI
.ID
);
146 buildFlameGraph(flamegraphModule
);
151 * Get the necessary data for the flame graph and display it
153 * @param flamegraphModule
154 * the callGraphAnalysis
156 private void buildFlameGraph(CallGraphAnalysis callGraphAnalysis
) {
157 fTimeGraphViewer
.setInput(null);
158 callGraphAnalysis
.schedule();
159 Job j
= new Job(Messages
.CallGraphAnalysis_Execution
) {
162 protected IStatus
run(IProgressMonitor monitor
) {
163 if (monitor
.isCanceled()) {
164 return Status
.CANCEL_STATUS
;
166 callGraphAnalysis
.waitForCompletion(monitor
);
167 Display
.getDefault().asyncExec(() -> {
168 fTimeGraphViewer
.setInput(callGraphAnalysis
.getThreadNodes());
170 return Status
.OK_STATUS
;
177 * Trace is closed: clear the data structures and the view
180 * the signal received
183 public void traceClosed(final TmfTraceClosedSignal signal
) {
184 if (signal
.getTrace() == fTrace
) {
185 fTimeGraphViewer
.setInput(null);
190 public void setFocus() {
191 fTimeGraphViewer
.setFocus();
194 // ------------------------------------------------------------------------
196 // ------------------------------------------------------------------------
198 private void createTimeEventContextMenu() {
199 fEventMenuManager
.setRemoveAllWhenShown(true);
200 TimeGraphControl timeGraphControl
= fTimeGraphViewer
.getTimeGraphControl();
201 final Menu timeEventMenu
= fEventMenuManager
.createContextMenu(timeGraphControl
);
203 timeGraphControl
.addTimeGraphEntryMenuListener(new MenuDetectListener() {
205 public void menuDetected(MenuDetectEvent event
) {
207 * The TimeGraphControl will call the TimeGraphEntryMenuListener
208 * before the TimeEventMenuListener. We need to clear the menu
209 * for the case the selection was done on the namespace where
210 * the time event listener below won't be called afterwards.
212 timeGraphControl
.setMenu(null);
216 timeGraphControl
.addTimeEventMenuListener(new MenuDetectListener() {
218 public void menuDetected(MenuDetectEvent event
) {
219 Menu menu
= timeEventMenu
;
220 if (event
.data
instanceof FlamegraphEvent
) {
221 timeGraphControl
.setMenu(menu
);
224 timeGraphControl
.setMenu(null);
229 fEventMenuManager
.addMenuListener(new IMenuListener() {
231 public void menuAboutToShow(IMenuManager manager
) {
232 fillTimeEventContextMenu(fEventMenuManager
);
233 fEventMenuManager
.add(new GroupMarker(IWorkbenchActionConstants
.MB_ADDITIONS
));
236 getSite().registerContextMenu(fEventMenuManager
, fTimeGraphViewer
.getSelectionProvider());
243 * a menuManager to fill
245 protected void fillTimeEventContextMenu(@NonNull IMenuManager menuManager
) {
246 ISelection selection
= getSite().getSelectionProvider().getSelection();
247 if (selection
instanceof IStructuredSelection
) {
248 for (Object object
: ((IStructuredSelection
) selection
).toList()) {
249 if (object
instanceof FlamegraphEvent
) {
250 final FlamegraphEvent flamegraphEvent
= (FlamegraphEvent
) object
;
251 menuManager
.add(new Action(Messages
.FlameGraphView_GotoMaxDuration
) {
254 ISegment maxSeg
= flamegraphEvent
.getStatistics().getMaxSegment();
255 TmfSelectionRangeUpdatedSignal sig
= new TmfSelectionRangeUpdatedSignal(this, TmfTimestamp
.fromNanos(maxSeg
.getStart()), TmfTimestamp
.fromNanos(maxSeg
.getEnd()));
260 menuManager
.add(new Action(Messages
.FlameGraphView_GotoMinDuration
) {
263 ISegment minSeg
= flamegraphEvent
.getStatistics().getMinSegment();
264 TmfSelectionRangeUpdatedSignal sig
= new TmfSelectionRangeUpdatedSignal(this, TmfTimestamp
.fromNanos(minSeg
.getStart()), TmfTimestamp
.fromNanos(minSeg
.getEnd()));
273 private void contributeToActionBars() {
274 IActionBars bars
= getViewSite().getActionBars();
275 fillLocalToolBar(bars
.getToolBarManager());
278 private void fillLocalToolBar(IToolBarManager manager
) {
279 manager
.add(getSortByNameAction());
280 manager
.add(getSortByIdAction());
281 manager
.add(new Separator());
284 private Action
getSortByNameAction() {
285 if (fSortByNameAction
== null) {
286 fSortByNameAction
= new Action(Messages
.FlameGraph_SortByThreadName
, IAction
.AS_CHECK_BOX
) {
289 SortOption sortOption
= fTimeGraphContentProvider
.getSortOption();
290 if (sortOption
== SortOption
.BY_NAME
) {
291 setSortOption(SortOption
.BY_NAME_REV
);
293 setSortOption(SortOption
.BY_NAME
);
297 fSortByNameAction
.setToolTipText(Messages
.FlameGraph_SortByThreadName
);
298 fSortByNameAction
.setImageDescriptor(SORT_BY_NAME_ICON
);
300 return fSortByNameAction
;
303 private Action
getSortByIdAction() {
304 if (fSortByIdAction
== null) {
305 fSortByIdAction
= new Action(Messages
.FlameGraph_SortByThreadId
, IAction
.AS_CHECK_BOX
) {
308 SortOption sortOption
= fTimeGraphContentProvider
.getSortOption();
309 if (sortOption
== SortOption
.BY_ID
) {
310 setSortOption(SortOption
.BY_ID_REV
);
312 setSortOption(SortOption
.BY_ID
);
316 fSortByIdAction
.setToolTipText(Messages
.FlameGraph_SortByThreadId
);
317 fSortByIdAction
.setImageDescriptor(SORT_BY_ID_ICON
);
319 return fSortByIdAction
;
322 private void setSortOption(SortOption sortOption
) {
324 getSortByNameAction().setChecked(false);
325 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_ICON
);
326 getSortByIdAction().setChecked(false);
327 getSortByIdAction().setImageDescriptor(SORT_BY_ID_ICON
);
329 if (sortOption
.equals(SortOption
.BY_NAME
)) {
330 fTimeGraphContentProvider
.setSortOption(SortOption
.BY_NAME
);
331 getSortByNameAction().setChecked(true);
332 } else if (sortOption
.equals(SortOption
.BY_NAME_REV
)) {
333 fTimeGraphContentProvider
.setSortOption(SortOption
.BY_NAME_REV
);
334 getSortByNameAction().setChecked(true);
335 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_REV_ICON
);
336 } else if (sortOption
.equals(SortOption
.BY_ID
)) {
337 fTimeGraphContentProvider
.setSortOption(SortOption
.BY_ID
);
338 getSortByIdAction().setChecked(true);
339 } else if (sortOption
.equals(SortOption
.BY_ID_REV
)) {
340 fTimeGraphContentProvider
.setSortOption(SortOption
.BY_ID_REV
);
341 getSortByIdAction().setChecked(true);
342 getSortByIdAction().setImageDescriptor(SORT_BY_ID_REV_ICON
);
345 fTimeGraphViewer
.refresh();
348 private void saveSortOption() {
349 SortOption sortOption
= fTimeGraphContentProvider
.getSortOption();
350 IDialogSettings settings
= Activator
.getDefault().getDialogSettings();
351 IDialogSettings section
= settings
.getSection(getClass().getName());
352 if (section
== null) {
353 section
= settings
.addNewSection(getClass().getName());
355 section
.put(SORT_OPTION_KEY
, sortOption
.name());
358 private void loadSortOption() {
359 IDialogSettings settings
= Activator
.getDefault().getDialogSettings();
360 IDialogSettings section
= settings
.getSection(getClass().getName());
361 if (section
== null) {
364 String sortOption
= section
.get(SORT_OPTION_KEY
);
365 if (sortOption
== null) {
368 setSortOption(SortOption
.fromName(sortOption
));