analysis: Add root trace entries to Control Flow view
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.os.linux.ui / src / org / eclipse / tracecompass / internal / analysis / os / linux / ui / views / controlflow / ControlFlowView.java
CommitLineData
6151d86c 1/*******************************************************************************
f8f46a52 2 * Copyright (c) 2012, 2016 Ericsson, École Polytechnique de Montréal and others.
6151d86c
PT
3 *
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
8 *
9 * Contributors:
10 * Patrick Tasse - Initial API and implementation
4999a196 11 * Geneviève Bastien - Move code to provide base classes for time graph view
b97d61f0 12 * Christian Mansky - Add check active / uncheck inactive buttons
bf415887 13 * Mahdi Zolnouri & Samuel Gagnon - Add flat / hierarchical button
6151d86c
PT
14 *******************************************************************************/
15
ace7140d 16package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow;
e363eae1 17
6151d86c 18import java.util.ArrayList;
3553c912 19import java.util.Collections;
6151d86c 20import java.util.Comparator;
1cf25311 21import java.util.HashMap;
bf415887 22import java.util.HashSet;
6151d86c 23import java.util.List;
1cf25311 24import java.util.Map;
bf415887
MZ
25import java.util.Set;
26import java.util.stream.Collectors;
27import java.util.stream.Stream;
6151d86c
PT
28
29import org.eclipse.core.runtime.IProgressMonitor;
dfa0ef96 30import org.eclipse.jdt.annotation.NonNull;
d2120fb6 31import org.eclipse.jdt.annotation.Nullable;
bf415887 32import org.eclipse.jface.action.Action;
03ab8eeb 33import org.eclipse.jface.action.IAction;
90bb3a0c 34import org.eclipse.jface.action.IMenuManager;
79ec0b89 35import org.eclipse.jface.action.IToolBarManager;
bf415887 36import org.eclipse.jface.action.MenuManager;
79ec0b89 37import org.eclipse.jface.dialogs.IDialogSettings;
90bb3a0c
BH
38import org.eclipse.jface.viewers.ISelection;
39import org.eclipse.jface.viewers.StructuredSelection;
b97d61f0 40import org.eclipse.swt.widgets.Composite;
0f7a12d3 41import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule;
bf415887 42import org.eclipse.tracecompass.common.core.StreamUtils.StreamFlattener;
f69045e2 43import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes;
e363eae1
AM
44import org.eclipse.tracecompass.internal.analysis.os.linux.ui.Activator;
45import org.eclipse.tracecompass.internal.analysis.os.linux.ui.Messages;
9620ac26 46import org.eclipse.tracecompass.internal.analysis.os.linux.ui.actions.FollowThreadAction;
e894a508
AM
47import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
48import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
49import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
50import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
51import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
52import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
53import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
bf415887
MZ
54import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
55import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
2bdf0193
AM
56import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
57import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
58import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
8a0bbebf 59import org.eclipse.tracecompass.tmf.core.util.Pair;
8321a699 60import org.eclipse.tracecompass.tmf.ui.views.timegraph.AbstractStateSystemTimeGraphView;
2bdf0193
AM
61import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ILinkEvent;
62import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
63import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
8321a699 64import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.NullTimeEvent;
2bdf0193
AM
65import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeEvent;
66import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
67import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeLinkEvent;
68import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils;
69import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.Resolution;
70import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
6151d86c 71
a4cddcbc
BH
72import com.google.common.collect.ImmutableList;
73
6151d86c
PT
74/**
75 * The Control Flow view main object
76 *
77 */
8321a699 78public class ControlFlowView extends AbstractStateSystemTimeGraphView {
6151d86c
PT
79
80 // ------------------------------------------------------------------------
81 // Constants
82 // ------------------------------------------------------------------------
6151d86c
PT
83 /**
84 * View ID.
85 */
e363eae1 86 public static final String ID = "org.eclipse.tracecompass.analysis.os.linux.views.controlflow"; //$NON-NLS-1$
6151d86c 87
4999a196
GB
88 private static final String PROCESS_COLUMN = Messages.ControlFlowView_processColumn;
89 private static final String TID_COLUMN = Messages.ControlFlowView_tidColumn;
90 private static final String PTID_COLUMN = Messages.ControlFlowView_ptidColumn;
6151d86c 91 private static final String BIRTH_TIME_COLUMN = Messages.ControlFlowView_birthTimeColumn;
6151d86c 92
4999a196 93 private static final String[] COLUMN_NAMES = new String[] {
6151d86c
PT
94 PROCESS_COLUMN,
95 TID_COLUMN,
96 PTID_COLUMN,
3553c912 97 BIRTH_TIME_COLUMN
6151d86c
PT
98 };
99
4999a196 100 private static final String[] FILTER_COLUMN_NAMES = new String[] {
6ac5a950
AM
101 PROCESS_COLUMN,
102 TID_COLUMN
103 };
104
aae89862
PT
105 // Timeout between updates in the build thread in ms
106 private static final long BUILD_UPDATE_TIMEOUT = 500;
107
a4cddcbc
BH
108 private static final Comparator<ITimeGraphEntry>[] COLUMN_COMPARATORS;
109
a14d7bd5
BH
110 private static final int INITIAL_SORT_COLUMN_INDEX = 3;
111
a4cddcbc
BH
112 static {
113 ImmutableList.Builder<Comparator<ITimeGraphEntry>> builder = ImmutableList.builder();
114 builder.add(ControlFlowColumnComparators.PROCESS_NAME_COLUMN_COMPARATOR)
9620ac26
MK
115 .add(ControlFlowColumnComparators.TID_COLUMN_COMPARATOR)
116 .add(ControlFlowColumnComparators.PTID_COLUMN_COMPARATOR)
3553c912 117 .add(ControlFlowColumnComparators.BIRTH_TIME_COLUMN_COMPARATOR);
a4cddcbc
BH
118 List<Comparator<ITimeGraphEntry>> l = builder.build();
119 COLUMN_COMPARATORS = l.toArray(new Comparator[l.size()]);
120 }
121
bf415887
MZ
122 private final Set<ITmfTrace> fFlatTraces = new HashSet<>();
123
124 private IAction fFlatAction;
125
126 private IAction fHierarchicalAction;
127
6151d86c 128 // ------------------------------------------------------------------------
4999a196 129 // Constructors
6151d86c
PT
130 // ------------------------------------------------------------------------
131
4999a196
GB
132 /**
133 * Constructor
134 */
135 public ControlFlowView() {
747adf5c 136 super(ID, new ControlFlowPresentationProvider());
a14d7bd5 137 setTreeColumns(COLUMN_NAMES, COLUMN_COMPARATORS, INITIAL_SORT_COLUMN_INDEX);
4999a196 138 setTreeLabelProvider(new ControlFlowTreeLabelProvider());
747adf5c 139 setFilterColumns(FILTER_COLUMN_NAMES);
a03b7ee4 140 setFilterLabelProvider(new ControlFlowFilterLabelProvider());
a4cddcbc 141 setEntryComparator(ControlFlowColumnComparators.BIRTH_TIME_COLUMN_COMPARATOR);
6151d86c
PT
142 }
143
b97d61f0
CM
144 @Override
145 public void createPartControl(Composite parent) {
146 super.createPartControl(parent);
147 // add "Check active" Button to TimeGraphFilterDialog
148 super.getTimeGraphCombo().addTimeGraphFilterCheckActiveButton(
149 new ControlFlowCheckActiveProvider(Messages.ControlFlowView_checkActiveLabel, Messages.ControlFlowView_checkActiveToolTip));
150 // add "Uncheck inactive" Button to TimeGraphFilterDialog
151 super.getTimeGraphCombo().addTimeGraphFilterUncheckInactiveButton(
152 new ControlFlowCheckActiveProvider(Messages.ControlFlowView_uncheckInactiveLabel, Messages.ControlFlowView_uncheckInactiveToolTip));
9620ac26
MK
153 }
154
90bb3a0c
BH
155 /**
156 * @since 2.0
157 */
158 @Override
159 protected void fillTimeGraphEntryContextMenu(@NonNull IMenuManager menuManager) {
160 ISelection selection = getSite().getSelectionProvider().getSelection();
161 if (selection instanceof StructuredSelection) {
162 StructuredSelection sSel = (StructuredSelection) selection;
163 if (sSel.getFirstElement() instanceof ControlFlowEntry) {
164 ControlFlowEntry entry = (ControlFlowEntry) sSel.getFirstElement();
165 menuManager.add(new FollowThreadAction(ControlFlowView.this, entry.getName(), entry.getThreadId(), entry.getTrace()));
9620ac26 166 }
90bb3a0c 167 }
b97d61f0
CM
168 }
169
79ec0b89
PT
170 @Override
171 protected void fillLocalToolBar(IToolBarManager manager) {
086f21ae 172 super.fillLocalToolBar(manager);
79ec0b89
PT
173 IDialogSettings settings = Activator.getDefault().getDialogSettings();
174 IDialogSettings section = settings.getSection(getClass().getName());
175 if (section == null) {
176 section = settings.addNewSection(getClass().getName());
177 }
03ab8eeb
PT
178
179 IAction hideArrowsAction = getTimeGraphCombo().getTimeGraphViewer().getHideArrowsAction(section);
180 manager.add(hideArrowsAction);
181
182 IAction followArrowBwdAction = getTimeGraphCombo().getTimeGraphViewer().getFollowArrowBwdAction();
183 followArrowBwdAction.setText(Messages.ControlFlowView_followCPUBwdText);
184 followArrowBwdAction.setToolTipText(Messages.ControlFlowView_followCPUBwdText);
185 manager.add(followArrowBwdAction);
186
187 IAction followArrowFwdAction = getTimeGraphCombo().getTimeGraphViewer().getFollowArrowFwdAction();
188 followArrowFwdAction.setText(Messages.ControlFlowView_followCPUFwdText);
189 followArrowFwdAction.setToolTipText(Messages.ControlFlowView_followCPUFwdText);
190 manager.add(followArrowFwdAction);
79ec0b89
PT
191 }
192
bf415887
MZ
193 @Override
194 protected void fillLocalMenu(IMenuManager manager) {
195 super.fillLocalMenu(manager);
196 final MenuManager item = new MenuManager(Messages.ControlFlowView_threadPresentation);
197 fFlatAction = createFlatAction();
198 item.add(fFlatAction);
199
200 fHierarchicalAction = createHierarchicalAction();
201 item.add(fHierarchicalAction);
202 manager.add(item);
203
204 }
205
206 private IAction createHierarchicalAction() {
207 IAction action = new Action(Messages.ControlFlowView_hierarchicalViewLabel, IAction.AS_RADIO_BUTTON) {
208 @Override
209 public void run() {
210 ITmfTrace parentTrace = getTrace();
211 synchronized (fFlatTraces) {
212 fFlatTraces.remove(parentTrace);
213 for (ITmfTrace trace : TmfTraceManager.getTraceSet(parentTrace)) {
214 final ITmfStateSystem ss = TmfStateSystemAnalysisModule.getStateSystem(trace, KernelAnalysisModule.ID);
3553c912
PT
215 for (TimeGraphEntry traceEntry : getEntryList(ss)) {
216 List<ControlFlowEntry> currentRootList = traceEntry.getChildren().stream()
217 .filter(e -> e instanceof ControlFlowEntry)
218 .map(e -> (ControlFlowEntry) e).collect(Collectors.toList());
219 addEntriesToHierarchicalTree(currentRootList, traceEntry);
220 }
bf415887
MZ
221 }
222 }
223 refresh();
224 }
225 };
226 action.setChecked(true);
227 action.setToolTipText(Messages.ControlFlowView_hierarchicalViewToolTip);
228 return action;
229 }
230
231 private IAction createFlatAction() {
232 IAction action = new Action(Messages.ControlFlowView_flatViewLabel, IAction.AS_RADIO_BUTTON) {
233 @Override
234 public void run() {
235 ITmfTrace parentTrace = getTrace();
236 synchronized (fFlatTraces) {
237 fFlatTraces.add(parentTrace);
238 for (ITmfTrace trace : TmfTraceManager.getTraceSet(parentTrace)) {
239 final ITmfStateSystem ss = TmfStateSystemAnalysisModule.getStateSystem(trace, KernelAnalysisModule.ID);
3553c912
PT
240 for (TimeGraphEntry traceEntry : getEntryList(ss)) {
241 hierarchicalToFlatTree(traceEntry);
242 }
bf415887
MZ
243 }
244 }
245 refresh();
246 }
247 };
248 action.setToolTipText(Messages.ControlFlowView_flatViewToolTip);
249 return action;
250 }
251
4999a196
GB
252 @Override
253 protected String getNextText() {
254 return Messages.ControlFlowView_nextProcessActionNameText;
255 }
6151d86c 256
4999a196
GB
257 @Override
258 protected String getNextTooltip() {
259 return Messages.ControlFlowView_nextProcessActionToolTipText;
260 }
6151d86c 261
4999a196
GB
262 @Override
263 protected String getPrevText() {
264 return Messages.ControlFlowView_previousProcessActionNameText;
265 }
6151d86c 266
4999a196
GB
267 @Override
268 protected String getPrevTooltip() {
269 return Messages.ControlFlowView_previousProcessActionToolTipText;
6151d86c
PT
270 }
271
6151d86c 272 /**
4999a196 273 * @author gbastien
6151d86c 274 *
6151d86c 275 */
4999a196 276 protected static class ControlFlowTreeLabelProvider extends TreeLabelProvider {
6151d86c 277
4999a196
GB
278 @Override
279 public String getColumnText(Object element, int columnIndex) {
3553c912
PT
280 if (element instanceof TraceEntry) {
281 if (columnIndex == 0) {
282 return ((TraceEntry) element).getName();
283 }
284 return ""; //$NON-NLS-1$
285 }
4999a196 286 ControlFlowEntry entry = (ControlFlowEntry) element;
6151d86c 287
4999a196
GB
288 if (COLUMN_NAMES[columnIndex].equals(Messages.ControlFlowView_processColumn)) {
289 return entry.getName();
290 } else if (COLUMN_NAMES[columnIndex].equals(Messages.ControlFlowView_tidColumn)) {
291 return Integer.toString(entry.getThreadId());
292 } else if (COLUMN_NAMES[columnIndex].equals(Messages.ControlFlowView_ptidColumn)) {
293 if (entry.getParentThreadId() > 0) {
294 return Integer.toString(entry.getParentThreadId());
6151d86c 295 }
4999a196
GB
296 } else if (COLUMN_NAMES[columnIndex].equals(Messages.ControlFlowView_birthTimeColumn)) {
297 return Utils.formatTime(entry.getStartTime(), TimeFormat.CALENDAR, Resolution.NANOSEC);
6151d86c 298 }
4999a196 299 return ""; //$NON-NLS-1$
6151d86c 300 }
6151d86c 301
6151d86c
PT
302 }
303
a03b7ee4
PT
304 private static class ControlFlowFilterLabelProvider extends TreeLabelProvider {
305
306 @Override
307 public String getColumnText(Object element, int columnIndex) {
3553c912
PT
308 if (element instanceof TraceEntry) {
309 if (columnIndex == 0) {
310 return ((TraceEntry) element).getName();
311 }
312 return ""; //$NON-NLS-1$
313 }
a03b7ee4
PT
314 ControlFlowEntry entry = (ControlFlowEntry) element;
315
316 if (columnIndex == 0) {
317 return entry.getName();
318 } else if (columnIndex == 1) {
319 return Integer.toString(entry.getThreadId());
320 }
321 return ""; //$NON-NLS-1$
322 }
323
324 }
325
3553c912
PT
326 private static class TraceEntry extends TimeGraphEntry {
327
328 public TraceEntry(String name, long startTime, long endTime) {
329 super(name, startTime, endTime);
330 }
331
332 @Override
333 public boolean hasTimeEvents() {
334 return false;
335 }
336 }
337
bf415887
MZ
338 @TmfSignalHandler
339 @Override
340 public void traceClosed(org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal signal) {
341 super.traceClosed(signal);
342 synchronized (fFlatTraces) {
343 fFlatTraces.remove(signal.getTrace());
344 }
345 }
346
347 @TmfSignalHandler
348 @Override
349 public void traceSelected(TmfTraceSelectedSignal signal) {
350 super.traceSelected(signal);
351 synchronized (fFlatTraces) {
352 if (fFlatTraces.contains(signal.getTrace())) {
353 fHierarchicalAction.setChecked(false);
354 fFlatAction.setChecked(true);
355 } else {
356 fFlatAction.setChecked(false);
357 fHierarchicalAction.setChecked(true);
358 }
359 }
360 }
361
6151d86c
PT
362 // ------------------------------------------------------------------------
363 // Internal
364 // ------------------------------------------------------------------------
365
4999a196 366 @Override
f8f46a52 367 protected void buildEntryList(final ITmfTrace trace, final ITmfTrace parentTrace, final IProgressMonitor monitor) {
8321a699 368 final ITmfStateSystem ssq = TmfStateSystemAnalysisModule.getStateSystem(trace, KernelAnalysisModule.ID);
1cf25311
PT
369 if (ssq == null) {
370 return;
371 }
fec1ac0b 372
8321a699 373 final List<ControlFlowEntry> entryList = new ArrayList<>();
3553c912
PT
374 /** Map of trace entries */
375 Map<ITmfTrace, TraceEntry> traceEntryMap = new HashMap<>();
376 /** Map of control flow entries, key is a pair [threadId, cpuId] */
8a0bbebf 377 final Map<Pair<Integer, Integer>, ControlFlowEntry> entryMap = new HashMap<>();
1cf25311
PT
378
379 long start = ssq.getStartTime();
380 setStartTime(Math.min(getStartTime(), start));
381
382 boolean complete = false;
383 while (!complete) {
faa38350
PT
384 if (monitor.isCanceled()) {
385 return;
386 }
aae89862 387 complete = ssq.waitUntilBuilt(BUILD_UPDATE_TIMEOUT);
1cf25311
PT
388 if (ssq.isCancelled()) {
389 return;
390 }
391 long end = ssq.getCurrentEndTime();
392 if (start == end && !complete) { // when complete execute one last time regardless of end time
393 continue;
394 }
3553c912
PT
395
396 TraceEntry aTraceEntry = traceEntryMap.get(trace);
397 if (aTraceEntry == null) {
398 aTraceEntry = new TraceEntry(trace.getName(), start, end + 1);
399 traceEntryMap.put(trace, aTraceEntry);
400 addToEntryList(parentTrace, ssq, Collections.singletonList(aTraceEntry));
401 } else {
402 aTraceEntry.updateEndTime(end + 1);
403 }
404 final TraceEntry traceEntry = aTraceEntry;
405
8321a699 406 final long resolution = Math.max(1, (end - ssq.getStartTime()) / getDisplayWidth());
1cf25311 407 setEndTime(Math.max(getEndTime(), end + 1));
8321a699 408 final List<Integer> threadQuarks = ssq.getQuarks(Attributes.THREADS, "*"); //$NON-NLS-1$
8d5d4aa4 409 queryFullStates(ssq, start, end, resolution, monitor, new IQueryHandler() {
8321a699
PT
410 @Override
411 public void handle(List<List<ITmfStateInterval>> fullStates, List<ITmfStateInterval> prevFullState) {
412 for (int threadQuark : threadQuarks) {
8a0bbebf
MJ
413 String threadAttributeName = ssq.getAttributeName(threadQuark);
414
642b4947 415 Pair<Integer, Integer> entryKey = Attributes.parseThreadAttributeName(threadAttributeName);
8a0bbebf
MJ
416 int threadId = entryKey.getFirst();
417
418 if (threadId < 0) { // ignore the 'unknown' (-1) thread
8321a699
PT
419 continue;
420 }
1c471b9e 421
8321a699
PT
422 int execNameQuark;
423 int ppidQuark;
424 try {
425 execNameQuark = ssq.getQuarkRelative(threadQuark, Attributes.EXEC_NAME);
426 ppidQuark = ssq.getQuarkRelative(threadQuark, Attributes.PPID);
427 } catch (AttributeNotFoundException e) {
428 /* No information on this thread (yet?), skip it for now */
429 continue;
430 }
431 ITmfStateInterval lastExecNameInterval = prevFullState == null || execNameQuark >= prevFullState.size() ? null : prevFullState.get(execNameQuark);
432 long lastExecNameStartTime = lastExecNameInterval == null ? -1 : lastExecNameInterval.getStartTime();
433 long lastExecNameEndTime = lastExecNameInterval == null ? -1 : lastExecNameInterval.getEndTime() + 1;
434 long lastPpidStartTime = prevFullState == null || ppidQuark >= prevFullState.size() ? -1 : prevFullState.get(ppidQuark).getStartTime();
435 for (List<ITmfStateInterval> fullState : fullStates) {
436 if (monitor.isCanceled()) {
437 return;
6151d86c 438 }
8321a699
PT
439 if (execNameQuark >= fullState.size() || ppidQuark >= fullState.size()) {
440 /* No information on this thread (yet?), skip it for now */
441 continue;
442 }
443 ITmfStateInterval execNameInterval = fullState.get(execNameQuark);
444 ITmfStateInterval ppidInterval = fullState.get(ppidQuark);
445 long startTime = execNameInterval.getStartTime();
446 long endTime = execNameInterval.getEndTime() + 1;
447 if (startTime == lastExecNameStartTime && ppidInterval.getStartTime() == lastPpidStartTime) {
448 continue;
449 }
450 boolean isNull = execNameInterval.getStateValue().isNull();
451 if (isNull && lastExecNameEndTime < startTime && lastExecNameEndTime != -1) {
452 /*
453 * There was a non-null interval in between the
454 * full states, try to use it.
455 */
456 try {
457 execNameInterval = ssq.querySingleState(startTime - 1, execNameQuark);
458 ppidInterval = ssq.querySingleState(startTime - 1, ppidQuark);
459 startTime = execNameInterval.getStartTime();
460 endTime = execNameInterval.getEndTime() + 1;
461 } catch (AttributeNotFoundException e) {
462 Activator.getDefault().logError(e.getMessage());
463 } catch (StateSystemDisposedException e) {
464 /* ignored */
465 }
1c471b9e 466 }
8321a699
PT
467 if (!execNameInterval.getStateValue().isNull() &&
468 execNameInterval.getStateValue().getType() == ITmfStateValue.Type.STRING) {
469 String execName = execNameInterval.getStateValue().unboxStr();
470 int ppid = ppidInterval.getStateValue().unboxInt();
8a0bbebf 471 ControlFlowEntry entry = entryMap.get(entryKey);
8321a699
PT
472 if (entry == null) {
473 entry = new ControlFlowEntry(threadQuark, trace, execName, threadId, ppid, startTime, endTime);
474 entryList.add(entry);
8a0bbebf 475 entryMap.put(entryKey, entry);
8321a699
PT
476 } else {
477 /*
478 * Update the name of the entry to the
479 * latest execName and the parent thread id
480 * to the latest ppid.
481 */
482 entry.setName(execName);
483 entry.setParentThreadId(ppid);
484 entry.updateEndTime(endTime);
485 }
486 }
487 if (isNull) {
8a0bbebf 488 entryMap.remove(entryKey);
8321a699
PT
489 }
490 lastExecNameStartTime = startTime;
491 lastExecNameEndTime = endTime;
492 lastPpidStartTime = ppidInterval.getStartTime();
6151d86c 493 }
6151d86c 494 }
bf415887
MZ
495 synchronized (fFlatTraces) {
496 if (fFlatTraces.contains(parentTrace)) {
3553c912 497 addEntriesToFlatTree(entryList, traceEntry);
bf415887 498 } else {
3553c912 499 addEntriesToHierarchicalTree(entryList, traceEntry);
bf415887
MZ
500 }
501 }
8d5d4aa4
PT
502 }
503 });
4999a196 504
8d5d4aa4
PT
505 queryFullStates(ssq, ssq.getStartTime(), end, resolution, monitor, new IQueryHandler() {
506 @Override
507 public void handle(@NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState) {
3553c912 508 for (final TimeGraphEntry entry : traceEntry.getChildren()) {
8321a699
PT
509 if (monitor.isCanceled()) {
510 return;
511 }
8d5d4aa4 512 buildStatusEvents(trace, parentTrace, ssq, fullStates, prevFullState, (ControlFlowEntry) entry, monitor, ssq.getStartTime(), end);
8321a699
PT
513 }
514 }
515 });
1cf25311
PT
516
517 if (parentTrace.equals(getTrace())) {
d7ee91bb 518 refresh();
6151d86c 519 }
1cf25311 520
1cf25311 521 start = end;
6151d86c
PT
522 }
523 }
524
bf415887 525 /**
3553c912 526 * Add entries to the traces's child list in a flat fashion (no hierarchy).
bf415887 527 * If one entry has children, we do a depth first search to add each child
3553c912 528 * to the trace's child list and update the parent and child relations.
bf415887 529 */
3553c912
PT
530 private static void hierarchicalToFlatTree(TimeGraphEntry traceEntry) {
531 List<@NonNull TimeGraphEntry> rootList = traceEntry.getChildren();
bf415887
MZ
532 // We visit the children of every entry to add
533 StreamFlattener<TimeGraphEntry> sf = new StreamFlattener<>(entry -> entry.getChildren().stream());
534 Stream<TimeGraphEntry> allEntries = rootList.stream().flatMap(entry -> sf.flatten(entry));
535
536 // We add every entry that is missing from the trace's entry list
537 List<@NonNull TimeGraphEntry> rootListToAdd = allEntries
538 .filter(entry -> !rootList.contains(entry))
539 .collect(Collectors.toList());
540 rootList.forEach(entry -> {
541 entry.clearChildren();
542 });
543 rootListToAdd.forEach(entry -> {
3553c912 544 traceEntry.addChild(entry);
bf415887
MZ
545 entry.clearChildren();
546 });
bf415887
MZ
547 }
548
549 /**
3553c912 550 * Add entries to the traces's child list in a flat fashion (no hierarchy).
bf415887 551 */
3553c912
PT
552 private static void addEntriesToFlatTree(List<@NonNull ControlFlowEntry> entryList, TimeGraphEntry traceEntry) {
553 List<TimeGraphEntry> rootList = traceEntry.getChildren();
554 for (ControlFlowEntry entry : entryList) {
555 if (!rootList.contains(entry)) {
556 traceEntry.addChild(entry);
557 }
558 }
bf415887
MZ
559 }
560
561 /**
3553c912 562 * Add entries to the trace's child list in a hierarchical fashion.
bf415887 563 */
3553c912
PT
564 private static void addEntriesToHierarchicalTree(List<ControlFlowEntry> entryList, TimeGraphEntry traceEntry) {
565 List<TimeGraphEntry> rootList = traceEntry.getChildren();
1cf25311 566
1d46dc38 567 for (ControlFlowEntry entry : entryList) {
3553c912 568 boolean root = (entry.getParent() == null || entry.getParent() == traceEntry);
1cf25311 569 if (root && entry.getParentThreadId() > 0) {
1d46dc38 570 for (ControlFlowEntry parent : entryList) {
0a35a36f
GB
571 /*
572 * Associate the parent entry only if their time overlap. A
573 * child entry may start before its parent, for example at
574 * the beginning of the trace if a parent has not yet
575 * appeared in the state system. We just want to make sure
576 * that the entry didn't start after the parent ended or
577 * ended before the parent started.
578 */
6151d86c 579 if (parent.getThreadId() == entry.getParentThreadId() &&
0a35a36f
GB
580 !(entry.getStartTime() > parent.getEndTime() ||
581 entry.getEndTime() < parent.getStartTime())) {
6151d86c
PT
582 parent.addChild(entry);
583 root = false;
3553c912
PT
584 if (rootList.contains(entry)) {
585 traceEntry.removeChild(entry);
1cf25311 586 }
6151d86c
PT
587 break;
588 }
589 }
590 }
3553c912
PT
591 if (root && (!rootList.contains(entry))) {
592 traceEntry.addChild(entry);
6151d86c
PT
593 }
594 }
595 }
596
8321a699
PT
597 private void buildStatusEvents(ITmfTrace trace, ITmfTrace parentTrace, ITmfStateSystem ss, @NonNull List<List<ITmfStateInterval>> fullStates,
598 @Nullable List<ITmfStateInterval> prevFullState, ControlFlowEntry entry, @NonNull IProgressMonitor monitor, long start, long end) {
1cf25311 599 if (start < entry.getEndTime() && end > entry.getStartTime()) {
8321a699 600 List<ITimeEvent> eventList = getEventList(entry, ss, fullStates, prevFullState, monitor);
d2120fb6 601 if (eventList == null) {
1cf25311
PT
602 return;
603 }
8d5d4aa4
PT
604 /* Start a new event list on first iteration, then append to it */
605 if (prevFullState == null) {
606 entry.setEventList(eventList);
607 } else {
608 for (ITimeEvent event : eventList) {
609 entry.addEvent(event);
610 }
1cf25311 611 }
8321a699 612 if (parentTrace.equals(getTrace())) {
1cf25311
PT
613 redraw();
614 }
faa38350 615 }
6151d86c 616 for (ITimeGraphEntry child : entry.getChildren()) {
faa38350
PT
617 if (monitor.isCanceled()) {
618 return;
619 }
8321a699 620 buildStatusEvents(trace, parentTrace, ss, fullStates, prevFullState, (ControlFlowEntry) child, monitor, start, end);
6151d86c
PT
621 }
622 }
623
4999a196 624 @Override
8321a699
PT
625 protected @Nullable List<ITimeEvent> getEventList(@NonNull TimeGraphEntry tgentry, ITmfStateSystem ss,
626 @NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState, @NonNull IProgressMonitor monitor) {
4999a196
GB
627 List<ITimeEvent> eventList = null;
628 if (!(tgentry instanceof ControlFlowEntry)) {
629 return eventList;
630 }
631 ControlFlowEntry entry = (ControlFlowEntry) tgentry;
6151d86c 632 try {
8321a699
PT
633 int threadQuark = entry.getThreadQuark();
634 int statusQuark = ss.getQuarkRelative(threadQuark, Attributes.STATUS);
635 eventList = new ArrayList<>(fullStates.size());
636 ITmfStateInterval lastInterval = prevFullState == null || statusQuark >= prevFullState.size() ? null : prevFullState.get(statusQuark);
637 long lastStartTime = lastInterval == null ? -1 : lastInterval.getStartTime();
638 long lastEndTime = lastInterval == null ? -1 : lastInterval.getEndTime() + 1;
639 for (List<ITmfStateInterval> fullState : fullStates) {
6151d86c
PT
640 if (monitor.isCanceled()) {
641 return null;
642 }
8321a699
PT
643 if (statusQuark >= fullState.size()) {
644 /* No information on this thread (yet?), skip it for now */
645 continue;
646 }
647 ITmfStateInterval statusInterval = fullState.get(statusQuark);
6151d86c 648 long time = statusInterval.getStartTime();
8321a699
PT
649 if (time == lastStartTime) {
650 continue;
651 }
6151d86c
PT
652 long duration = statusInterval.getEndTime() - time + 1;
653 int status = -1;
654 try {
655 status = statusInterval.getStateValue().unboxInt();
656 } catch (StateValueTypeException e) {
8321a699 657 Activator.getDefault().logError(e.getMessage());
6151d86c
PT
658 }
659 if (lastEndTime != time && lastEndTime != -1) {
af10fe06 660 eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime));
6151d86c 661 }
8321a699
PT
662 if (!statusInterval.getStateValue().isNull()) {
663 eventList.add(new TimeEvent(entry, time, duration, status));
664 } else {
665 eventList.add(new NullTimeEvent(entry, time, duration));
666 }
667 lastStartTime = time;
6151d86c
PT
668 lastEndTime = time + duration;
669 }
8321a699 670 } catch (AttributeNotFoundException | TimeRangeException e) {
50a47aa6 671 Activator.getDefault().logError(e.getMessage());
6151d86c
PT
672 }
673 return eventList;
674 }
675
4999a196
GB
676 /**
677 * Returns a value corresponding to the selected entry.
678 *
1cf25311
PT
679 * Used in conjunction with synchingToTime to change the selected entry. If
680 * one of these methods is overridden in child class, then both should be.
4999a196
GB
681 *
682 * @param time
683 * The currently selected time
684 * @return a value identifying the entry
685 */
686 private int getSelectionValue(long time) {
687 int thread = -1;
c14c0757 688 for (ITmfTrace trace : TmfTraceManager.getTraceSet(getTrace())) {
4999a196
GB
689 if (thread > 0) {
690 break;
691 }
6d16f5a9 692 ITmfStateSystem ssq = TmfStateSystemAnalysisModule.getStateSystem(trace, KernelAnalysisModule.ID);
1cf25311
PT
693 if (ssq == null) {
694 continue;
695 }
696 if (time >= ssq.getStartTime() && time <= ssq.getCurrentEndTime()) {
697 List<Integer> currentThreadQuarks = ssq.getQuarks(Attributes.CPUS, "*", Attributes.CURRENT_THREAD); //$NON-NLS-1$
698 for (int currentThreadQuark : currentThreadQuarks) {
699 try {
700 ITmfStateInterval currentThreadInterval = ssq.querySingleState(time, currentThreadQuark);
701 int currentThread = currentThreadInterval.getStateValue().unboxInt();
702 if (currentThread > 0) {
703 int statusQuark = ssq.getQuarkAbsolute(Attributes.THREADS, Integer.toString(currentThread), Attributes.STATUS);
704 ITmfStateInterval statusInterval = ssq.querySingleState(time, statusQuark);
705 if (statusInterval.getStartTime() == time) {
706 thread = currentThread;
707 break;
4999a196 708 }
4999a196 709 }
1cf25311 710 } catch (AttributeNotFoundException | TimeRangeException | StateValueTypeException e) {
8321a699 711 Activator.getDefault().logError(e.getMessage());
1cf25311
PT
712 } catch (StateSystemDisposedException e) {
713 /* Ignored */
faa38350 714 }
6151d86c 715 }
6151d86c 716 }
4999a196
GB
717 }
718 return thread;
6151d86c
PT
719 }
720
4999a196
GB
721 @Override
722 protected void synchingToTime(long time) {
723 int selected = getSelectionValue(time);
724 if (selected > 0) {
747adf5c 725 for (Object element : getTimeGraphViewer().getExpandedElements()) {
4999a196
GB
726 if (element instanceof ControlFlowEntry) {
727 ControlFlowEntry entry = (ControlFlowEntry) element;
728 if (entry.getThreadId() == selected) {
729 getTimeGraphCombo().setSelection(entry);
730 break;
6151d86c
PT
731 }
732 }
733 }
6151d86c 734 }
6151d86c 735 }
79ec0b89
PT
736
737 @Override
8321a699 738 protected @NonNull List<ILinkEvent> getLinkList(ITmfStateSystem ss,
143217ee 739 @NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState, @NonNull IProgressMonitor monitor) {
e0838ca1 740 List<ILinkEvent> list = new ArrayList<>();
8321a699 741 List<TimeGraphEntry> entryList = getEntryList(ss);
c14c0757 742 if (entryList == null) {
79ec0b89
PT
743 return list;
744 }
c14c0757 745 for (ITmfTrace trace : TmfTraceManager.getTraceSet(getTrace())) {
8321a699
PT
746 List<Integer> currentThreadQuarks = ss.getQuarks(Attributes.CPUS, "*", Attributes.CURRENT_THREAD); //$NON-NLS-1$
747 for (int currentThreadQuark : currentThreadQuarks) {
748 if (currentThreadQuark >= fullStates.get(0).size()) {
749 /* No information on this cpu (yet?), skip it for now */
4bc53929
GB
750 continue;
751 }
8321a699
PT
752 List<ITmfStateInterval> currentThreadIntervals = new ArrayList<>(fullStates.size() + 2);
753 try {
143217ee
PT
754 /*
755 * Add the previous interval if it is the first query
756 * iteration and the first interval has currentThread=0. Add
757 * the following interval if the last interval has
758 * currentThread=0. These are diagonal arrows crossing the
759 * query iteration range.
760 */
761 if (prevFullState == null) {
762 ITmfStateInterval currentThreadInterval = fullStates.get(0).get(currentThreadQuark);
763 if (currentThreadInterval.getStateValue().unboxInt() == 0) {
764 long start = Math.max(currentThreadInterval.getStartTime() - 1, ss.getStartTime());
765 currentThreadIntervals.add(ss.querySingleState(start, currentThreadQuark));
766 }
767 }
8321a699
PT
768 for (List<ITmfStateInterval> fullState : fullStates) {
769 currentThreadIntervals.add(fullState.get(currentThreadQuark));
770 }
143217ee
PT
771 ITmfStateInterval currentThreadInterval = fullStates.get(fullStates.size() - 1).get(currentThreadQuark);
772 if (currentThreadInterval.getStateValue().unboxInt() == 0) {
773 long end = Math.min(currentThreadInterval.getEndTime() + 1, ss.getCurrentEndTime());
774 currentThreadIntervals.add(ss.querySingleState(end, currentThreadQuark));
775 }
8321a699
PT
776 } catch (AttributeNotFoundException e) {
777 Activator.getDefault().logError(e.getMessage());
778 return list;
779 } catch (StateSystemDisposedException e) {
780 /* Ignored */
781 return list;
782 }
783 int prevThread = 0;
784 long prevEnd = 0;
785 long lastEnd = 0;
786 for (ITmfStateInterval currentThreadInterval : currentThreadIntervals) {
787 if (monitor.isCanceled()) {
788 return list;
789 }
790 if (currentThreadInterval.getEndTime() + 1 == lastEnd) {
791 continue;
792 }
793 long time = currentThreadInterval.getStartTime();
794 if (time != lastEnd) {
795 // don't create links where there are gaps in intervals due to the resolution
796 prevThread = 0;
797 prevEnd = 0;
798 }
799 int thread = currentThreadInterval.getStateValue().unboxInt();
800 if (thread > 0 && prevThread > 0) {
801 ITimeGraphEntry prevEntry = findEntry(entryList, trace, prevThread);
802 ITimeGraphEntry nextEntry = findEntry(entryList, trace, thread);
803 list.add(new TimeLinkEvent(prevEntry, nextEntry, prevEnd, time - prevEnd, 0));
804 }
805 lastEnd = currentThreadInterval.getEndTime() + 1;
806 if (thread != 0) {
807 prevThread = thread;
808 prevEnd = lastEnd;
79ec0b89 809 }
79ec0b89
PT
810 }
811 }
812 }
813 return list;
814 }
815
3553c912
PT
816 private ControlFlowEntry findEntry(List<TimeGraphEntry> entryList, ITmfTrace trace, int threadId) {
817 for (TimeGraphEntry entry : entryList) {
79ec0b89
PT
818 if (entry instanceof ControlFlowEntry) {
819 ControlFlowEntry controlFlowEntry = (ControlFlowEntry) entry;
820 if (controlFlowEntry.getThreadId() == threadId && controlFlowEntry.getTrace() == trace) {
821 return controlFlowEntry;
3553c912
PT
822 }
823 }
824 if (entry.hasChildren()) {
825 ControlFlowEntry controlFlowEntry = findEntry(entry.getChildren(), trace, threadId);
826 if (controlFlowEntry != null) {
827 return controlFlowEntry;
79ec0b89
PT
828 }
829 }
830 }
831 return null;
832 }
6151d86c 833}
This page took 0.128212 seconds and 5 git commands to generate.