timing.ui: Remove dependency on trace with FlameGraphContentProvider
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.timing.ui / src / org / eclipse / tracecompass / internal / analysis / timing / ui / flamegraph / FlameGraphView.java
CommitLineData
74ccf789
SF
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 *******************************************************************************/
12package org.eclipse.tracecompass.internal.analysis.timing.ui.flamegraph;
13
c827e96f
MK
14import java.util.concurrent.Semaphore;
15
74ccf789
SF
16import org.eclipse.core.runtime.IProgressMonitor;
17import org.eclipse.core.runtime.IStatus;
18import org.eclipse.core.runtime.Status;
19import org.eclipse.core.runtime.jobs.Job;
f13aa9cd
MK
20import org.eclipse.jdt.annotation.NonNull;
21import org.eclipse.jface.action.Action;
22import org.eclipse.jface.action.GroupMarker;
e162d9ae 23import org.eclipse.jface.action.IAction;
f13aa9cd
MK
24import org.eclipse.jface.action.IMenuListener;
25import org.eclipse.jface.action.IMenuManager;
e162d9ae 26import org.eclipse.jface.action.IToolBarManager;
f13aa9cd 27import org.eclipse.jface.action.MenuManager;
e162d9ae
BH
28import org.eclipse.jface.action.Separator;
29import org.eclipse.jface.dialogs.IDialogSettings;
30import org.eclipse.jface.resource.ImageDescriptor;
f13aa9cd
MK
31import org.eclipse.jface.viewers.ISelection;
32import org.eclipse.jface.viewers.IStructuredSelection;
74ccf789 33import org.eclipse.swt.SWT;
f13aa9cd
MK
34import org.eclipse.swt.events.MenuDetectEvent;
35import org.eclipse.swt.events.MenuDetectListener;
9d92c2d2
MK
36import org.eclipse.swt.events.MouseAdapter;
37import org.eclipse.swt.events.MouseEvent;
74ccf789
SF
38import org.eclipse.swt.widgets.Composite;
39import org.eclipse.swt.widgets.Display;
f13aa9cd 40import org.eclipse.swt.widgets.Menu;
74ccf789 41import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.CallGraphAnalysis;
e162d9ae 42import org.eclipse.tracecompass.internal.analysis.timing.ui.Activator;
74ccf789 43import org.eclipse.tracecompass.internal.analysis.timing.ui.callgraph.CallGraphAnalysisUI;
f13aa9cd
MK
44import org.eclipse.tracecompass.segmentstore.core.ISegment;
45import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal;
74ccf789
SF
46import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
47import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
74ccf789 48import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
f13aa9cd 49import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
74ccf789 50import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
74ccf789
SF
51import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
52import org.eclipse.tracecompass.tmf.ui.editors.ITmfTraceEditor;
53import org.eclipse.tracecompass.tmf.ui.views.TmfView;
54import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider;
55import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphViewer;
f13aa9cd 56import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
e162d9ae 57import org.eclipse.ui.IActionBars;
74ccf789 58import org.eclipse.ui.IEditorPart;
f13aa9cd 59import org.eclipse.ui.IWorkbenchActionConstants;
74ccf789 60
c827e96f
MK
61import com.google.common.annotations.VisibleForTesting;
62
74ccf789
SF
63/**
64 * View to display the flame graph .This uses the flameGraphNode tree generated
65 * by CallGraphAnalysisUI.
66 *
67 * @author Sonia Farrah
68 */
69public class FlameGraphView extends TmfView {
70
71 /**
72 *
73 */
74 public static final String ID = FlameGraphView.class.getPackage().getName() + ".flamegraphView"; //$NON-NLS-1$
75
e162d9ae
BH
76 private static final String SORT_OPTION_KEY = "sort.option"; //$NON-NLS-1$
77 private static final ImageDescriptor SORT_BY_NAME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha.gif"); //$NON-NLS-1$
78 private static final ImageDescriptor SORT_BY_NAME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha_rev.gif"); //$NON-NLS-1$
79 private static final ImageDescriptor SORT_BY_ID_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num.gif"); //$NON-NLS-1$
80 private static final ImageDescriptor SORT_BY_ID_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num_rev.gif"); //$NON-NLS-1$
81
74ccf789
SF
82 private TimeGraphViewer fTimeGraphViewer;
83
84 private FlameGraphContentProvider fTimeGraphContentProvider;
85
86 private TimeGraphPresentationProvider fPresentationProvider;
87
88 private ITmfTrace fTrace;
89
f13aa9cd 90 private final @NonNull MenuManager fEventMenuManager = new MenuManager();
e162d9ae
BH
91 private Action fSortByNameAction;
92 private Action fSortByIdAction;
c827e96f
MK
93 /**
94 * A plain old semaphore is used since different threads will be competing
95 * for the same resource.
96 */
97 private final Semaphore fLock = new Semaphore(1);
f13aa9cd 98
74ccf789
SF
99 /**
100 * Constructor
101 */
102 public FlameGraphView() {
103 super(ID);
104 }
105
106 @Override
107 public void createPartControl(Composite parent) {
108 super.createPartControl(parent);
109 fTimeGraphViewer = new TimeGraphViewer(parent, SWT.NONE);
110 fTimeGraphContentProvider = new FlameGraphContentProvider();
111 fPresentationProvider = new FlameGraphPresentationProvider();
112 fTimeGraphViewer.setTimeGraphContentProvider(fTimeGraphContentProvider);
113 fTimeGraphViewer.setTimeGraphProvider(fPresentationProvider);
114 IEditorPart editor = getSite().getPage().getActiveEditor();
115 if (editor instanceof ITmfTraceEditor) {
116 ITmfTrace trace = ((ITmfTraceEditor) editor).getTrace();
117 if (trace != null) {
118 traceSelected(new TmfTraceSelectedSignal(this, trace));
119 }
120 }
e162d9ae
BH
121 contributeToActionBars();
122 loadSortOption();
123
f13aa9cd
MK
124 getSite().setSelectionProvider(fTimeGraphViewer.getSelectionProvider());
125 createTimeEventContextMenu();
9d92c2d2
MK
126 fTimeGraphViewer.getTimeGraphControl().addMouseListener(new MouseAdapter() {
127 @Override
128 public void mouseDoubleClick(MouseEvent e) {
129 TimeGraphControl timeGraphControl = getTimeGraphViewer().getTimeGraphControl();
130 ISelection selection = timeGraphControl.getSelection();
131 if (selection instanceof IStructuredSelection) {
132 for (Object object : ((IStructuredSelection) selection).toList()) {
133 if (object instanceof FlamegraphEvent) {
134 FlamegraphEvent event = (FlamegraphEvent) object;
135 long startTime = event.getTime();
136 long endTime = startTime + event.getDuration();
137 getTimeGraphViewer().setStartFinishTime(startTime, endTime);
138 break;
139 }
140 }
141 }
142 }
143 });
74ccf789
SF
144 }
145
74ccf789 146 /**
c827e96f 147 * Get the time graph viewer
74ccf789 148 *
c827e96f 149 * @return the time graph viewer
74ccf789 150 */
c827e96f
MK
151 @VisibleForTesting
152 public TimeGraphViewer getTimeGraphViewer() {
153 return fTimeGraphViewer;
74ccf789
SF
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 *
c827e96f 174 * @param callGraphAnalysis
74ccf789
SF
175 * the callGraphAnalysis
176 */
c827e96f
MK
177 @VisibleForTesting
178 public void buildFlameGraph(CallGraphAnalysis callGraphAnalysis) {
179 /*
180 * Note for synchronization:
181 *
182 * Acquire the lock at entry. then we have 4 places to release it
183 *
184 * 1- if the lock failed
185 *
186 * 2- if the data is null and we have no UI to update
187 *
188 * 3- if the request is cancelled before it gets to the display
189 *
190 * 4- on a clean execution
191 */
192 try {
193 fLock.acquire();
194 } catch (InterruptedException e) {
195 Activator.getDefault().logError(e.getMessage(), e);
196 fLock.release();
197 }
198 if (callGraphAnalysis == null) {
199 fTimeGraphViewer.setInput(null);
200 fLock.release();
201 return;
202 }
203 fTimeGraphViewer.setInput(callGraphAnalysis.getSegmentStore());
74ccf789
SF
204 callGraphAnalysis.schedule();
205 Job j = new Job(Messages.CallGraphAnalysis_Execution) {
206
207 @Override
208 protected IStatus run(IProgressMonitor monitor) {
209 if (monitor.isCanceled()) {
c827e96f 210 fLock.release();
74ccf789
SF
211 return Status.CANCEL_STATUS;
212 }
213 callGraphAnalysis.waitForCompletion(monitor);
214 Display.getDefault().asyncExec(() -> {
215 fTimeGraphViewer.setInput(callGraphAnalysis.getThreadNodes());
c418199f 216 fTimeGraphViewer.resetStartFinishTime();
c827e96f 217 fLock.release();
74ccf789
SF
218 });
219 return Status.OK_STATUS;
220 }
221 };
222 j.schedule();
223 }
224
c827e96f
MK
225 /**
226 * Await the next refresh
227 *
228 * @throws InterruptedException
229 * something took too long
230 */
231 @VisibleForTesting
232 public void waitForUpdate() throws InterruptedException {
233 /*
234 * wait for the semaphore to be available, then release it immediately
235 */
236 fLock.acquire();
237 fLock.release();
238 }
239
74ccf789
SF
240 /**
241 * Trace is closed: clear the data structures and the view
242 *
243 * @param signal
244 * the signal received
245 */
246 @TmfSignalHandler
247 public void traceClosed(final TmfTraceClosedSignal signal) {
248 if (signal.getTrace() == fTrace) {
249 fTimeGraphViewer.setInput(null);
250 }
251 }
252
253 @Override
254 public void setFocus() {
255 fTimeGraphViewer.setFocus();
256 }
257
e162d9ae
BH
258 // ------------------------------------------------------------------------
259 // Helper methods
260 // ------------------------------------------------------------------------
261
f13aa9cd
MK
262 private void createTimeEventContextMenu() {
263 fEventMenuManager.setRemoveAllWhenShown(true);
264 TimeGraphControl timeGraphControl = fTimeGraphViewer.getTimeGraphControl();
265 final Menu timeEventMenu = fEventMenuManager.createContextMenu(timeGraphControl);
266
267 timeGraphControl.addTimeGraphEntryMenuListener(new MenuDetectListener() {
268 @Override
269 public void menuDetected(MenuDetectEvent event) {
270 /*
271 * The TimeGraphControl will call the TimeGraphEntryMenuListener
272 * before the TimeEventMenuListener. We need to clear the menu
273 * for the case the selection was done on the namespace where
274 * the time event listener below won't be called afterwards.
275 */
276 timeGraphControl.setMenu(null);
277 event.doit = false;
278 }
279 });
280 timeGraphControl.addTimeEventMenuListener(new MenuDetectListener() {
281 @Override
282 public void menuDetected(MenuDetectEvent event) {
283 Menu menu = timeEventMenu;
284 if (event.data instanceof FlamegraphEvent) {
285 timeGraphControl.setMenu(menu);
286 return;
287 }
288 timeGraphControl.setMenu(null);
289 event.doit = false;
290 }
291 });
292
293 fEventMenuManager.addMenuListener(new IMenuListener() {
294 @Override
295 public void menuAboutToShow(IMenuManager manager) {
296 fillTimeEventContextMenu(fEventMenuManager);
297 fEventMenuManager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
298 }
299 });
300 getSite().registerContextMenu(fEventMenuManager, fTimeGraphViewer.getSelectionProvider());
301 }
302
303 /**
304 * Fill context menu
305 *
306 * @param menuManager
9d92c2d2 307 * a menuManager to fill
f13aa9cd
MK
308 */
309 protected void fillTimeEventContextMenu(@NonNull IMenuManager menuManager) {
310 ISelection selection = getSite().getSelectionProvider().getSelection();
311 if (selection instanceof IStructuredSelection) {
312 for (Object object : ((IStructuredSelection) selection).toList()) {
313 if (object instanceof FlamegraphEvent) {
314 final FlamegraphEvent flamegraphEvent = (FlamegraphEvent) object;
315 menuManager.add(new Action(Messages.FlameGraphView_GotoMaxDuration) {
316 @Override
317 public void run() {
318 ISegment maxSeg = flamegraphEvent.getStatistics().getMaxSegment();
319 TmfSelectionRangeUpdatedSignal sig = new TmfSelectionRangeUpdatedSignal(this, TmfTimestamp.fromNanos(maxSeg.getStart()), TmfTimestamp.fromNanos(maxSeg.getEnd()));
320 broadcast(sig);
321 }
322 });
323
324 menuManager.add(new Action(Messages.FlameGraphView_GotoMinDuration) {
325 @Override
326 public void run() {
327 ISegment minSeg = flamegraphEvent.getStatistics().getMinSegment();
328 TmfSelectionRangeUpdatedSignal sig = new TmfSelectionRangeUpdatedSignal(this, TmfTimestamp.fromNanos(minSeg.getStart()), TmfTimestamp.fromNanos(minSeg.getEnd()));
329 broadcast(sig);
330 }
331 });
332 }
333 }
334 }
335 }
e162d9ae
BH
336
337 private void contributeToActionBars() {
338 IActionBars bars = getViewSite().getActionBars();
339 fillLocalToolBar(bars.getToolBarManager());
340 }
341
342 private void fillLocalToolBar(IToolBarManager manager) {
343 manager.add(getSortByNameAction());
344 manager.add(getSortByIdAction());
345 manager.add(new Separator());
346 }
347
348 private Action getSortByNameAction() {
349 if (fSortByNameAction == null) {
350 fSortByNameAction = new Action(Messages.FlameGraph_SortByThreadName, IAction.AS_CHECK_BOX) {
351 @Override
352 public void run() {
353 SortOption sortOption = fTimeGraphContentProvider.getSortOption();
354 if (sortOption == SortOption.BY_NAME) {
355 setSortOption(SortOption.BY_NAME_REV);
356 } else {
357 setSortOption(SortOption.BY_NAME);
358 }
359 }
360 };
361 fSortByNameAction.setToolTipText(Messages.FlameGraph_SortByThreadName);
362 fSortByNameAction.setImageDescriptor(SORT_BY_NAME_ICON);
363 }
364 return fSortByNameAction;
365 }
366
367 private Action getSortByIdAction() {
368 if (fSortByIdAction == null) {
369 fSortByIdAction = new Action(Messages.FlameGraph_SortByThreadId, IAction.AS_CHECK_BOX) {
370 @Override
371 public void run() {
372 SortOption sortOption = fTimeGraphContentProvider.getSortOption();
373 if (sortOption == SortOption.BY_ID) {
374 setSortOption(SortOption.BY_ID_REV);
375 } else {
376 setSortOption(SortOption.BY_ID);
377 }
378 }
379 };
380 fSortByIdAction.setToolTipText(Messages.FlameGraph_SortByThreadId);
381 fSortByIdAction.setImageDescriptor(SORT_BY_ID_ICON);
382 }
383 return fSortByIdAction;
384 }
385
386 private void setSortOption(SortOption sortOption) {
387 // reset defaults
388 getSortByNameAction().setChecked(false);
389 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_ICON);
390 getSortByIdAction().setChecked(false);
391 getSortByIdAction().setImageDescriptor(SORT_BY_ID_ICON);
392
393 if (sortOption.equals(SortOption.BY_NAME)) {
394 fTimeGraphContentProvider.setSortOption(SortOption.BY_NAME);
395 getSortByNameAction().setChecked(true);
396 } else if (sortOption.equals(SortOption.BY_NAME_REV)) {
397 fTimeGraphContentProvider.setSortOption(SortOption.BY_NAME_REV);
398 getSortByNameAction().setChecked(true);
399 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_REV_ICON);
400 } else if (sortOption.equals(SortOption.BY_ID)) {
401 fTimeGraphContentProvider.setSortOption(SortOption.BY_ID);
402 getSortByIdAction().setChecked(true);
403 } else if (sortOption.equals(SortOption.BY_ID_REV)) {
404 fTimeGraphContentProvider.setSortOption(SortOption.BY_ID_REV);
405 getSortByIdAction().setChecked(true);
406 getSortByIdAction().setImageDescriptor(SORT_BY_ID_REV_ICON);
407 }
408 saveSortOption();
409 fTimeGraphViewer.refresh();
410 }
411
412 private void saveSortOption() {
413 SortOption sortOption = fTimeGraphContentProvider.getSortOption();
414 IDialogSettings settings = Activator.getDefault().getDialogSettings();
415 IDialogSettings section = settings.getSection(getClass().getName());
416 if (section == null) {
417 section = settings.addNewSection(getClass().getName());
418 }
419 section.put(SORT_OPTION_KEY, sortOption.name());
420 }
421
422 private void loadSortOption() {
423 IDialogSettings settings = Activator.getDefault().getDialogSettings();
424 IDialogSettings section = settings.getSection(getClass().getName());
425 if (section == null) {
426 return;
427 }
428 String sortOption = section.get(SORT_OPTION_KEY);
429 if (sortOption == null) {
430 return;
431 }
432 setSortOption(SortOption.fromName(sortOption));
433 }
434
74ccf789 435}
This page took 0.044655 seconds and 5 git commands to generate.