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
.linuxtools
.internal
.lttng2
.kernel
.core
.Attributes
;
23 import org
.eclipse
.linuxtools
.internal
.lttng2
.kernel
.ui
.Messages
;
24 import org
.eclipse
.linuxtools
.lttng2
.kernel
.core
.trace
.LttngKernelTrace
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.AttributeNotFoundException
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateSystemDisposedException
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateValueTypeException
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TimeRangeException
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.interval
.ITmfStateInterval
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.statesystem
.ITmfStateSystem
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.statevalue
.ITmfStateValue
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
33 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.timegraph
.AbstractTimeGraphView
;
34 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
35 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
36 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.TimeEvent
;
37 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.TimeGraphEntry
;
38 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
;
39 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.Resolution
;
40 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.TimeFormat
;
43 * The Control Flow view main object
46 public class ControlFlowView
extends AbstractTimeGraphView
{
48 // ------------------------------------------------------------------------
50 // ------------------------------------------------------------------------
55 public static final String ID
= "org.eclipse.linuxtools.lttng2.kernel.ui.views.controlflow"; //$NON-NLS-1$
57 private static final String PROCESS_COLUMN
= Messages
.ControlFlowView_processColumn
;
58 private static final String TID_COLUMN
= Messages
.ControlFlowView_tidColumn
;
59 private static final String PTID_COLUMN
= Messages
.ControlFlowView_ptidColumn
;
60 private static final String BIRTH_TIME_COLUMN
= Messages
.ControlFlowView_birthTimeColumn
;
61 private static final String TRACE_COLUMN
= Messages
.ControlFlowView_traceColumn
;
63 private static final String
[] COLUMN_NAMES
= new String
[] {
71 private static final String
[] FILTER_COLUMN_NAMES
= new String
[] {
76 // ------------------------------------------------------------------------
78 // ------------------------------------------------------------------------
83 public ControlFlowView() {
84 super(ID
, COLUMN_NAMES
, FILTER_COLUMN_NAMES
, new ControlFlowPresentationProvider());
85 setTreeLabelProvider(new ControlFlowTreeLabelProvider());
86 setEntryComparator(new ControlFlowEntryComparator());
90 protected String
getNextText() {
91 return Messages
.ControlFlowView_nextProcessActionNameText
;
95 protected String
getNextTooltip() {
96 return Messages
.ControlFlowView_nextProcessActionToolTipText
;
100 protected String
getPrevText() {
101 return Messages
.ControlFlowView_previousProcessActionNameText
;
105 protected String
getPrevTooltip() {
106 return Messages
.ControlFlowView_previousProcessActionToolTipText
;
109 private static class ControlFlowEntryComparator
implements Comparator
<ITimeGraphEntry
> {
112 public int compare(ITimeGraphEntry o1
, ITimeGraphEntry o2
) {
116 if ((o1
instanceof ControlFlowEntry
) && (o2
instanceof ControlFlowEntry
)) {
117 ControlFlowEntry entry1
= (ControlFlowEntry
) o1
;
118 ControlFlowEntry entry2
= (ControlFlowEntry
) o2
;
119 result
= entry1
.getTrace().getStartTime().compareTo(entry2
.getTrace().getStartTime());
121 result
= entry1
.getTrace().getName().compareTo(entry2
.getTrace().getName());
124 result
= entry1
.getThreadId() < entry2
.getThreadId() ?
-1 : entry1
.getThreadId() > entry2
.getThreadId() ?
1 : 0;
129 result
= o1
.getStartTime() < o2
.getStartTime() ?
-1 : o1
.getStartTime() > o2
.getStartTime() ?
1 : 0;
140 protected static class ControlFlowTreeLabelProvider
extends TreeLabelProvider
{
143 public String
getColumnText(Object element
, int columnIndex
) {
144 ControlFlowEntry entry
= (ControlFlowEntry
) element
;
146 if (COLUMN_NAMES
[columnIndex
].equals(Messages
.ControlFlowView_processColumn
)) {
147 return entry
.getName();
148 } else if (COLUMN_NAMES
[columnIndex
].equals(Messages
.ControlFlowView_tidColumn
)) {
149 return Integer
.toString(entry
.getThreadId());
150 } else if (COLUMN_NAMES
[columnIndex
].equals(Messages
.ControlFlowView_ptidColumn
)) {
151 if (entry
.getParentThreadId() > 0) {
152 return Integer
.toString(entry
.getParentThreadId());
154 } else if (COLUMN_NAMES
[columnIndex
].equals(Messages
.ControlFlowView_birthTimeColumn
)) {
155 return Utils
.formatTime(entry
.getStartTime(), TimeFormat
.CALENDAR
, Resolution
.NANOSEC
);
156 } else if (COLUMN_NAMES
[columnIndex
].equals(Messages
.ControlFlowView_traceColumn
)) {
157 return entry
.getTrace().getName();
159 return ""; //$NON-NLS-1$
164 // ------------------------------------------------------------------------
166 // ------------------------------------------------------------------------
169 protected void buildEventList(final ITmfTrace trace
, IProgressMonitor monitor
) {
170 setStartTime(Long
.MAX_VALUE
);
171 setEndTime(Long
.MIN_VALUE
);
173 ArrayList
<TimeGraphEntry
> rootList
= new ArrayList
<TimeGraphEntry
>();
174 for (ITmfTrace aTrace
: fTraceManager
.getActiveTraceSet()) {
175 if (monitor
.isCanceled()) {
178 if (aTrace
instanceof LttngKernelTrace
) {
179 ArrayList
<TimeGraphEntry
> entryList
= new ArrayList
<TimeGraphEntry
>();
180 LttngKernelTrace ctfKernelTrace
= (LttngKernelTrace
) aTrace
;
181 ITmfStateSystem ssq
= ctfKernelTrace
.getStateSystems().get(LttngKernelTrace
.STATE_ID
);
182 if (!ssq
.waitUntilBuilt()) {
185 long start
= ssq
.getStartTime();
186 long end
= ssq
.getCurrentEndTime() + 1;
187 setStartTime(Math
.min(getStartTime(), start
));
188 setEndTime(Math
.max(getEndTime(), end
));
189 List
<Integer
> threadQuarks
= ssq
.getQuarks(Attributes
.THREADS
, "*"); //$NON-NLS-1$
190 for (int threadQuark
: threadQuarks
) {
191 if (monitor
.isCanceled()) {
194 String threadName
= ssq
.getAttributeName(threadQuark
);
197 threadId
= Integer
.parseInt(threadName
);
198 } catch (NumberFormatException e1
) {
201 if (threadId
== 0) { // ignore the swapper thread
204 int execNameQuark
= -1;
207 execNameQuark
= ssq
.getQuarkRelative(threadQuark
, Attributes
.EXEC_NAME
);
208 } catch (AttributeNotFoundException e
) {
211 int ppidQuark
= ssq
.getQuarkRelative(threadQuark
, Attributes
.PPID
);
212 List
<ITmfStateInterval
> execNameIntervals
= ssq
.queryHistoryRange(execNameQuark
, start
, end
- 1);
213 // use monitor when available in api
214 if (monitor
.isCanceled()) {
217 TimeGraphEntry entry
= null;
218 for (ITmfStateInterval execNameInterval
: execNameIntervals
) {
219 if (monitor
.isCanceled()) {
222 if (!execNameInterval
.getStateValue().isNull() &&
223 execNameInterval
.getStateValue().getType() == ITmfStateValue
.Type
.STRING
) {
224 String execName
= execNameInterval
.getStateValue().unboxStr();
225 long startTime
= execNameInterval
.getStartTime();
226 long endTime
= execNameInterval
.getEndTime() + 1;
228 if (ppidQuark
!= -1) {
229 ITmfStateInterval ppidInterval
= ssq
.querySingleState(startTime
, ppidQuark
);
230 ppid
= ppidInterval
.getStateValue().unboxInt();
233 entry
= new ControlFlowEntry(threadQuark
, ctfKernelTrace
, execName
, threadId
, ppid
, startTime
, endTime
);
234 entryList
.add(entry
);
236 // update the name of the entry to the
238 entry
.setName(execName
);
240 entry
.addEvent(new TimeEvent(entry
, startTime
, endTime
- startTime
));
245 } catch (AttributeNotFoundException e
) {
247 } catch (TimeRangeException e
) {
249 } catch (StateValueTypeException e
) {
251 } catch (StateSystemDisposedException e
) {
255 buildTree(entryList
, rootList
);
257 Collections
.sort(rootList
, getEntryComparator());
258 putEntryList(trace
, (ArrayList
<TimeGraphEntry
>) rootList
.clone());
260 if (trace
.equals(getTrace())) {
264 for (TimeGraphEntry entry
: rootList
) {
265 if (monitor
.isCanceled()) {
268 buildStatusEvents(trace
, entry
, monitor
);
272 private static void buildTree(ArrayList
<TimeGraphEntry
> entryList
,
273 ArrayList
<TimeGraphEntry
> rootList
) {
274 for (TimeGraphEntry listentry
: entryList
) {
275 ControlFlowEntry entry
= (ControlFlowEntry
) listentry
;
277 if (entry
.getParentThreadId() > 0) {
278 for (TimeGraphEntry parententry
: entryList
) {
279 ControlFlowEntry parent
= (ControlFlowEntry
) parententry
;
280 if (parent
.getThreadId() == entry
.getParentThreadId() &&
281 entry
.getStartTime() >= parent
.getStartTime() &&
282 entry
.getStartTime() <= parent
.getEndTime()) {
283 parent
.addChild(entry
);
295 private void buildStatusEvents(ITmfTrace trace
, TimeGraphEntry entry
, IProgressMonitor monitor
) {
296 ITmfStateSystem ssq
= entry
.getTrace().getStateSystems().get(LttngKernelTrace
.STATE_ID
);
298 long start
= ssq
.getStartTime();
299 long end
= ssq
.getCurrentEndTime() + 1;
300 long resolution
= Math
.max(1, (end
- start
) / getDisplayWidth());
301 List
<ITimeEvent
> eventList
= getEventList(entry
, entry
.getStartTime(), entry
.getEndTime(), resolution
, monitor
);
302 if (monitor
.isCanceled()) {
305 entry
.setEventList(eventList
);
306 if (trace
.equals(getTrace())) {
309 for (ITimeGraphEntry child
: entry
.getChildren()) {
310 if (monitor
.isCanceled()) {
313 buildStatusEvents(trace
, (TimeGraphEntry
) child
, monitor
);
318 protected List
<ITimeEvent
> getEventList(TimeGraphEntry tgentry
, long startTime
, long endTime
, long resolution
, IProgressMonitor monitor
) {
319 List
<ITimeEvent
> eventList
= null;
320 if (!(tgentry
instanceof ControlFlowEntry
)) {
323 ControlFlowEntry entry
= (ControlFlowEntry
) tgentry
;
324 final long realStart
= Math
.max(startTime
, entry
.getStartTime());
325 final long realEnd
= Math
.min(endTime
, entry
.getEndTime());
326 if (realEnd
<= realStart
) {
329 ITmfStateSystem ssq
= entry
.getTrace().getStateSystems().get(LttngKernelTrace
.STATE_ID
);
331 int statusQuark
= ssq
.getQuarkRelative(entry
.getThreadQuark(), Attributes
.STATUS
);
332 List
<ITmfStateInterval
> statusIntervals
= ssq
.queryHistoryRange(statusQuark
, realStart
, realEnd
- 1, resolution
, monitor
);
333 eventList
= new ArrayList
<ITimeEvent
>(statusIntervals
.size());
334 long lastEndTime
= -1;
335 for (ITmfStateInterval statusInterval
: statusIntervals
) {
336 if (monitor
.isCanceled()) {
339 long time
= statusInterval
.getStartTime();
340 long duration
= statusInterval
.getEndTime() - time
+ 1;
343 status
= statusInterval
.getStateValue().unboxInt();
344 } catch (StateValueTypeException e
) {
347 if (lastEndTime
!= time
&& lastEndTime
!= -1) {
348 eventList
.add(new TimeEvent(entry
, lastEndTime
, time
- lastEndTime
));
350 eventList
.add(new TimeEvent(entry
, time
, duration
, status
));
351 lastEndTime
= time
+ duration
;
353 } catch (AttributeNotFoundException e
) {
355 } catch (TimeRangeException e
) {
357 } catch (StateSystemDisposedException e
) {
364 * Returns a value corresponding to the selected entry.
366 * Used in conjunction with selectEntry to change the selected entry. If one
367 * of these methods is overridden in child class, then both should be.
370 * The currently selected time
371 * @return a value identifying the entry
373 private int getSelectionValue(long time
) {
375 for (ITmfTrace trace
: fTraceManager
.getActiveTraceSet()) {
379 if (trace
instanceof LttngKernelTrace
) {
380 LttngKernelTrace ctfKernelTrace
= (LttngKernelTrace
) trace
;
381 ITmfStateSystem ssq
= ctfKernelTrace
.getStateSystems().get(LttngKernelTrace
.STATE_ID
);
382 if (time
>= ssq
.getStartTime() && time
<= ssq
.getCurrentEndTime()) {
383 List
<Integer
> currentThreadQuarks
= ssq
.getQuarks(Attributes
.CPUS
, "*", Attributes
.CURRENT_THREAD
); //$NON-NLS-1$
384 for (int currentThreadQuark
: currentThreadQuarks
) {
386 ITmfStateInterval currentThreadInterval
= ssq
.querySingleState(time
, currentThreadQuark
);
387 int currentThread
= currentThreadInterval
.getStateValue().unboxInt();
388 if (currentThread
> 0) {
389 int statusQuark
= ssq
.getQuarkAbsolute(Attributes
.THREADS
, Integer
.toString(currentThread
), Attributes
.STATUS
);
390 ITmfStateInterval statusInterval
= ssq
.querySingleState(time
, statusQuark
);
391 if (statusInterval
.getStartTime() == time
) {
392 thread
= currentThread
;
396 } catch (AttributeNotFoundException e
) {
398 } catch (TimeRangeException e
) {
400 } catch (StateValueTypeException e
) {
402 } catch (StateSystemDisposedException e
) {
413 protected void synchingToTime(long time
) {
414 int selected
= getSelectionValue(time
);
416 for (Object element
: getTimeGraphCombo().getTimeGraphViewer().getExpandedElements()) {
417 if (element
instanceof ControlFlowEntry
) {
418 ControlFlowEntry entry
= (ControlFlowEntry
) element
;
419 if (entry
.getThreadId() == selected
) {
420 getTimeGraphCombo().setSelection(entry
);