575fcf926019d26247905878d8a02f0134e7e57c
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.timing.ui / src / org / eclipse / tracecompass / internal / analysis / timing / ui / flamegraph / FlameGraphView.java
1 /*******************************************************************************
2 * Copyright (c) 2016 Ericsson
3 *
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
8 *
9 * Author:
10 * Sonia Farrah
11 *******************************************************************************/
12 package org.eclipse.tracecompass.internal.analysis.timing.ui.flamegraph;
13
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;
57
58 /**
59 * View to display the flame graph .This uses the flameGraphNode tree generated
60 * by CallGraphAnalysisUI.
61 *
62 * @author Sonia Farrah
63 */
64 public class FlameGraphView extends TmfView {
65
66 /**
67 *
68 */
69 public static final String ID = FlameGraphView.class.getPackage().getName() + ".flamegraphView"; //$NON-NLS-1$
70
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$
76
77
78 private TimeGraphViewer fTimeGraphViewer;
79
80 private FlameGraphContentProvider fTimeGraphContentProvider;
81
82 private TimeGraphPresentationProvider fPresentationProvider;
83
84 private ITmfTrace fTrace;
85
86 private final @NonNull MenuManager fEventMenuManager = new MenuManager();
87 private Action fSortByNameAction;
88 private Action fSortByIdAction;
89
90 /**
91 * Constructor
92 */
93 public FlameGraphView() {
94 super(ID);
95 }
96
97 @Override
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();
108 if (trace != null) {
109 traceSelected(new TmfTraceSelectedSignal(this, trace));
110 }
111 }
112 contributeToActionBars();
113 loadSortOption();
114
115 getSite().setSelectionProvider(fTimeGraphViewer.getSelectionProvider());
116 createTimeEventContextMenu();
117 }
118
119
120 /**
121 * Handler for the trace opened signal
122 *
123 * @param signal
124 * The incoming signal
125 */
126 @TmfSignalHandler
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);
132 }
133 }
134
135 /**
136 * Handler for the trace selected signal
137 *
138 * @param signal
139 * The incoming signal
140 */
141 @TmfSignalHandler
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);
147 }
148 }
149
150 /**
151 * Get the necessary data for the flame graph and display it
152 *
153 * @param flamegraphModule
154 * the callGraphAnalysis
155 */
156 private void buildFlameGraph(CallGraphAnalysis callGraphAnalysis) {
157 fTimeGraphViewer.setInput(null);
158 callGraphAnalysis.schedule();
159 Job j = new Job(Messages.CallGraphAnalysis_Execution) {
160
161 @Override
162 protected IStatus run(IProgressMonitor monitor) {
163 if (monitor.isCanceled()) {
164 return Status.CANCEL_STATUS;
165 }
166 callGraphAnalysis.waitForCompletion(monitor);
167 Display.getDefault().asyncExec(() -> {
168 fTimeGraphViewer.setInput(callGraphAnalysis.getThreadNodes());
169 fTimeGraphViewer.resetStartFinishTime();
170 });
171 return Status.OK_STATUS;
172 }
173 };
174 j.schedule();
175 }
176
177 /**
178 * Trace is closed: clear the data structures and the view
179 *
180 * @param signal
181 * the signal received
182 */
183 @TmfSignalHandler
184 public void traceClosed(final TmfTraceClosedSignal signal) {
185 if (signal.getTrace() == fTrace) {
186 fTimeGraphViewer.setInput(null);
187 }
188 }
189
190 @Override
191 public void setFocus() {
192 fTimeGraphViewer.setFocus();
193 }
194
195 // ------------------------------------------------------------------------
196 // Helper methods
197 // ------------------------------------------------------------------------
198
199 private void createTimeEventContextMenu() {
200 fEventMenuManager.setRemoveAllWhenShown(true);
201 TimeGraphControl timeGraphControl = fTimeGraphViewer.getTimeGraphControl();
202 final Menu timeEventMenu = fEventMenuManager.createContextMenu(timeGraphControl);
203
204 timeGraphControl.addTimeGraphEntryMenuListener(new MenuDetectListener() {
205 @Override
206 public void menuDetected(MenuDetectEvent event) {
207 /*
208 * The TimeGraphControl will call the TimeGraphEntryMenuListener
209 * before the TimeEventMenuListener. We need to clear the menu
210 * for the case the selection was done on the namespace where
211 * the time event listener below won't be called afterwards.
212 */
213 timeGraphControl.setMenu(null);
214 event.doit = false;
215 }
216 });
217 timeGraphControl.addTimeEventMenuListener(new MenuDetectListener() {
218 @Override
219 public void menuDetected(MenuDetectEvent event) {
220 Menu menu = timeEventMenu;
221 if (event.data instanceof FlamegraphEvent) {
222 timeGraphControl.setMenu(menu);
223 return;
224 }
225 timeGraphControl.setMenu(null);
226 event.doit = false;
227 }
228 });
229
230 fEventMenuManager.addMenuListener(new IMenuListener() {
231 @Override
232 public void menuAboutToShow(IMenuManager manager) {
233 fillTimeEventContextMenu(fEventMenuManager);
234 fEventMenuManager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
235 }
236 });
237 getSite().registerContextMenu(fEventMenuManager, fTimeGraphViewer.getSelectionProvider());
238 }
239
240 /**
241 * Fill context menu
242 *
243 * @param menuManager
244 * a menuManager to fill
245 */
246 protected void fillTimeEventContextMenu(@NonNull IMenuManager menuManager) {
247 ISelection selection = getSite().getSelectionProvider().getSelection();
248 if (selection instanceof IStructuredSelection) {
249 for (Object object : ((IStructuredSelection) selection).toList()) {
250 if (object instanceof FlamegraphEvent) {
251 final FlamegraphEvent flamegraphEvent = (FlamegraphEvent) object;
252 menuManager.add(new Action(Messages.FlameGraphView_GotoMaxDuration) {
253 @Override
254 public void run() {
255 ISegment maxSeg = flamegraphEvent.getStatistics().getMaxSegment();
256 TmfSelectionRangeUpdatedSignal sig = new TmfSelectionRangeUpdatedSignal(this, TmfTimestamp.fromNanos(maxSeg.getStart()), TmfTimestamp.fromNanos(maxSeg.getEnd()));
257 broadcast(sig);
258 }
259 });
260
261 menuManager.add(new Action(Messages.FlameGraphView_GotoMinDuration) {
262 @Override
263 public void run() {
264 ISegment minSeg = flamegraphEvent.getStatistics().getMinSegment();
265 TmfSelectionRangeUpdatedSignal sig = new TmfSelectionRangeUpdatedSignal(this, TmfTimestamp.fromNanos(minSeg.getStart()), TmfTimestamp.fromNanos(minSeg.getEnd()));
266 broadcast(sig);
267 }
268 });
269 }
270 }
271 }
272 }
273
274 private void contributeToActionBars() {
275 IActionBars bars = getViewSite().getActionBars();
276 fillLocalToolBar(bars.getToolBarManager());
277 }
278
279 private void fillLocalToolBar(IToolBarManager manager) {
280 manager.add(getSortByNameAction());
281 manager.add(getSortByIdAction());
282 manager.add(new Separator());
283 }
284
285 private Action getSortByNameAction() {
286 if (fSortByNameAction == null) {
287 fSortByNameAction = new Action(Messages.FlameGraph_SortByThreadName, IAction.AS_CHECK_BOX) {
288 @Override
289 public void run() {
290 SortOption sortOption = fTimeGraphContentProvider.getSortOption();
291 if (sortOption == SortOption.BY_NAME) {
292 setSortOption(SortOption.BY_NAME_REV);
293 } else {
294 setSortOption(SortOption.BY_NAME);
295 }
296 }
297 };
298 fSortByNameAction.setToolTipText(Messages.FlameGraph_SortByThreadName);
299 fSortByNameAction.setImageDescriptor(SORT_BY_NAME_ICON);
300 }
301 return fSortByNameAction;
302 }
303
304 private Action getSortByIdAction() {
305 if (fSortByIdAction == null) {
306 fSortByIdAction = new Action(Messages.FlameGraph_SortByThreadId, IAction.AS_CHECK_BOX) {
307 @Override
308 public void run() {
309 SortOption sortOption = fTimeGraphContentProvider.getSortOption();
310 if (sortOption == SortOption.BY_ID) {
311 setSortOption(SortOption.BY_ID_REV);
312 } else {
313 setSortOption(SortOption.BY_ID);
314 }
315 }
316 };
317 fSortByIdAction.setToolTipText(Messages.FlameGraph_SortByThreadId);
318 fSortByIdAction.setImageDescriptor(SORT_BY_ID_ICON);
319 }
320 return fSortByIdAction;
321 }
322
323 private void setSortOption(SortOption sortOption) {
324 // reset defaults
325 getSortByNameAction().setChecked(false);
326 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_ICON);
327 getSortByIdAction().setChecked(false);
328 getSortByIdAction().setImageDescriptor(SORT_BY_ID_ICON);
329
330 if (sortOption.equals(SortOption.BY_NAME)) {
331 fTimeGraphContentProvider.setSortOption(SortOption.BY_NAME);
332 getSortByNameAction().setChecked(true);
333 } else if (sortOption.equals(SortOption.BY_NAME_REV)) {
334 fTimeGraphContentProvider.setSortOption(SortOption.BY_NAME_REV);
335 getSortByNameAction().setChecked(true);
336 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_REV_ICON);
337 } else if (sortOption.equals(SortOption.BY_ID)) {
338 fTimeGraphContentProvider.setSortOption(SortOption.BY_ID);
339 getSortByIdAction().setChecked(true);
340 } else if (sortOption.equals(SortOption.BY_ID_REV)) {
341 fTimeGraphContentProvider.setSortOption(SortOption.BY_ID_REV);
342 getSortByIdAction().setChecked(true);
343 getSortByIdAction().setImageDescriptor(SORT_BY_ID_REV_ICON);
344 }
345 saveSortOption();
346 fTimeGraphViewer.refresh();
347 }
348
349 private void saveSortOption() {
350 SortOption sortOption = fTimeGraphContentProvider.getSortOption();
351 IDialogSettings settings = Activator.getDefault().getDialogSettings();
352 IDialogSettings section = settings.getSection(getClass().getName());
353 if (section == null) {
354 section = settings.addNewSection(getClass().getName());
355 }
356 section.put(SORT_OPTION_KEY, sortOption.name());
357 }
358
359 private void loadSortOption() {
360 IDialogSettings settings = Activator.getDefault().getDialogSettings();
361 IDialogSettings section = settings.getSection(getClass().getName());
362 if (section == null) {
363 return;
364 }
365 String sortOption = section.get(SORT_OPTION_KEY);
366 if (sortOption == null) {
367 return;
368 }
369 setSortOption(SortOption.fromName(sortOption));
370 }
371
372 }
This page took 0.037723 seconds and 4 git commands to generate.