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