1 /*******************************************************************************
2 * Copyright (c) 2012, 2015 Ericsson, École Polytechnique de Montréal and others.
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 * Christian Mansky - Add check active / uncheck inactive buttons
13 *******************************************************************************/
15 package org
.eclipse
.tracecompass
.analysis
.os
.linux
.ui
.views
.controlflow
;
17 import java
.util
.ArrayList
;
18 import java
.util
.Comparator
;
19 import java
.util
.HashMap
;
20 import java
.util
.List
;
23 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
24 import org
.eclipse
.jdt
.annotation
.NonNull
;
25 import org
.eclipse
.jdt
.annotation
.Nullable
;
26 import org
.eclipse
.jface
.action
.IAction
;
27 import org
.eclipse
.jface
.action
.IToolBarManager
;
28 import org
.eclipse
.jface
.action
.MenuManager
;
29 import org
.eclipse
.jface
.dialogs
.IDialogSettings
;
30 import org
.eclipse
.jface
.viewers
.TreeViewer
;
31 import org
.eclipse
.swt
.events
.MenuDetectEvent
;
32 import org
.eclipse
.swt
.events
.MenuDetectListener
;
33 import org
.eclipse
.swt
.graphics
.Point
;
34 import org
.eclipse
.swt
.widgets
.Composite
;
35 import org
.eclipse
.swt
.widgets
.Control
;
36 import org
.eclipse
.swt
.widgets
.Menu
;
37 import org
.eclipse
.swt
.widgets
.TreeItem
;
38 import org
.eclipse
.tracecompass
.analysis
.os
.linux
.core
.kernel
.Attributes
;
39 import org
.eclipse
.tracecompass
.analysis
.os
.linux
.core
.kernel
.KernelAnalysisModule
;
40 import org
.eclipse
.tracecompass
.internal
.analysis
.os
.linux
.ui
.Activator
;
41 import org
.eclipse
.tracecompass
.internal
.analysis
.os
.linux
.ui
.Messages
;
42 import org
.eclipse
.tracecompass
.internal
.analysis
.os
.linux
.ui
.actions
.FollowThreadAction
;
43 import org
.eclipse
.tracecompass
.internal
.analysis
.os
.linux
.ui
.views
.controlflow
.ControlFlowColumnComparators
;
44 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystem
;
45 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
46 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateSystemDisposedException
;
47 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateValueTypeException
;
48 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.TimeRangeException
;
49 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
50 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
51 import org
.eclipse
.tracecompass
.tmf
.core
.statesystem
.TmfStateSystemAnalysisModule
;
52 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
53 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceManager
;
54 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.timegraph
.AbstractStateSystemTimeGraphView
;
55 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphCombo
;
56 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ILinkEvent
;
57 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
58 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
59 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.NullTimeEvent
;
60 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.TimeEvent
;
61 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.TimeGraphEntry
;
62 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.TimeLinkEvent
;
63 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
;
64 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.Resolution
;
65 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.TimeFormat
;
67 import com
.google
.common
.collect
.ImmutableList
;
70 * The Control Flow view main object
73 public class ControlFlowView
extends AbstractStateSystemTimeGraphView
{
75 // ------------------------------------------------------------------------
77 // ------------------------------------------------------------------------
81 public static final String ID
= "org.eclipse.tracecompass.analysis.os.linux.views.controlflow"; //$NON-NLS-1$
83 private static final String PROCESS_COLUMN
= Messages
.ControlFlowView_processColumn
;
84 private static final String TID_COLUMN
= Messages
.ControlFlowView_tidColumn
;
85 private static final String PTID_COLUMN
= Messages
.ControlFlowView_ptidColumn
;
86 private static final String BIRTH_TIME_COLUMN
= Messages
.ControlFlowView_birthTimeColumn
;
87 private static final String TRACE_COLUMN
= Messages
.ControlFlowView_traceColumn
;
89 private static final String
[] COLUMN_NAMES
= new String
[] {
97 private static final String
[] FILTER_COLUMN_NAMES
= new String
[] {
102 // Timeout between updates in the build thread in ms
103 private static final long BUILD_UPDATE_TIMEOUT
= 500;
105 private static final Comparator
<ITimeGraphEntry
>[] COLUMN_COMPARATORS
;
107 private static final int INITIAL_SORT_COLUMN_INDEX
= 3;
110 ImmutableList
.Builder
<Comparator
<ITimeGraphEntry
>> builder
= ImmutableList
.builder();
111 builder
.add(ControlFlowColumnComparators
.PROCESS_NAME_COLUMN_COMPARATOR
)
112 .add(ControlFlowColumnComparators
.TID_COLUMN_COMPARATOR
)
113 .add(ControlFlowColumnComparators
.PTID_COLUMN_COMPARATOR
)
114 .add(ControlFlowColumnComparators
.BIRTH_TIME_COLUMN_COMPARATOR
)
115 .add(ControlFlowColumnComparators
.TRACE_COLUMN_COMPARATOR
);
116 List
<Comparator
<ITimeGraphEntry
>> l
= builder
.build();
117 COLUMN_COMPARATORS
= l
.toArray(new Comparator
[l
.size()]);
120 private MenuManager fMenuMgr
;
122 // ------------------------------------------------------------------------
124 // ------------------------------------------------------------------------
129 public ControlFlowView() {
130 super(ID
, new ControlFlowPresentationProvider());
131 setTreeColumns(COLUMN_NAMES
, COLUMN_COMPARATORS
, INITIAL_SORT_COLUMN_INDEX
);
132 setTreeLabelProvider(new ControlFlowTreeLabelProvider());
133 setFilterColumns(FILTER_COLUMN_NAMES
);
134 setFilterLabelProvider(new ControlFlowFilterLabelProvider());
135 setEntryComparator(ControlFlowColumnComparators
.BIRTH_TIME_COLUMN_COMPARATOR
);
139 public void createPartControl(Composite parent
) {
140 super.createPartControl(parent
);
141 // add "Check active" Button to TimeGraphFilterDialog
142 super.getTimeGraphCombo().addTimeGraphFilterCheckActiveButton(
143 new ControlFlowCheckActiveProvider(Messages
.ControlFlowView_checkActiveLabel
, Messages
.ControlFlowView_checkActiveToolTip
));
144 // add "Uncheck inactive" Button to TimeGraphFilterDialog
145 super.getTimeGraphCombo().addTimeGraphFilterUncheckInactiveButton(
146 new ControlFlowCheckActiveProvider(Messages
.ControlFlowView_uncheckInactiveLabel
, Messages
.ControlFlowView_uncheckInactiveToolTip
));
150 private void createContextMenu() {
151 fMenuMgr
= new MenuManager();
152 final TimeGraphCombo timeGraphCombo
= getTimeGraphCombo();
153 TreeViewer treeViewer
= timeGraphCombo
.getTreeViewer();
154 Control control
= treeViewer
.getControl();
155 Menu menu
= fMenuMgr
.createContextMenu(control
);
156 control
.setMenu(menu
);
157 control
.addMenuDetectListener(new MenuDetectListener() {
159 public void menuDetected(MenuDetectEvent event
) {
160 fMenuMgr
.removeAll();
161 Point point
= control
.toControl(event
.x
, event
.y
);
162 // this is super important, it makes zoom still work. Do not try
163 // to extend to the time graph area.
164 TreeItem item
= treeViewer
.getTree().getItem(point
);
166 if (item
.getData() instanceof ControlFlowEntry
) {
167 ControlFlowEntry entry
= (ControlFlowEntry
) item
.getData();
168 fMenuMgr
.add(new FollowThreadAction(ControlFlowView
.this, entry
.getName(), entry
.getThreadId(), entry
.getTrace()));
176 protected void fillLocalToolBar(IToolBarManager manager
) {
177 super.fillLocalToolBar(manager
);
178 IDialogSettings settings
= Activator
.getDefault().getDialogSettings();
179 IDialogSettings section
= settings
.getSection(getClass().getName());
180 if (section
== null) {
181 section
= settings
.addNewSection(getClass().getName());
184 IAction hideArrowsAction
= getTimeGraphCombo().getTimeGraphViewer().getHideArrowsAction(section
);
185 manager
.add(hideArrowsAction
);
187 IAction followArrowBwdAction
= getTimeGraphCombo().getTimeGraphViewer().getFollowArrowBwdAction();
188 followArrowBwdAction
.setText(Messages
.ControlFlowView_followCPUBwdText
);
189 followArrowBwdAction
.setToolTipText(Messages
.ControlFlowView_followCPUBwdText
);
190 manager
.add(followArrowBwdAction
);
192 IAction followArrowFwdAction
= getTimeGraphCombo().getTimeGraphViewer().getFollowArrowFwdAction();
193 followArrowFwdAction
.setText(Messages
.ControlFlowView_followCPUFwdText
);
194 followArrowFwdAction
.setToolTipText(Messages
.ControlFlowView_followCPUFwdText
);
195 manager
.add(followArrowFwdAction
);
199 protected String
getNextText() {
200 return Messages
.ControlFlowView_nextProcessActionNameText
;
204 protected String
getNextTooltip() {
205 return Messages
.ControlFlowView_nextProcessActionToolTipText
;
209 protected String
getPrevText() {
210 return Messages
.ControlFlowView_previousProcessActionNameText
;
214 protected String
getPrevTooltip() {
215 return Messages
.ControlFlowView_previousProcessActionToolTipText
;
222 protected static class ControlFlowTreeLabelProvider
extends TreeLabelProvider
{
225 public String
getColumnText(Object element
, int columnIndex
) {
226 ControlFlowEntry entry
= (ControlFlowEntry
) element
;
228 if (COLUMN_NAMES
[columnIndex
].equals(Messages
.ControlFlowView_processColumn
)) {
229 return entry
.getName();
230 } else if (COLUMN_NAMES
[columnIndex
].equals(Messages
.ControlFlowView_tidColumn
)) {
231 return Integer
.toString(entry
.getThreadId());
232 } else if (COLUMN_NAMES
[columnIndex
].equals(Messages
.ControlFlowView_ptidColumn
)) {
233 if (entry
.getParentThreadId() > 0) {
234 return Integer
.toString(entry
.getParentThreadId());
236 } else if (COLUMN_NAMES
[columnIndex
].equals(Messages
.ControlFlowView_birthTimeColumn
)) {
237 return Utils
.formatTime(entry
.getStartTime(), TimeFormat
.CALENDAR
, Resolution
.NANOSEC
);
238 } else if (COLUMN_NAMES
[columnIndex
].equals(Messages
.ControlFlowView_traceColumn
)) {
239 return entry
.getTrace().getName();
241 return ""; //$NON-NLS-1$
246 private static class ControlFlowFilterLabelProvider
extends TreeLabelProvider
{
249 public String
getColumnText(Object element
, int columnIndex
) {
250 ControlFlowEntry entry
= (ControlFlowEntry
) element
;
252 if (columnIndex
== 0) {
253 return entry
.getName();
254 } else if (columnIndex
== 1) {
255 return Integer
.toString(entry
.getThreadId());
257 return ""; //$NON-NLS-1$
262 // ------------------------------------------------------------------------
264 // ------------------------------------------------------------------------
267 protected void buildEventList(final ITmfTrace trace
, final ITmfTrace parentTrace
, final IProgressMonitor monitor
) {
268 final ITmfStateSystem ssq
= TmfStateSystemAnalysisModule
.getStateSystem(trace
, KernelAnalysisModule
.ID
);
273 final List
<ControlFlowEntry
> entryList
= new ArrayList
<>();
274 final Map
<Integer
, ControlFlowEntry
> entryMap
= new HashMap
<>();
276 long start
= ssq
.getStartTime();
277 setStartTime(Math
.min(getStartTime(), start
));
279 boolean complete
= false;
281 if (monitor
.isCanceled()) {
284 complete
= ssq
.waitUntilBuilt(BUILD_UPDATE_TIMEOUT
);
285 if (ssq
.isCancelled()) {
288 long end
= ssq
.getCurrentEndTime();
289 if (start
== end
&& !complete
) { // when complete execute one last time regardless of end time
292 final long resolution
= Math
.max(1, (end
- ssq
.getStartTime()) / getDisplayWidth());
293 setEndTime(Math
.max(getEndTime(), end
+ 1));
294 final List
<Integer
> threadQuarks
= ssq
.getQuarks(Attributes
.THREADS
, "*"); //$NON-NLS-1$
295 final long qStart
= start
;
296 final long qEnd
= end
;
297 queryFullStates(ssq
, qStart
, qEnd
, resolution
, monitor
, new IQueryHandler() {
299 public void handle(List
<List
<ITmfStateInterval
>> fullStates
, List
<ITmfStateInterval
> prevFullState
) {
300 for (int threadQuark
: threadQuarks
) {
301 String threadName
= ssq
.getAttributeName(threadQuark
);
304 threadId
= Integer
.parseInt(threadName
);
305 } catch (NumberFormatException e1
) {
308 if (threadId
<= 0) { // ignore the 'unknown' (-1) and swapper (0) threads
315 execNameQuark
= ssq
.getQuarkRelative(threadQuark
, Attributes
.EXEC_NAME
);
316 ppidQuark
= ssq
.getQuarkRelative(threadQuark
, Attributes
.PPID
);
317 } catch (AttributeNotFoundException e
) {
318 /* No information on this thread (yet?), skip it for now */
321 ITmfStateInterval lastExecNameInterval
= prevFullState
== null || execNameQuark
>= prevFullState
.size() ?
null : prevFullState
.get(execNameQuark
);
322 long lastExecNameStartTime
= lastExecNameInterval
== null ?
-1 : lastExecNameInterval
.getStartTime();
323 long lastExecNameEndTime
= lastExecNameInterval
== null ?
-1 : lastExecNameInterval
.getEndTime() + 1;
324 long lastPpidStartTime
= prevFullState
== null || ppidQuark
>= prevFullState
.size() ?
-1 : prevFullState
.get(ppidQuark
).getStartTime();
325 for (List
<ITmfStateInterval
> fullState
: fullStates
) {
326 if (monitor
.isCanceled()) {
329 if (execNameQuark
>= fullState
.size() || ppidQuark
>= fullState
.size()) {
330 /* No information on this thread (yet?), skip it for now */
333 ITmfStateInterval execNameInterval
= fullState
.get(execNameQuark
);
334 ITmfStateInterval ppidInterval
= fullState
.get(ppidQuark
);
335 long startTime
= execNameInterval
.getStartTime();
336 long endTime
= execNameInterval
.getEndTime() + 1;
337 if (startTime
== lastExecNameStartTime
&& ppidInterval
.getStartTime() == lastPpidStartTime
) {
340 boolean isNull
= execNameInterval
.getStateValue().isNull();
341 if (isNull
&& lastExecNameEndTime
< startTime
&& lastExecNameEndTime
!= -1) {
343 * There was a non-null interval in between the
344 * full states, try to use it.
347 execNameInterval
= ssq
.querySingleState(startTime
- 1, execNameQuark
);
348 ppidInterval
= ssq
.querySingleState(startTime
- 1, ppidQuark
);
349 startTime
= execNameInterval
.getStartTime();
350 endTime
= execNameInterval
.getEndTime() + 1;
351 } catch (AttributeNotFoundException e
) {
352 Activator
.getDefault().logError(e
.getMessage());
353 } catch (StateSystemDisposedException e
) {
357 if (!execNameInterval
.getStateValue().isNull() &&
358 execNameInterval
.getStateValue().getType() == ITmfStateValue
.Type
.STRING
) {
359 String execName
= execNameInterval
.getStateValue().unboxStr();
360 int ppid
= ppidInterval
.getStateValue().unboxInt();
361 ControlFlowEntry entry
= entryMap
.get(threadId
);
363 entry
= new ControlFlowEntry(threadQuark
, trace
, execName
, threadId
, ppid
, startTime
, endTime
);
364 entryList
.add(entry
);
365 entryMap
.put(threadId
, entry
);
368 * Update the name of the entry to the
369 * latest execName and the parent thread id
370 * to the latest ppid.
372 entry
.setName(execName
);
373 entry
.setParentThreadId(ppid
);
374 entry
.updateEndTime(endTime
);
378 entryMap
.remove(threadId
);
380 lastExecNameStartTime
= startTime
;
381 lastExecNameEndTime
= endTime
;
382 lastPpidStartTime
= ppidInterval
.getStartTime();
385 updateTree(entryList
, parentTrace
, ssq
);
387 for (final TimeGraphEntry entry
: getEntryList(ssq
)) {
388 if (monitor
.isCanceled()) {
391 buildStatusEvents(trace
, parentTrace
, ssq
, fullStates
, prevFullState
, (ControlFlowEntry
) entry
, monitor
, qStart
, qEnd
);
396 if (parentTrace
.equals(getTrace())) {
404 private void updateTree(List
<ControlFlowEntry
> entryList
, ITmfTrace parentTrace
, ITmfStateSystem ss
) {
405 List
<TimeGraphEntry
> rootListToAdd
= new ArrayList
<>();
406 List
<TimeGraphEntry
> rootListToRemove
= new ArrayList
<>();
407 List
<TimeGraphEntry
> rootList
= getEntryList(ss
);
409 for (ControlFlowEntry entry
: entryList
) {
410 boolean root
= (entry
.getParent() == null);
411 if (root
&& entry
.getParentThreadId() > 0) {
412 for (ControlFlowEntry parent
: entryList
) {
414 * Associate the parent entry only if their time overlap. A
415 * child entry may start before its parent, for example at
416 * the beginning of the trace if a parent has not yet
417 * appeared in the state system. We just want to make sure
418 * that the entry didn't start after the parent ended or
419 * ended before the parent started.
421 if (parent
.getThreadId() == entry
.getParentThreadId() &&
422 !(entry
.getStartTime() > parent
.getEndTime() ||
423 entry
.getEndTime() < parent
.getStartTime())) {
424 parent
.addChild(entry
);
426 if (rootList
!= null && rootList
.contains(entry
)) {
427 rootListToRemove
.add(entry
);
433 if (root
&& (rootList
== null || !rootList
.contains(entry
))) {
434 rootListToAdd
.add(entry
);
438 addToEntryList(parentTrace
, ss
, rootListToAdd
);
439 removeFromEntryList(parentTrace
, ss
, rootListToRemove
);
442 private void buildStatusEvents(ITmfTrace trace
, ITmfTrace parentTrace
, ITmfStateSystem ss
, @NonNull List
<List
<ITmfStateInterval
>> fullStates
,
443 @Nullable List
<ITmfStateInterval
> prevFullState
, ControlFlowEntry entry
, @NonNull IProgressMonitor monitor
, long start
, long end
) {
444 if (start
< entry
.getEndTime() && end
> entry
.getStartTime()) {
445 List
<ITimeEvent
> eventList
= getEventList(entry
, ss
, fullStates
, prevFullState
, monitor
);
446 if (eventList
== null) {
449 for (ITimeEvent event
: eventList
) {
450 entry
.addEvent(event
);
452 if (parentTrace
.equals(getTrace())) {
456 for (ITimeGraphEntry child
: entry
.getChildren()) {
457 if (monitor
.isCanceled()) {
460 buildStatusEvents(trace
, parentTrace
, ss
, fullStates
, prevFullState
, (ControlFlowEntry
) child
, monitor
, start
, end
);
465 protected @Nullable List
<ITimeEvent
> getEventList(@NonNull TimeGraphEntry tgentry
, ITmfStateSystem ss
,
466 @NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
, @NonNull IProgressMonitor monitor
) {
467 List
<ITimeEvent
> eventList
= null;
468 if (!(tgentry
instanceof ControlFlowEntry
)) {
471 ControlFlowEntry entry
= (ControlFlowEntry
) tgentry
;
473 int threadQuark
= entry
.getThreadQuark();
474 int statusQuark
= ss
.getQuarkRelative(threadQuark
, Attributes
.STATUS
);
475 eventList
= new ArrayList
<>(fullStates
.size());
476 ITmfStateInterval lastInterval
= prevFullState
== null || statusQuark
>= prevFullState
.size() ?
null : prevFullState
.get(statusQuark
);
477 long lastStartTime
= lastInterval
== null ?
-1 : lastInterval
.getStartTime();
478 long lastEndTime
= lastInterval
== null ?
-1 : lastInterval
.getEndTime() + 1;
479 for (List
<ITmfStateInterval
> fullState
: fullStates
) {
480 if (monitor
.isCanceled()) {
483 if (statusQuark
>= fullState
.size()) {
484 /* No information on this thread (yet?), skip it for now */
487 ITmfStateInterval statusInterval
= fullState
.get(statusQuark
);
488 long time
= statusInterval
.getStartTime();
489 if (time
== lastStartTime
) {
492 long duration
= statusInterval
.getEndTime() - time
+ 1;
495 status
= statusInterval
.getStateValue().unboxInt();
496 } catch (StateValueTypeException e
) {
497 Activator
.getDefault().logError(e
.getMessage());
499 if (lastEndTime
!= time
&& lastEndTime
!= -1) {
500 eventList
.add(new TimeEvent(entry
, lastEndTime
, time
- lastEndTime
));
502 if (!statusInterval
.getStateValue().isNull()) {
503 eventList
.add(new TimeEvent(entry
, time
, duration
, status
));
505 eventList
.add(new NullTimeEvent(entry
, time
, duration
));
507 lastStartTime
= time
;
508 lastEndTime
= time
+ duration
;
510 } catch (AttributeNotFoundException
| TimeRangeException e
) {
511 Activator
.getDefault().logError(e
.getMessage());
517 * Returns a value corresponding to the selected entry.
519 * Used in conjunction with synchingToTime to change the selected entry. If
520 * one of these methods is overridden in child class, then both should be.
523 * The currently selected time
524 * @return a value identifying the entry
526 private int getSelectionValue(long time
) {
528 for (ITmfTrace trace
: TmfTraceManager
.getTraceSet(getTrace())) {
532 ITmfStateSystem ssq
= TmfStateSystemAnalysisModule
.getStateSystem(trace
, KernelAnalysisModule
.ID
);
536 if (time
>= ssq
.getStartTime() && time
<= ssq
.getCurrentEndTime()) {
537 List
<Integer
> currentThreadQuarks
= ssq
.getQuarks(Attributes
.CPUS
, "*", Attributes
.CURRENT_THREAD
); //$NON-NLS-1$
538 for (int currentThreadQuark
: currentThreadQuarks
) {
540 ITmfStateInterval currentThreadInterval
= ssq
.querySingleState(time
, currentThreadQuark
);
541 int currentThread
= currentThreadInterval
.getStateValue().unboxInt();
542 if (currentThread
> 0) {
543 int statusQuark
= ssq
.getQuarkAbsolute(Attributes
.THREADS
, Integer
.toString(currentThread
), Attributes
.STATUS
);
544 ITmfStateInterval statusInterval
= ssq
.querySingleState(time
, statusQuark
);
545 if (statusInterval
.getStartTime() == time
) {
546 thread
= currentThread
;
550 } catch (AttributeNotFoundException
| TimeRangeException
| StateValueTypeException e
) {
551 Activator
.getDefault().logError(e
.getMessage());
552 } catch (StateSystemDisposedException e
) {
562 protected void synchingToTime(long time
) {
563 int selected
= getSelectionValue(time
);
565 for (Object element
: getTimeGraphViewer().getExpandedElements()) {
566 if (element
instanceof ControlFlowEntry
) {
567 ControlFlowEntry entry
= (ControlFlowEntry
) element
;
568 if (entry
.getThreadId() == selected
) {
569 getTimeGraphCombo().setSelection(entry
);
578 protected @NonNull List
<ILinkEvent
> getLinkList(ITmfStateSystem ss
,
579 @NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
, @NonNull IProgressMonitor monitor
) {
580 List
<ILinkEvent
> list
= new ArrayList
<>();
581 List
<TimeGraphEntry
> entryList
= getEntryList(ss
);
582 if (entryList
== null) {
585 for (ITmfTrace trace
: TmfTraceManager
.getTraceSet(getTrace())) {
586 List
<Integer
> currentThreadQuarks
= ss
.getQuarks(Attributes
.CPUS
, "*", Attributes
.CURRENT_THREAD
); //$NON-NLS-1$
587 for (int currentThreadQuark
: currentThreadQuarks
) {
588 if (currentThreadQuark
>= fullStates
.get(0).size()) {
589 /* No information on this cpu (yet?), skip it for now */
592 List
<ITmfStateInterval
> currentThreadIntervals
= new ArrayList
<>(fullStates
.size() + 2);
595 * Add the previous interval if it is the first query
596 * iteration and the first interval has currentThread=0. Add
597 * the following interval if the last interval has
598 * currentThread=0. These are diagonal arrows crossing the
599 * query iteration range.
601 if (prevFullState
== null) {
602 ITmfStateInterval currentThreadInterval
= fullStates
.get(0).get(currentThreadQuark
);
603 if (currentThreadInterval
.getStateValue().unboxInt() == 0) {
604 long start
= Math
.max(currentThreadInterval
.getStartTime() - 1, ss
.getStartTime());
605 currentThreadIntervals
.add(ss
.querySingleState(start
, currentThreadQuark
));
608 for (List
<ITmfStateInterval
> fullState
: fullStates
) {
609 currentThreadIntervals
.add(fullState
.get(currentThreadQuark
));
611 ITmfStateInterval currentThreadInterval
= fullStates
.get(fullStates
.size() - 1).get(currentThreadQuark
);
612 if (currentThreadInterval
.getStateValue().unboxInt() == 0) {
613 long end
= Math
.min(currentThreadInterval
.getEndTime() + 1, ss
.getCurrentEndTime());
614 currentThreadIntervals
.add(ss
.querySingleState(end
, currentThreadQuark
));
616 } catch (AttributeNotFoundException e
) {
617 Activator
.getDefault().logError(e
.getMessage());
619 } catch (StateSystemDisposedException e
) {
626 for (ITmfStateInterval currentThreadInterval
: currentThreadIntervals
) {
627 if (monitor
.isCanceled()) {
630 if (currentThreadInterval
.getEndTime() + 1 == lastEnd
) {
633 long time
= currentThreadInterval
.getStartTime();
634 if (time
!= lastEnd
) {
635 // don't create links where there are gaps in intervals due to the resolution
639 int thread
= currentThreadInterval
.getStateValue().unboxInt();
640 if (thread
> 0 && prevThread
> 0) {
641 ITimeGraphEntry prevEntry
= findEntry(entryList
, trace
, prevThread
);
642 ITimeGraphEntry nextEntry
= findEntry(entryList
, trace
, thread
);
643 list
.add(new TimeLinkEvent(prevEntry
, nextEntry
, prevEnd
, time
- prevEnd
, 0));
645 lastEnd
= currentThreadInterval
.getEndTime() + 1;
656 private ControlFlowEntry
findEntry(List
<?
extends ITimeGraphEntry
> entryList
, ITmfTrace trace
, int threadId
) {
657 for (ITimeGraphEntry entry
: entryList
) {
658 if (entry
instanceof ControlFlowEntry
) {
659 ControlFlowEntry controlFlowEntry
= (ControlFlowEntry
) entry
;
660 if (controlFlowEntry
.getThreadId() == threadId
&& controlFlowEntry
.getTrace() == trace
) {
661 return controlFlowEntry
;
662 } else if (entry
.hasChildren()) {
663 controlFlowEntry
= findEntry(entry
.getChildren(), trace
, threadId
);
664 if (controlFlowEntry
!= null) {
665 return controlFlowEntry
;