1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 Ericsson, École Polytechnique de Montréal
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
10 * Patrick Tasse - Initial API and implementation
11 * Geneviève Bastien - Move code to provide base classes for time graph view
12 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.internal
.lttng2
.kernel
.ui
.views
.controlflow
;
16 import java
.util
.ArrayList
;
17 import java
.util
.Collections
;
18 import java
.util
.Comparator
;
19 import java
.util
.List
;
21 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
22 import org
.eclipse
.jface
.action
.IToolBarManager
;
23 import org
.eclipse
.jface
.dialogs
.IDialogSettings
;
24 import org
.eclipse
.linuxtools
.internal
.lttng2
.kernel
.core
.Attributes
;
25 import org
.eclipse
.linuxtools
.internal
.lttng2
.kernel
.ui
.Activator
;
26 import org
.eclipse
.linuxtools
.internal
.lttng2
.kernel
.ui
.Messages
;
27 import org
.eclipse
.linuxtools
.lttng2
.kernel
.core
.trace
.LttngKernelTrace
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.AttributeNotFoundException
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateSystemDisposedException
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateValueTypeException
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TimeRangeException
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.interval
.ITmfStateInterval
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.statesystem
.ITmfStateSystem
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.statevalue
.ITmfStateValue
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
36 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfTraceManager
;
37 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.timegraph
.AbstractTimeGraphView
;
38 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ILinkEvent
;
39 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
40 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
41 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.TimeEvent
;
42 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.TimeGraphEntry
;
43 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.TimeLinkEvent
;
44 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
;
45 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.Resolution
;
46 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.TimeFormat
;
49 * The Control Flow view main object
52 public class ControlFlowView
extends AbstractTimeGraphView
{
54 // ------------------------------------------------------------------------
56 // ------------------------------------------------------------------------
61 public static final String ID
= "org.eclipse.linuxtools.lttng2.kernel.ui.views.controlflow"; //$NON-NLS-1$
63 private static final String PROCESS_COLUMN
= Messages
.ControlFlowView_processColumn
;
64 private static final String TID_COLUMN
= Messages
.ControlFlowView_tidColumn
;
65 private static final String PTID_COLUMN
= Messages
.ControlFlowView_ptidColumn
;
66 private static final String BIRTH_TIME_COLUMN
= Messages
.ControlFlowView_birthTimeColumn
;
67 private static final String TRACE_COLUMN
= Messages
.ControlFlowView_traceColumn
;
69 private static final String
[] COLUMN_NAMES
= new String
[] {
77 private static final String
[] FILTER_COLUMN_NAMES
= new String
[] {
82 // ------------------------------------------------------------------------
84 // ------------------------------------------------------------------------
89 public ControlFlowView() {
90 super(ID
, new ControlFlowPresentationProvider());
91 setTreeColumns(COLUMN_NAMES
);
92 setTreeLabelProvider(new ControlFlowTreeLabelProvider());
93 setFilterColumns(FILTER_COLUMN_NAMES
);
94 setEntryComparator(new ControlFlowEntryComparator());
98 protected void fillLocalToolBar(IToolBarManager manager
) {
99 super.fillLocalToolBar(manager
);
100 IDialogSettings settings
= Activator
.getDefault().getDialogSettings();
101 IDialogSettings section
= settings
.getSection(getClass().getName());
102 if (section
== null) {
103 section
= settings
.addNewSection(getClass().getName());
105 manager
.add(getTimeGraphCombo().getTimeGraphViewer().getHideArrowsAction(section
));
106 manager
.add(getTimeGraphCombo().getTimeGraphViewer().getFollowArrowBwdAction());
107 manager
.add(getTimeGraphCombo().getTimeGraphViewer().getFollowArrowFwdAction());
111 protected String
getNextText() {
112 return Messages
.ControlFlowView_nextProcessActionNameText
;
116 protected String
getNextTooltip() {
117 return Messages
.ControlFlowView_nextProcessActionToolTipText
;
121 protected String
getPrevText() {
122 return Messages
.ControlFlowView_previousProcessActionNameText
;
126 protected String
getPrevTooltip() {
127 return Messages
.ControlFlowView_previousProcessActionToolTipText
;
130 private static class ControlFlowEntryComparator
implements Comparator
<ITimeGraphEntry
> {
133 public int compare(ITimeGraphEntry o1
, ITimeGraphEntry o2
) {
137 if ((o1
instanceof ControlFlowEntry
) && (o2
instanceof ControlFlowEntry
)) {
138 ControlFlowEntry entry1
= (ControlFlowEntry
) o1
;
139 ControlFlowEntry entry2
= (ControlFlowEntry
) o2
;
140 result
= entry1
.getTrace().getStartTime().compareTo(entry2
.getTrace().getStartTime());
142 result
= entry1
.getTrace().getName().compareTo(entry2
.getTrace().getName());
145 result
= entry1
.getThreadId() < entry2
.getThreadId() ?
-1 : entry1
.getThreadId() > entry2
.getThreadId() ?
1 : 0;
150 result
= o1
.getStartTime() < o2
.getStartTime() ?
-1 : o1
.getStartTime() > o2
.getStartTime() ?
1 : 0;
161 protected static class ControlFlowTreeLabelProvider
extends TreeLabelProvider
{
164 public String
getColumnText(Object element
, int columnIndex
) {
165 ControlFlowEntry entry
= (ControlFlowEntry
) element
;
167 if (COLUMN_NAMES
[columnIndex
].equals(Messages
.ControlFlowView_processColumn
)) {
168 return entry
.getName();
169 } else if (COLUMN_NAMES
[columnIndex
].equals(Messages
.ControlFlowView_tidColumn
)) {
170 return Integer
.toString(entry
.getThreadId());
171 } else if (COLUMN_NAMES
[columnIndex
].equals(Messages
.ControlFlowView_ptidColumn
)) {
172 if (entry
.getParentThreadId() > 0) {
173 return Integer
.toString(entry
.getParentThreadId());
175 } else if (COLUMN_NAMES
[columnIndex
].equals(Messages
.ControlFlowView_birthTimeColumn
)) {
176 return Utils
.formatTime(entry
.getStartTime(), TimeFormat
.CALENDAR
, Resolution
.NANOSEC
);
177 } else if (COLUMN_NAMES
[columnIndex
].equals(Messages
.ControlFlowView_traceColumn
)) {
178 return entry
.getTrace().getName();
180 return ""; //$NON-NLS-1$
185 // ------------------------------------------------------------------------
187 // ------------------------------------------------------------------------
190 protected void buildEventList(final ITmfTrace trace
, IProgressMonitor monitor
) {
191 setStartTime(Long
.MAX_VALUE
);
192 setEndTime(Long
.MIN_VALUE
);
194 ArrayList
<TimeGraphEntry
> rootList
= new ArrayList
<TimeGraphEntry
>();
195 for (ITmfTrace aTrace
: fTraceManager
.getActiveTraceSet()) {
196 if (monitor
.isCanceled()) {
199 if (aTrace
instanceof LttngKernelTrace
) {
200 ArrayList
<TimeGraphEntry
> entryList
= new ArrayList
<TimeGraphEntry
>();
201 LttngKernelTrace ctfKernelTrace
= (LttngKernelTrace
) aTrace
;
202 ITmfStateSystem ssq
= ctfKernelTrace
.getStateSystems().get(LttngKernelTrace
.STATE_ID
);
203 if (!ssq
.waitUntilBuilt()) {
206 long start
= ssq
.getStartTime();
207 long end
= ssq
.getCurrentEndTime() + 1;
208 setStartTime(Math
.min(getStartTime(), start
));
209 setEndTime(Math
.max(getEndTime(), end
));
210 List
<Integer
> threadQuarks
= ssq
.getQuarks(Attributes
.THREADS
, "*"); //$NON-NLS-1$
211 for (int threadQuark
: threadQuarks
) {
212 if (monitor
.isCanceled()) {
215 String threadName
= ssq
.getAttributeName(threadQuark
);
218 threadId
= Integer
.parseInt(threadName
);
219 } catch (NumberFormatException e1
) {
222 if (threadId
== 0) { // ignore the swapper thread
225 int execNameQuark
= -1;
228 execNameQuark
= ssq
.getQuarkRelative(threadQuark
, Attributes
.EXEC_NAME
);
229 } catch (AttributeNotFoundException e
) {
232 int ppidQuark
= ssq
.getQuarkRelative(threadQuark
, Attributes
.PPID
);
233 List
<ITmfStateInterval
> execNameIntervals
= ssq
.queryHistoryRange(execNameQuark
, start
, end
- 1);
234 // use monitor when available in api
235 if (monitor
.isCanceled()) {
238 TimeGraphEntry entry
= null;
239 for (ITmfStateInterval execNameInterval
: execNameIntervals
) {
240 if (monitor
.isCanceled()) {
243 if (!execNameInterval
.getStateValue().isNull() &&
244 execNameInterval
.getStateValue().getType() == ITmfStateValue
.Type
.STRING
) {
245 String execName
= execNameInterval
.getStateValue().unboxStr();
246 long startTime
= execNameInterval
.getStartTime();
247 long endTime
= execNameInterval
.getEndTime() + 1;
249 if (ppidQuark
!= -1) {
250 ITmfStateInterval ppidInterval
= ssq
.querySingleState(startTime
, ppidQuark
);
251 ppid
= ppidInterval
.getStateValue().unboxInt();
254 entry
= new ControlFlowEntry(threadQuark
, ctfKernelTrace
, execName
, threadId
, ppid
, startTime
, endTime
);
255 entryList
.add(entry
);
257 // update the name of the entry to the
259 entry
.setName(execName
);
261 entry
.addEvent(new TimeEvent(entry
, startTime
, endTime
- startTime
));
266 } catch (AttributeNotFoundException e
) {
268 } catch (TimeRangeException e
) {
270 } catch (StateValueTypeException e
) {
272 } catch (StateSystemDisposedException e
) {
276 buildTree(entryList
, rootList
);
278 Collections
.sort(rootList
, getEntryComparator());
279 putEntryList(trace
, (ArrayList
<TimeGraphEntry
>) rootList
.clone());
281 if (trace
.equals(getTrace())) {
285 for (TimeGraphEntry entry
: rootList
) {
286 if (monitor
.isCanceled()) {
289 buildStatusEvents(trace
, entry
, monitor
);
293 private static void buildTree(ArrayList
<TimeGraphEntry
> entryList
,
294 ArrayList
<TimeGraphEntry
> rootList
) {
295 for (TimeGraphEntry listentry
: entryList
) {
296 ControlFlowEntry entry
= (ControlFlowEntry
) listentry
;
298 if (entry
.getParentThreadId() > 0) {
299 for (TimeGraphEntry parententry
: entryList
) {
300 ControlFlowEntry parent
= (ControlFlowEntry
) parententry
;
301 if (parent
.getThreadId() == entry
.getParentThreadId() &&
302 entry
.getStartTime() >= parent
.getStartTime() &&
303 entry
.getStartTime() <= parent
.getEndTime()) {
304 parent
.addChild(entry
);
316 private void buildStatusEvents(ITmfTrace trace
, TimeGraphEntry entry
, IProgressMonitor monitor
) {
317 ITmfStateSystem ssq
= entry
.getTrace().getStateSystems().get(LttngKernelTrace
.STATE_ID
);
319 long start
= ssq
.getStartTime();
320 long end
= ssq
.getCurrentEndTime() + 1;
321 long resolution
= Math
.max(1, (end
- start
) / getDisplayWidth());
322 List
<ITimeEvent
> eventList
= getEventList(entry
, entry
.getStartTime(), entry
.getEndTime(), resolution
, monitor
);
323 if (monitor
.isCanceled()) {
326 entry
.setEventList(eventList
);
327 if (trace
.equals(getTrace())) {
330 for (ITimeGraphEntry child
: entry
.getChildren()) {
331 if (monitor
.isCanceled()) {
334 buildStatusEvents(trace
, (TimeGraphEntry
) child
, monitor
);
339 protected List
<ITimeEvent
> getEventList(TimeGraphEntry tgentry
, long startTime
, long endTime
, long resolution
, IProgressMonitor monitor
) {
340 List
<ITimeEvent
> eventList
= null;
341 if (!(tgentry
instanceof ControlFlowEntry
)) {
344 ControlFlowEntry entry
= (ControlFlowEntry
) tgentry
;
345 final long realStart
= Math
.max(startTime
, entry
.getStartTime());
346 final long realEnd
= Math
.min(endTime
, entry
.getEndTime());
347 if (realEnd
<= realStart
) {
350 ITmfStateSystem ssq
= entry
.getTrace().getStateSystems().get(LttngKernelTrace
.STATE_ID
);
352 int statusQuark
= ssq
.getQuarkRelative(entry
.getThreadQuark(), Attributes
.STATUS
);
353 List
<ITmfStateInterval
> statusIntervals
= ssq
.queryHistoryRange(statusQuark
, realStart
, realEnd
- 1, resolution
, monitor
);
354 eventList
= new ArrayList
<ITimeEvent
>(statusIntervals
.size());
355 long lastEndTime
= -1;
356 for (ITmfStateInterval statusInterval
: statusIntervals
) {
357 if (monitor
.isCanceled()) {
360 long time
= statusInterval
.getStartTime();
361 long duration
= statusInterval
.getEndTime() - time
+ 1;
364 status
= statusInterval
.getStateValue().unboxInt();
365 } catch (StateValueTypeException e
) {
368 if (lastEndTime
!= time
&& lastEndTime
!= -1) {
369 eventList
.add(new TimeEvent(entry
, lastEndTime
, time
- lastEndTime
));
371 eventList
.add(new TimeEvent(entry
, time
, duration
, status
));
372 lastEndTime
= time
+ duration
;
374 } catch (AttributeNotFoundException e
) {
376 } catch (TimeRangeException e
) {
378 } catch (StateSystemDisposedException e
) {
385 * Returns a value corresponding to the selected entry.
387 * Used in conjunction with selectEntry to change the selected entry. If one
388 * of these methods is overridden in child class, then both should be.
391 * The currently selected time
392 * @return a value identifying the entry
394 private int getSelectionValue(long time
) {
396 for (ITmfTrace trace
: fTraceManager
.getActiveTraceSet()) {
400 if (trace
instanceof LttngKernelTrace
) {
401 LttngKernelTrace ctfKernelTrace
= (LttngKernelTrace
) trace
;
402 ITmfStateSystem ssq
= ctfKernelTrace
.getStateSystems().get(LttngKernelTrace
.STATE_ID
);
403 if (time
>= ssq
.getStartTime() && time
<= ssq
.getCurrentEndTime()) {
404 List
<Integer
> currentThreadQuarks
= ssq
.getQuarks(Attributes
.CPUS
, "*", Attributes
.CURRENT_THREAD
); //$NON-NLS-1$
405 for (int currentThreadQuark
: currentThreadQuarks
) {
407 ITmfStateInterval currentThreadInterval
= ssq
.querySingleState(time
, currentThreadQuark
);
408 int currentThread
= currentThreadInterval
.getStateValue().unboxInt();
409 if (currentThread
> 0) {
410 int statusQuark
= ssq
.getQuarkAbsolute(Attributes
.THREADS
, Integer
.toString(currentThread
), Attributes
.STATUS
);
411 ITmfStateInterval statusInterval
= ssq
.querySingleState(time
, statusQuark
);
412 if (statusInterval
.getStartTime() == time
) {
413 thread
= currentThread
;
417 } catch (AttributeNotFoundException e
) {
419 } catch (TimeRangeException e
) {
421 } catch (StateValueTypeException e
) {
423 } catch (StateSystemDisposedException e
) {
434 protected void synchingToTime(long time
) {
435 int selected
= getSelectionValue(time
);
437 for (Object element
: getTimeGraphViewer().getExpandedElements()) {
438 if (element
instanceof ControlFlowEntry
) {
439 ControlFlowEntry entry
= (ControlFlowEntry
) element
;
440 if (entry
.getThreadId() == selected
) {
441 getTimeGraphCombo().setSelection(entry
);
450 protected List
<ILinkEvent
> getLinkList(long startTime
, long endTime
, long resolution
, IProgressMonitor monitor
) {
451 List
<ILinkEvent
> list
= new ArrayList
<ILinkEvent
>();
452 ITmfTrace
[] traces
= TmfTraceManager
.getTraceSet(getTrace());
453 List
<TimeGraphEntry
> entryList
= getEntryListMap().get(getTrace());
454 if (traces
== null || entryList
== null) {
457 for (ITmfTrace trace
: traces
) {
458 if (trace
instanceof LttngKernelTrace
) {
459 ITmfStateSystem ssq
= trace
.getStateSystems().get(LttngKernelTrace
.STATE_ID
);
461 long start
= Math
.max(startTime
, ssq
.getStartTime());
462 long end
= Math
.min(endTime
, ssq
.getCurrentEndTime());
466 List
<Integer
> currentThreadQuarks
= ssq
.getQuarks(Attributes
.CPUS
, "*", Attributes
.CURRENT_THREAD
); //$NON-NLS-1$
467 for (int currentThreadQuark
: currentThreadQuarks
) {
468 List
<ITmfStateInterval
> currentThreadIntervals
= ssq
.queryHistoryRange(currentThreadQuark
, start
, end
, resolution
, monitor
);
471 for (ITmfStateInterval currentThreadInterval
: currentThreadIntervals
) {
472 if (monitor
.isCanceled()) {
475 long time
= currentThreadInterval
.getStartTime();
476 int thread
= currentThreadInterval
.getStateValue().unboxInt();
477 if (thread
> 0 && prevThread
> 0 && thread
!= prevThread
&& time
== prevEnd
) {
478 ITimeGraphEntry prevEntry
= findEntry(entryList
, trace
, prevThread
);
479 ITimeGraphEntry nextEntry
= findEntry(entryList
, trace
, thread
);
480 list
.add(new TimeLinkEvent(prevEntry
, nextEntry
, time
, 0, 0));
483 prevEnd
= currentThreadInterval
.getEndTime() + 1;
486 } catch (TimeRangeException e
) {
488 } catch (AttributeNotFoundException e
) {
490 } catch (StateValueTypeException e
) {
492 } catch (StateSystemDisposedException e
) {
500 private ControlFlowEntry
findEntry(List
<TimeGraphEntry
> entryList
, ITmfTrace trace
, int threadId
) {
501 for (TimeGraphEntry entry
: entryList
) {
502 if (entry
instanceof ControlFlowEntry
) {
503 ControlFlowEntry controlFlowEntry
= (ControlFlowEntry
) entry
;
504 if (controlFlowEntry
.getThreadId() == threadId
&& controlFlowEntry
.getTrace() == trace
) {
505 return controlFlowEntry
;
506 } else if (entry
.hasChildren()) {
507 controlFlowEntry
= findEntry(entry
.getChildren(), trace
, threadId
);
508 if (controlFlowEntry
!= null) {
509 return controlFlowEntry
;