87c9773c965597c033f96da38b495c29729f3511
[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.events.MouseAdapter;
35 import org.eclipse.swt.events.MouseEvent;
36 import org.eclipse.swt.widgets.Composite;
37 import org.eclipse.swt.widgets.Display;
38 import org.eclipse.swt.widgets.Menu;
39 import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.CallGraphAnalysis;
40 import org.eclipse.tracecompass.internal.analysis.timing.ui.Activator;
41 import org.eclipse.tracecompass.internal.analysis.timing.ui.callgraph.CallGraphAnalysisUI;
42 import org.eclipse.tracecompass.segmentstore.core.ISegment;
43 import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal;
44 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
45 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
46 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
47 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
48 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
49 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
50 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
51 import org.eclipse.tracecompass.tmf.ui.editors.ITmfTraceEditor;
52 import org.eclipse.tracecompass.tmf.ui.views.TmfView;
53 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider;
54 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphViewer;
55 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
56 import org.eclipse.ui.IActionBars;
57 import org.eclipse.ui.IEditorPart;
58 import org.eclipse.ui.IWorkbenchActionConstants;
59
60 /**
61 * View to display the flame graph .This uses the flameGraphNode tree generated
62 * by CallGraphAnalysisUI.
63 *
64 * @author Sonia Farrah
65 */
66 public class FlameGraphView extends TmfView {
67
68 /**
69 *
70 */
71 public static final String ID = FlameGraphView.class.getPackage().getName() + ".flamegraphView"; //$NON-NLS-1$
72
73 private static final String SORT_OPTION_KEY = "sort.option"; //$NON-NLS-1$
74 private static final ImageDescriptor SORT_BY_NAME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha.gif"); //$NON-NLS-1$
75 private static final ImageDescriptor SORT_BY_NAME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha_rev.gif"); //$NON-NLS-1$
76 private static final ImageDescriptor SORT_BY_ID_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num.gif"); //$NON-NLS-1$
77 private static final ImageDescriptor SORT_BY_ID_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num_rev.gif"); //$NON-NLS-1$
78
79 private TimeGraphViewer fTimeGraphViewer;
80
81 private FlameGraphContentProvider fTimeGraphContentProvider;
82
83 private TimeGraphPresentationProvider fPresentationProvider;
84
85 private ITmfTrace fTrace;
86
87 private final @NonNull MenuManager fEventMenuManager = new MenuManager();
88 private Action fSortByNameAction;
89 private Action fSortByIdAction;
90
91 /**
92 * Constructor
93 */
94 public FlameGraphView() {
95 super(ID);
96 }
97
98 @Override
99 public void createPartControl(Composite parent) {
100 super.createPartControl(parent);
101 fTimeGraphViewer = new TimeGraphViewer(parent, SWT.NONE);
102 fTimeGraphContentProvider = new FlameGraphContentProvider();
103 fPresentationProvider = new FlameGraphPresentationProvider();
104 fTimeGraphViewer.setTimeGraphContentProvider(fTimeGraphContentProvider);
105 fTimeGraphViewer.setTimeGraphProvider(fPresentationProvider);
106 IEditorPart editor = getSite().getPage().getActiveEditor();
107 if (editor instanceof ITmfTraceEditor) {
108 ITmfTrace trace = ((ITmfTraceEditor) editor).getTrace();
109 if (trace != null) {
110 traceSelected(new TmfTraceSelectedSignal(this, trace));
111 }
112 }
113 contributeToActionBars();
114 loadSortOption();
115
116 getSite().setSelectionProvider(fTimeGraphViewer.getSelectionProvider());
117 createTimeEventContextMenu();
118 fTimeGraphViewer.getTimeGraphControl().addMouseListener(new MouseAdapter() {
119 @Override
120 public void mouseDoubleClick(MouseEvent e) {
121 TimeGraphControl timeGraphControl = getTimeGraphViewer().getTimeGraphControl();
122 ISelection selection = timeGraphControl.getSelection();
123 if (selection instanceof IStructuredSelection) {
124 for (Object object : ((IStructuredSelection) selection).toList()) {
125 if (object instanceof FlamegraphEvent) {
126 FlamegraphEvent event = (FlamegraphEvent) object;
127 long startTime = event.getTime();
128 long endTime = startTime + event.getDuration();
129 getTimeGraphViewer().setStartFinishTime(startTime, endTime);
130 break;
131 }
132 }
133 }
134 }
135 });
136 }
137
138 private TimeGraphViewer getTimeGraphViewer() {
139 return fTimeGraphViewer;
140 }
141 /**
142 * Handler for the trace opened signal
143 *
144 * @param signal
145 * The incoming signal
146 */
147 @TmfSignalHandler
148 public void TraceOpened(TmfTraceOpenedSignal signal) {
149 fTrace = signal.getTrace();
150 if (fTrace != null) {
151 CallGraphAnalysis flamegraphModule = TmfTraceUtils.getAnalysisModuleOfClass(fTrace, CallGraphAnalysis.class, CallGraphAnalysisUI.ID);
152 buildFlameGraph(flamegraphModule);
153 }
154 }
155
156 /**
157 * Handler for the trace selected signal
158 *
159 * @param signal
160 * The incoming signal
161 */
162 @TmfSignalHandler
163 public void traceSelected(final TmfTraceSelectedSignal signal) {
164 fTrace = signal.getTrace();
165 if (fTrace != null) {
166 CallGraphAnalysis flamegraphModule = TmfTraceUtils.getAnalysisModuleOfClass(fTrace, CallGraphAnalysis.class, CallGraphAnalysisUI.ID);
167 buildFlameGraph(flamegraphModule);
168 }
169 }
170
171 /**
172 * Get the necessary data for the flame graph and display it
173 *
174 * @param flamegraphModule
175 * the callGraphAnalysis
176 */
177 private void buildFlameGraph(CallGraphAnalysis callGraphAnalysis) {
178 fTimeGraphViewer.setInput(null);
179 callGraphAnalysis.schedule();
180 Job j = new Job(Messages.CallGraphAnalysis_Execution) {
181
182 @Override
183 protected IStatus run(IProgressMonitor monitor) {
184 if (monitor.isCanceled()) {
185 return Status.CANCEL_STATUS;
186 }
187 callGraphAnalysis.waitForCompletion(monitor);
188 Display.getDefault().asyncExec(() -> {
189 fTimeGraphViewer.setInput(callGraphAnalysis.getThreadNodes());
190 fTimeGraphViewer.resetStartFinishTime();
191 });
192 return Status.OK_STATUS;
193 }
194 };
195 j.schedule();
196 }
197
198 /**
199 * Trace is closed: clear the data structures and the view
200 *
201 * @param signal
202 * the signal received
203 */
204 @TmfSignalHandler
205 public void traceClosed(final TmfTraceClosedSignal signal) {
206 if (signal.getTrace() == fTrace) {
207 fTimeGraphViewer.setInput(null);
208 }
209 }
210
211 @Override
212 public void setFocus() {
213 fTimeGraphViewer.setFocus();
214 }
215
216 // ------------------------------------------------------------------------
217 // Helper methods
218 // ------------------------------------------------------------------------
219
220 private void createTimeEventContextMenu() {
221 fEventMenuManager.setRemoveAllWhenShown(true);
222 TimeGraphControl timeGraphControl = fTimeGraphViewer.getTimeGraphControl();
223 final Menu timeEventMenu = fEventMenuManager.createContextMenu(timeGraphControl);
224
225 timeGraphControl.addTimeGraphEntryMenuListener(new MenuDetectListener() {
226 @Override
227 public void menuDetected(MenuDetectEvent event) {
228 /*
229 * The TimeGraphControl will call the TimeGraphEntryMenuListener
230 * before the TimeEventMenuListener. We need to clear the menu
231 * for the case the selection was done on the namespace where
232 * the time event listener below won't be called afterwards.
233 */
234 timeGraphControl.setMenu(null);
235 event.doit = false;
236 }
237 });
238 timeGraphControl.addTimeEventMenuListener(new MenuDetectListener() {
239 @Override
240 public void menuDetected(MenuDetectEvent event) {
241 Menu menu = timeEventMenu;
242 if (event.data instanceof FlamegraphEvent) {
243 timeGraphControl.setMenu(menu);
244 return;
245 }
246 timeGraphControl.setMenu(null);
247 event.doit = false;
248 }
249 });
250
251 fEventMenuManager.addMenuListener(new IMenuListener() {
252 @Override
253 public void menuAboutToShow(IMenuManager manager) {
254 fillTimeEventContextMenu(fEventMenuManager);
255 fEventMenuManager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
256 }
257 });
258 getSite().registerContextMenu(fEventMenuManager, fTimeGraphViewer.getSelectionProvider());
259 }
260
261 /**
262 * Fill context menu
263 *
264 * @param menuManager
265 * a menuManager to fill
266 */
267 protected void fillTimeEventContextMenu(@NonNull IMenuManager menuManager) {
268 ISelection selection = getSite().getSelectionProvider().getSelection();
269 if (selection instanceof IStructuredSelection) {
270 for (Object object : ((IStructuredSelection) selection).toList()) {
271 if (object instanceof FlamegraphEvent) {
272 final FlamegraphEvent flamegraphEvent = (FlamegraphEvent) object;
273 menuManager.add(new Action(Messages.FlameGraphView_GotoMaxDuration) {
274 @Override
275 public void run() {
276 ISegment maxSeg = flamegraphEvent.getStatistics().getMaxSegment();
277 TmfSelectionRangeUpdatedSignal sig = new TmfSelectionRangeUpdatedSignal(this, TmfTimestamp.fromNanos(maxSeg.getStart()), TmfTimestamp.fromNanos(maxSeg.getEnd()));
278 broadcast(sig);
279 }
280 });
281
282 menuManager.add(new Action(Messages.FlameGraphView_GotoMinDuration) {
283 @Override
284 public void run() {
285 ISegment minSeg = flamegraphEvent.getStatistics().getMinSegment();
286 TmfSelectionRangeUpdatedSignal sig = new TmfSelectionRangeUpdatedSignal(this, TmfTimestamp.fromNanos(minSeg.getStart()), TmfTimestamp.fromNanos(minSeg.getEnd()));
287 broadcast(sig);
288 }
289 });
290 }
291 }
292 }
293 }
294
295 private void contributeToActionBars() {
296 IActionBars bars = getViewSite().getActionBars();
297 fillLocalToolBar(bars.getToolBarManager());
298 }
299
300 private void fillLocalToolBar(IToolBarManager manager) {
301 manager.add(getSortByNameAction());
302 manager.add(getSortByIdAction());
303 manager.add(new Separator());
304 }
305
306 private Action getSortByNameAction() {
307 if (fSortByNameAction == null) {
308 fSortByNameAction = new Action(Messages.FlameGraph_SortByThreadName, IAction.AS_CHECK_BOX) {
309 @Override
310 public void run() {
311 SortOption sortOption = fTimeGraphContentProvider.getSortOption();
312 if (sortOption == SortOption.BY_NAME) {
313 setSortOption(SortOption.BY_NAME_REV);
314 } else {
315 setSortOption(SortOption.BY_NAME);
316 }
317 }
318 };
319 fSortByNameAction.setToolTipText(Messages.FlameGraph_SortByThreadName);
320 fSortByNameAction.setImageDescriptor(SORT_BY_NAME_ICON);
321 }
322 return fSortByNameAction;
323 }
324
325 private Action getSortByIdAction() {
326 if (fSortByIdAction == null) {
327 fSortByIdAction = new Action(Messages.FlameGraph_SortByThreadId, IAction.AS_CHECK_BOX) {
328 @Override
329 public void run() {
330 SortOption sortOption = fTimeGraphContentProvider.getSortOption();
331 if (sortOption == SortOption.BY_ID) {
332 setSortOption(SortOption.BY_ID_REV);
333 } else {
334 setSortOption(SortOption.BY_ID);
335 }
336 }
337 };
338 fSortByIdAction.setToolTipText(Messages.FlameGraph_SortByThreadId);
339 fSortByIdAction.setImageDescriptor(SORT_BY_ID_ICON);
340 }
341 return fSortByIdAction;
342 }
343
344 private void setSortOption(SortOption sortOption) {
345 // reset defaults
346 getSortByNameAction().setChecked(false);
347 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_ICON);
348 getSortByIdAction().setChecked(false);
349 getSortByIdAction().setImageDescriptor(SORT_BY_ID_ICON);
350
351 if (sortOption.equals(SortOption.BY_NAME)) {
352 fTimeGraphContentProvider.setSortOption(SortOption.BY_NAME);
353 getSortByNameAction().setChecked(true);
354 } else if (sortOption.equals(SortOption.BY_NAME_REV)) {
355 fTimeGraphContentProvider.setSortOption(SortOption.BY_NAME_REV);
356 getSortByNameAction().setChecked(true);
357 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_REV_ICON);
358 } else if (sortOption.equals(SortOption.BY_ID)) {
359 fTimeGraphContentProvider.setSortOption(SortOption.BY_ID);
360 getSortByIdAction().setChecked(true);
361 } else if (sortOption.equals(SortOption.BY_ID_REV)) {
362 fTimeGraphContentProvider.setSortOption(SortOption.BY_ID_REV);
363 getSortByIdAction().setChecked(true);
364 getSortByIdAction().setImageDescriptor(SORT_BY_ID_REV_ICON);
365 }
366 saveSortOption();
367 fTimeGraphViewer.refresh();
368 }
369
370 private void saveSortOption() {
371 SortOption sortOption = fTimeGraphContentProvider.getSortOption();
372 IDialogSettings settings = Activator.getDefault().getDialogSettings();
373 IDialogSettings section = settings.getSection(getClass().getName());
374 if (section == null) {
375 section = settings.addNewSection(getClass().getName());
376 }
377 section.put(SORT_OPTION_KEY, sortOption.name());
378 }
379
380 private void loadSortOption() {
381 IDialogSettings settings = Activator.getDefault().getDialogSettings();
382 IDialogSettings section = settings.getSection(getClass().getName());
383 if (section == null) {
384 return;
385 }
386 String sortOption = section.get(SORT_OPTION_KEY);
387 if (sortOption == null) {
388 return;
389 }
390 setSortOption(SortOption.fromName(sortOption));
391 }
392
393 }
This page took 0.039215 seconds and 4 git commands to generate.