/*******************************************************************************
- * Copyright (c) 2012 Ericsson
+ * Copyright (c) 2012, 2014 Ericsson, École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
*
* Contributors:
* Patrick Tasse - Initial API and implementation
+ * Geneviève Bastien - Move code to provide base classes for time graph view
*******************************************************************************/
package org.eclipse.linuxtools.internal.lttng2.kernel.ui.views.controlflow;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.jface.action.Action;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IToolBarManager;
-import org.eclipse.jface.action.Separator;
-import org.eclipse.jface.viewers.ILabelProviderListener;
-import org.eclipse.jface.viewers.ITableLabelProvider;
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.linuxtools.internal.lttng2.kernel.core.Attributes;
+import org.eclipse.linuxtools.internal.lttng2.kernel.ui.Activator;
import org.eclipse.linuxtools.internal.lttng2.kernel.ui.Messages;
-import org.eclipse.linuxtools.lttng2.kernel.core.trace.CtfKernelTrace;
-import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfTmfTimestamp;
-import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
-import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;
-import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
-import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
-import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
-import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
-import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentDisposedSignal;
-import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentSelectedSignal;
-import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal;
-import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
-import org.eclipse.linuxtools.tmf.core.signal.TmfStateSystemBuildCompleted;
-import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;
-import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
+import org.eclipse.linuxtools.lttng2.kernel.core.analysis.LttngKernelAnalysisModule;
+import org.eclipse.linuxtools.statesystem.core.ITmfStateSystem;
+import org.eclipse.linuxtools.statesystem.core.exceptions.AttributeNotFoundException;
+import org.eclipse.linuxtools.statesystem.core.exceptions.StateSystemDisposedException;
+import org.eclipse.linuxtools.statesystem.core.exceptions.StateValueTypeException;
+import org.eclipse.linuxtools.statesystem.core.exceptions.TimeRangeException;
+import org.eclipse.linuxtools.statesystem.core.interval.ITmfStateInterval;
+import org.eclipse.linuxtools.statesystem.core.statevalue.ITmfStateValue;
+import org.eclipse.linuxtools.tmf.core.statesystem.TmfStateSystemAnalysisModule;
import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
-import org.eclipse.linuxtools.tmf.core.trace.TmfExperiment;
-import org.eclipse.linuxtools.tmf.ui.views.TmfView;
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphRangeListener;
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphSelectionListener;
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphCombo;
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphRangeUpdateEvent;
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphSelectionEvent;
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphTimeEvent;
+import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
+import org.eclipse.linuxtools.tmf.ui.views.timegraph.AbstractTimeGraphView;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ILinkEvent;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeEvent;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.TimeEvent;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.TimeLinkEvent;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils.Resolution;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.TreeColumn;
-import org.eclipse.ui.IActionBars;
/**
* The Control Flow view main object
*
*/
-public class ControlFlowView extends TmfView {
+public class ControlFlowView extends AbstractTimeGraphView {
// ------------------------------------------------------------------------
// Constants
*/
public static final String ID = "org.eclipse.linuxtools.lttng2.kernel.ui.views.controlflow"; //$NON-NLS-1$
- /**
- * Initial time range
- */
- private static final long INITIAL_WINDOW_OFFSET = (1L * 100 * 1000 * 1000); // .1sec
-
- private static final String PROCESS_COLUMN = Messages.ControlFlowView_processColumn;
- private static final String TID_COLUMN = Messages.ControlFlowView_tidColumn;
- private static final String PTID_COLUMN = Messages.ControlFlowView_ptidColumn;
+ private static final String PROCESS_COLUMN = Messages.ControlFlowView_processColumn;
+ private static final String TID_COLUMN = Messages.ControlFlowView_tidColumn;
+ private static final String PTID_COLUMN = Messages.ControlFlowView_ptidColumn;
private static final String BIRTH_TIME_COLUMN = Messages.ControlFlowView_birthTimeColumn;
- private static final String TRACE_COLUMN = Messages.ControlFlowView_traceColumn;
+ private static final String TRACE_COLUMN = Messages.ControlFlowView_traceColumn;
- private final String[] COLUMN_NAMES = new String[] {
+ private static final String[] COLUMN_NAMES = new String[] {
PROCESS_COLUMN,
TID_COLUMN,
PTID_COLUMN,
TRACE_COLUMN
};
- /**
- * Redraw state enum
- */
- private enum State { IDLE, BUSY, PENDING }
-
- // ------------------------------------------------------------------------
- // Fields
- // ------------------------------------------------------------------------
-
- // The timegraph combo
- private TimeGraphCombo fTimeGraphCombo;
-
- // The selected experiment
- private TmfExperiment fSelectedExperiment;
-
- // The timegraph entry list
- private ArrayList<ControlFlowEntry> fEntryList;
-
- // The time graph entry list synchronization object
- final private Object fEntryListSyncObj = new Object();
-
- // The start time
- private long fStartTime;
-
- // The end time
- private long fEndTime;
-
- // The display width
- private final int fDisplayWidth;
-
- // The zoom thread
- private ZoomThread fZoomThread;
-
- // The next resource action
- private Action fNextResourceAction;
-
- // The previous resource action
- private Action fPreviousResourceAction;
-
- // A comparator class
- private final ControlFlowEntryComparator fControlFlowEntryComparator = new ControlFlowEntryComparator();
-
- // The redraw state used to prevent unnecessary queuing of display runnables
- private State fRedrawState = State.IDLE;
+ private static final String[] FILTER_COLUMN_NAMES = new String[] {
+ PROCESS_COLUMN,
+ TID_COLUMN
+ };
- // The redraw synchronization object
- final private Object fSyncObj = new Object();
+ // Timeout between updates in the build thread in ms
+ private static final long BUILD_UPDATE_TIMEOUT = 500;
// ------------------------------------------------------------------------
- // Classes
+ // Constructors
// ------------------------------------------------------------------------
- private class TreeContentProvider implements ITreeContentProvider {
-
- @Override
- public void dispose() {
- }
-
- @Override
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- }
-
- @Override
- public Object[] getElements(Object inputElement) {
- return (ITimeGraphEntry[]) inputElement;
- }
-
- @Override
- public Object[] getChildren(Object parentElement) {
- ITimeGraphEntry entry = (ITimeGraphEntry) parentElement;
- List<? extends ITimeGraphEntry> children = entry.getChildren();
- return children.toArray(new ITimeGraphEntry[children.size()]);
- }
-
- @Override
- public Object getParent(Object element) {
- ITimeGraphEntry entry = (ITimeGraphEntry) element;
- return entry.getParent();
- }
-
- @Override
- public boolean hasChildren(Object element) {
- ITimeGraphEntry entry = (ITimeGraphEntry) element;
- return entry.hasChildren();
- }
-
+ /**
+ * Constructor
+ */
+ public ControlFlowView() {
+ super(ID, new ControlFlowPresentationProvider());
+ setTreeColumns(COLUMN_NAMES);
+ setTreeLabelProvider(new ControlFlowTreeLabelProvider());
+ setFilterColumns(FILTER_COLUMN_NAMES);
+ setFilterLabelProvider(new ControlFlowFilterLabelProvider());
+ setEntryComparator(new ControlFlowEntryComparator());
}
- private class TreeLabelProvider implements ITableLabelProvider {
-
- @Override
- public void addListener(ILabelProviderListener listener) {
- }
-
- @Override
- public void dispose() {
- }
-
- @Override
- public boolean isLabelProperty(Object element, String property) {
- return false;
- }
+ @Override
+ protected void fillLocalToolBar(IToolBarManager manager) {
+ super.fillLocalToolBar(manager);
+ IDialogSettings settings = Activator.getDefault().getDialogSettings();
+ IDialogSettings section = settings.getSection(getClass().getName());
+ if (section == null) {
+ section = settings.addNewSection(getClass().getName());
+ }
+
+ IAction hideArrowsAction = getTimeGraphCombo().getTimeGraphViewer().getHideArrowsAction(section);
+ manager.add(hideArrowsAction);
+
+ IAction followArrowBwdAction = getTimeGraphCombo().getTimeGraphViewer().getFollowArrowBwdAction();
+ followArrowBwdAction.setText(Messages.ControlFlowView_followCPUBwdText);
+ followArrowBwdAction.setToolTipText(Messages.ControlFlowView_followCPUBwdText);
+ manager.add(followArrowBwdAction);
+
+ IAction followArrowFwdAction = getTimeGraphCombo().getTimeGraphViewer().getFollowArrowFwdAction();
+ followArrowFwdAction.setText(Messages.ControlFlowView_followCPUFwdText);
+ followArrowFwdAction.setToolTipText(Messages.ControlFlowView_followCPUFwdText);
+ manager.add(followArrowFwdAction);
+ }
- @Override
- public void removeListener(ILabelProviderListener listener) {
- }
+ @Override
+ protected String getNextText() {
+ return Messages.ControlFlowView_nextProcessActionNameText;
+ }
- @Override
- public Image getColumnImage(Object element, int columnIndex) {
- return null;
- }
+ @Override
+ protected String getNextTooltip() {
+ return Messages.ControlFlowView_nextProcessActionToolTipText;
+ }
- @Override
- public String getColumnText(Object element, int columnIndex) {
- ControlFlowEntry entry = (ControlFlowEntry) element;
- if (columnIndex == 0) {
- return entry.getName();
- } else if (columnIndex == 1) {
- return Integer.toString(entry.getThreadId());
- } else if (columnIndex == 2) {
- if (entry.getParentThreadId() > 0) {
- return Integer.toString(entry.getParentThreadId());
- }
- } else if (columnIndex == 3) {
- return Utils.formatTime(entry.getBirthTime(), TimeFormat.ABSOLUTE, Resolution.NANOSEC);
- } else if (columnIndex == 4) {
- return entry.getTrace().getName();
- }
- return ""; //$NON-NLS-1$
- }
+ @Override
+ protected String getPrevText() {
+ return Messages.ControlFlowView_previousProcessActionNameText;
+ }
+ @Override
+ protected String getPrevTooltip() {
+ return Messages.ControlFlowView_previousProcessActionToolTipText;
}
private static class ControlFlowEntryComparator implements Comparator<ITimeGraphEntry> {
@Override
public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
+
int result = 0;
if ((o1 instanceof ControlFlowEntry) && (o2 instanceof ControlFlowEntry)) {
}
}
-
- private class ZoomThread extends Thread {
- private final long fZoomStartTime;
- private final long fZoomEndTime;
- private final long fResolution;
- private final IProgressMonitor fMonitor;
-
- public ZoomThread(long startTime, long endTime) {
- super("ControlFlowView zoom"); //$NON-NLS-1$
- fZoomStartTime = startTime;
- fZoomEndTime = endTime;
- fResolution = Math.max(1, (fZoomEndTime - fZoomStartTime) / fDisplayWidth);
- fMonitor = new NullProgressMonitor();
- }
+ /**
+ * @author gbastien
+ *
+ */
+ protected static class ControlFlowTreeLabelProvider extends TreeLabelProvider {
@Override
- public void run() {
- ArrayList<ControlFlowEntry> entryList = null;
- synchronized (fEntryListSyncObj) {
- entryList = (ArrayList<ControlFlowEntry>) fEntryList.clone();
- }
- if (entryList == null) {
- return;
- }
- for (ControlFlowEntry entry : entryList) {
- if (fMonitor.isCanceled()) {
- break;
- }
- zoom(entry, fMonitor);
- }
- }
+ public String getColumnText(Object element, int columnIndex) {
+ ControlFlowEntry entry = (ControlFlowEntry) element;
- private void zoom(ControlFlowEntry entry, IProgressMonitor monitor) {
- if (fZoomStartTime <= fStartTime && fZoomEndTime >= fEndTime) {
- entry.setZoomedEventList(null);
- } else {
- List<ITimeEvent> zoomedEventList = getEventList(entry, fZoomStartTime, fZoomEndTime, fResolution, monitor);
- if (zoomedEventList != null) {
- entry.setZoomedEventList(zoomedEventList);
- }
- }
- redraw();
- for (ControlFlowEntry child : entry.getChildren()) {
- if (fMonitor.isCanceled()) {
- return;
+ if (COLUMN_NAMES[columnIndex].equals(Messages.ControlFlowView_processColumn)) {
+ return entry.getName();
+ } else if (COLUMN_NAMES[columnIndex].equals(Messages.ControlFlowView_tidColumn)) {
+ return Integer.toString(entry.getThreadId());
+ } else if (COLUMN_NAMES[columnIndex].equals(Messages.ControlFlowView_ptidColumn)) {
+ if (entry.getParentThreadId() > 0) {
+ return Integer.toString(entry.getParentThreadId());
}
- zoom(child, monitor);
+ } else if (COLUMN_NAMES[columnIndex].equals(Messages.ControlFlowView_birthTimeColumn)) {
+ return Utils.formatTime(entry.getStartTime(), TimeFormat.CALENDAR, Resolution.NANOSEC);
+ } else if (COLUMN_NAMES[columnIndex].equals(Messages.ControlFlowView_traceColumn)) {
+ return entry.getTrace().getName();
}
+ return ""; //$NON-NLS-1$
}
- public void cancel() {
- fMonitor.setCanceled(true);
- }
- }
-
- // ------------------------------------------------------------------------
- // Constructors
- // ------------------------------------------------------------------------
-
- /**
- * Constructor
- */
- public ControlFlowView() {
- super(ID);
- fDisplayWidth = Display.getDefault().getBounds().width;
}
- // ------------------------------------------------------------------------
- // ViewPart
- // ------------------------------------------------------------------------
-
- /* (non-Javadoc)
- * @see org.eclipse.linuxtools.tmf.ui.views.TmfView#createPartControl(org.eclipse.swt.widgets.Composite)
- */
- @Override
- public void createPartControl(Composite parent) {
- fTimeGraphCombo = new TimeGraphCombo(parent, SWT.NONE);
-
- fTimeGraphCombo.setTreeContentProvider(new TreeContentProvider());
-
- fTimeGraphCombo.setTreeLabelProvider(new TreeLabelProvider());
-
- fTimeGraphCombo.setTimeGraphProvider(new ControlFlowPresentationProvider());
-
- fTimeGraphCombo.setTreeColumns(COLUMN_NAMES);
-
- fTimeGraphCombo.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
- @Override
- public void timeRangeUpdated(TimeGraphRangeUpdateEvent event) {
- final long startTime = event.getStartTime();
- final long endTime = event.getEndTime();
- TmfTimeRange range = new TmfTimeRange(new CtfTmfTimestamp(startTime), new CtfTmfTimestamp(endTime));
- TmfTimestamp time = new CtfTmfTimestamp(fTimeGraphCombo.getTimeGraphViewer().getSelectedTime());
- broadcast(new TmfRangeSynchSignal(ControlFlowView.this, range, time));
- if (fZoomThread != null) {
- fZoomThread.cancel();
- }
- startZoomThread(startTime, endTime);
- }
- });
-
- fTimeGraphCombo.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
- @Override
- public void timeSelected(TimeGraphTimeEvent event) {
- long time = event.getTime();
- broadcast(new TmfTimeSynchSignal(ControlFlowView.this, new CtfTmfTimestamp(time)));
- }
- });
-
- fTimeGraphCombo.addSelectionListener(new ITimeGraphSelectionListener() {
- @Override
- public void selectionChanged(TimeGraphSelectionEvent event) {
- //ITimeGraphEntry selection = event.getSelection();
- }
- });
+ private static class ControlFlowFilterLabelProvider extends TreeLabelProvider {
- fTimeGraphCombo.getTimeGraphViewer().setTimeCalendarFormat(true);
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ ControlFlowEntry entry = (ControlFlowEntry) element;
- final Thread thread = new Thread("ControlFlowView build") { //$NON-NLS-1$
- @Override
- public void run() {
- if (TmfExperiment.getCurrentExperiment() != null) {
- selectExperiment(TmfExperiment.getCurrentExperiment());
- }
+ if (columnIndex == 0) {
+ return entry.getName();
+ } else if (columnIndex == 1) {
+ return Integer.toString(entry.getThreadId());
}
- };
- thread.start();
+ return ""; //$NON-NLS-1$
+ }
- // View Action Handling
- makeActions();
- contributeToActionBars();
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
- */
- @Override
- public void setFocus() {
- fTimeGraphCombo.setFocus();
}
// ------------------------------------------------------------------------
- // Signal handlers
+ // Internal
// ------------------------------------------------------------------------
- /**
- * Handler for the experiment selected signal
- *
- * @param signal
- * The signal that's received
- */
- @TmfSignalHandler
- public void experimentSelected(final TmfExperimentSelectedSignal signal) {
- if (signal.getExperiment().equals(fSelectedExperiment)) {
+ @Override
+ protected void buildEventList(final ITmfTrace trace, ITmfTrace parentTrace, IProgressMonitor monitor) {
+ if (trace == null) {
return;
}
-
- final Thread thread = new Thread("ControlFlowView build") { //$NON-NLS-1$
- @Override
- public void run() {
- selectExperiment(signal.getExperiment());
- }
- };
- thread.start();
- }
-
- /**
- * Experiment is disposed: clear the data structures and the view
- *
- * @param signal the signal received
- */
- @TmfSignalHandler
- public void experimentDisposed(final TmfExperimentDisposedSignal signal) {
- if (signal.getExperiment().equals(fSelectedExperiment)) {
- fSelectedExperiment = null;
- fStartTime = 0;
- fEndTime = 0;
- fZoomThread.cancel();
- synchronized(fEntryListSyncObj) {
- fEntryList.clear();
- }
- refresh(INITIAL_WINDOW_OFFSET);
- }
- }
-
- /**
- * Handler for the synch signal
- *
- * @param signal
- * The signal that's received
- */
- @TmfSignalHandler
- public void synchToTime(final TmfTimeSynchSignal signal) {
- if (signal.getSource() == this || fSelectedExperiment == null || fSelectedExperiment.getTraces() == null) {
+ ITmfStateSystem ssq = TmfStateSystemAnalysisModule.getStateSystem(trace, LttngKernelAnalysisModule.ID);
+ if (ssq == null) {
return;
}
- final long time = signal.getCurrentTime().normalize(0, -9).getValue();
- int thread = -1;
- for (ITmfTrace trace : fSelectedExperiment.getTraces()) {
- if (thread > 0) {
- break;
+ List<ControlFlowEntry> entryList = new ArrayList<>();
+ Map<Integer, ControlFlowEntry> entryMap = new HashMap<>();
+
+ long start = ssq.getStartTime();
+ setStartTime(Math.min(getStartTime(), start));
+
+ boolean complete = false;
+ while (!complete) {
+ if (monitor.isCanceled()) {
+ return;
}
- if (trace instanceof CtfKernelTrace) {
- CtfKernelTrace ctfKernelTrace = (CtfKernelTrace) trace;
- ITmfStateSystem ssq = ctfKernelTrace.getStateSystem();
- if (time >= ssq.getStartTime() && time <= ssq.getCurrentEndTime()) {
- List<Integer> currentThreadQuarks = ssq.getQuarks(Attributes.CPUS, "*", Attributes.CURRENT_THREAD); //$NON-NLS-1$
- for (int currentThreadQuark : currentThreadQuarks) {
- try {
- ITmfStateInterval currentThreadInterval = ssq.querySingleState(time, currentThreadQuark);
- int currentThread = currentThreadInterval.getStateValue().unboxInt();
- if (currentThread > 0) {
- int statusQuark = ssq.getQuarkAbsolute(Attributes.THREADS, Integer.toString(currentThread), Attributes.STATUS);
- ITmfStateInterval statusInterval = ssq.querySingleState(time, statusQuark);
- if (statusInterval.getStartTime() == time) {
- thread = currentThread;
- break;
- }
- }
- } catch (AttributeNotFoundException e) {
- e.printStackTrace();
- } catch (TimeRangeException e) {
- e.printStackTrace();
- } catch (StateValueTypeException e) {
- e.printStackTrace();
- }
- }
- }
+ complete = ssq.waitUntilBuilt(BUILD_UPDATE_TIMEOUT);
+ if (ssq.isCancelled()) {
+ return;
}
- }
- final int selectedThread = thread;
-
- Display.getDefault().asyncExec(new Runnable() {
- @Override
- public void run() {
- if (fTimeGraphCombo.isDisposed()) {
+ long end = ssq.getCurrentEndTime();
+ if (start == end && !complete) { // when complete execute one last time regardless of end time
+ continue;
+ }
+ setEndTime(Math.max(getEndTime(), end + 1));
+ List<Integer> threadQuarks = ssq.getQuarks(Attributes.THREADS, "*"); //$NON-NLS-1$
+ for (int threadQuark : threadQuarks) {
+ if (monitor.isCanceled()) {
return;
}
- fTimeGraphCombo.getTimeGraphViewer().setSelectedTime(time, true);
- startZoomThread(fTimeGraphCombo.getTimeGraphViewer().getTime0(), fTimeGraphCombo.getTimeGraphViewer().getTime1());
-
- if (selectedThread > 0) {
- for (Object element : fTimeGraphCombo.getTimeGraphViewer().getExpandedElements()) {
- if (element instanceof ControlFlowEntry) {
- ControlFlowEntry entry = (ControlFlowEntry) element;
- if (entry.getThreadId() == selectedThread) {
- fTimeGraphCombo.setSelection(entry);
+ String threadName = ssq.getAttributeName(threadQuark);
+ int threadId = -1;
+ try {
+ threadId = Integer.parseInt(threadName);
+ } catch (NumberFormatException e1) {
+ continue;
+ }
+ if (threadId <= 0) { // ignore the 'unknown' (-1) and swapper (0) threads
+ continue;
+ }
+
+ int execNameQuark;
+ List<ITmfStateInterval> execNameIntervals;
+ try {
+ execNameQuark = ssq.getQuarkRelative(threadQuark, Attributes.EXEC_NAME);
+ execNameIntervals = ssq.queryHistoryRange(execNameQuark, start, end);
+ } catch (AttributeNotFoundException e) {
+ /* No information on this thread (yet?), skip it for now */
+ continue;
+ } catch (StateSystemDisposedException e) {
+ /* State system is closing down, no point continuing */
+ break;
+ }
+
+ for (ITmfStateInterval execNameInterval : execNameIntervals) {
+ if (monitor.isCanceled()) {
+ return;
+ }
+ ControlFlowEntry entry = entryMap.get(threadId);
+ if (!execNameInterval.getStateValue().isNull() &&
+ execNameInterval.getStateValue().getType() == ITmfStateValue.Type.STRING) {
+ String execName = execNameInterval.getStateValue().unboxStr();
+ long startTime = execNameInterval.getStartTime();
+ long endTime = execNameInterval.getEndTime() + 1;
+ if (entry == null) {
+ ITmfStateInterval ppidInterval = null;
+ try {
+ int ppidQuark = ssq.getQuarkRelative(threadQuark, Attributes.PPID);
+ ppidInterval = ssq.querySingleState(startTime, ppidQuark);
+ } catch (AttributeNotFoundException e) {
+ /* No info, keep PPID at -1 */
+ } catch (StateSystemDisposedException e) {
+ /* SS is closing down, time to bail */
break;
}
+ int ppid = -1;
+ if (!(ppidInterval == null) && !ppidInterval.getStateValue().isNull()) {
+ ppid = ppidInterval.getStateValue().unboxInt();
+ }
+ entry = new ControlFlowEntry(threadQuark, trace, execName, threadId, ppid, startTime, endTime);
+ entryList.add(entry);
+ entryMap.put(threadId, entry);
+ } else {
+ // update the name of the entry to the latest
+ // execName
+ entry.setName(execName);
+ entry.updateEndTime(endTime);
}
+ } else {
+ entryMap.remove(threadId);
}
}
}
- });
- }
- /**
- * Handler for the range sync signal
- *
- * @param signal
- * The signal that's received
- */
- @TmfSignalHandler
- public void synchToRange(final TmfRangeSynchSignal signal) {
- if (signal.getSource() == this || fSelectedExperiment == null) {
- return;
- }
- final long startTime = signal.getCurrentRange().getStartTime().normalize(0, -9).getValue();
- final long endTime = signal.getCurrentRange().getEndTime().normalize(0, -9).getValue();
- final long time = signal.getCurrentTime().normalize(0, -9).getValue();
- Display.getDefault().asyncExec(new Runnable() {
- @Override
- public void run() {
- if (fTimeGraphCombo.isDisposed()) {
- return;
- }
- fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
- fTimeGraphCombo.getTimeGraphViewer().setSelectedTime(time, false);
- startZoomThread(startTime, endTime);
- }
- });
- }
+ updateTree(entryList, parentTrace);
- /**
- * Handler for the state system build completed signal
- *
- * @param signal
- * The signal that's received
- */
- @TmfSignalHandler
- public void stateSystemBuildCompleted (final TmfStateSystemBuildCompleted signal) {
- final TmfExperiment selectedExperiment = fSelectedExperiment;
- if (selectedExperiment == null || selectedExperiment.getTraces() == null) {
- return;
- }
- for (ITmfTrace trace : selectedExperiment.getTraces()) {
- if (trace == signal.getTrace() && trace instanceof CtfKernelTrace) {
- final Thread thread = new Thread("ControlFlowView build") { //$NON-NLS-1$
- @Override
- public void run() {
- // rebuild the model
- selectExperiment(selectedExperiment);
- }
- };
- thread.start();
+ if (parentTrace.equals(getTrace())) {
+ refresh();
}
- }
- }
-
- // ------------------------------------------------------------------------
- // Internal
- // ------------------------------------------------------------------------
- private void selectExperiment(TmfExperiment experiment) {
- fStartTime = Long.MAX_VALUE;
- fEndTime = Long.MIN_VALUE;
- fSelectedExperiment = experiment;
- ArrayList<ControlFlowEntry> rootList = new ArrayList<ControlFlowEntry>();
- for (ITmfTrace trace : experiment.getTraces()) {
- if (trace instanceof CtfKernelTrace) {
- ArrayList<ControlFlowEntry> entryList = new ArrayList<ControlFlowEntry>();
- CtfKernelTrace ctfKernelTrace = (CtfKernelTrace) trace;
- ITmfStateSystem ssq = ctfKernelTrace.getStateSystem();
- long start = ssq.getStartTime();
- long end = ssq.getCurrentEndTime() + 1;
- fStartTime = Math.min(fStartTime, start);
- fEndTime = Math.max(fEndTime, end);
- List<Integer> threadQuarks = ssq.getQuarks(Attributes.THREADS, "*"); //$NON-NLS-1$
- for (int threadQuark : threadQuarks) {
- String threadName = ssq.getAttributeName(threadQuark);
- int threadId = -1;
- try {
- threadId = Integer.parseInt(threadName);
- } catch (NumberFormatException e1) {
- continue;
- }
- if (threadId == 0) { // ignore the swapper thread
- continue;
- }
- int execNameQuark = -1;
- try {
- try {
- execNameQuark = ssq.getQuarkRelative(threadQuark, Attributes.EXEC_NAME);
- } catch (AttributeNotFoundException e) {
- continue;
- }
- int ppidQuark = ssq.getQuarkRelative(threadQuark, Attributes.PPID);
- List<ITmfStateInterval> execNameIntervals = ssq.queryHistoryRange(execNameQuark, start, end - 1);
- long birthTime = -1;
- for (ITmfStateInterval execNameInterval : execNameIntervals) {
- if (!execNameInterval.getStateValue().isNull() && execNameInterval.getStateValue().getType() == 1) {
- String execName = execNameInterval.getStateValue().unboxStr();
- long startTime = execNameInterval.getStartTime();
- long endTime = execNameInterval.getEndTime() + 1;
- if (birthTime == -1) {
- birthTime = startTime;
- }
- int ppid = -1;
- if (ppidQuark != -1) {
- ITmfStateInterval ppidInterval = ssq.querySingleState(startTime, ppidQuark);
- ppid = ppidInterval.getStateValue().unboxInt();
- }
- ControlFlowEntry entry = new ControlFlowEntry(threadQuark, ctfKernelTrace, execName, threadId, ppid, birthTime, startTime, endTime);
- entryList.add(entry);
- entry.addEvent(new TimeEvent(entry, startTime, endTime - startTime));
- } else {
- birthTime = -1;
- }
- }
- } catch (AttributeNotFoundException e) {
- e.printStackTrace();
- } catch (TimeRangeException e) {
- e.printStackTrace();
- } catch (StateValueTypeException e) {
- e.printStackTrace();
- }
+ for (ControlFlowEntry entry : entryList) {
+ if (monitor.isCanceled()) {
+ return;
}
- buildTree(entryList, rootList);
+ buildStatusEvents(entry.getTrace(), entry, monitor, start, end);
}
- Collections.sort(rootList, fControlFlowEntryComparator);
- synchronized (fEntryListSyncObj) {
- fEntryList = (ArrayList<ControlFlowEntry>) rootList.clone();
- }
- refresh(INITIAL_WINDOW_OFFSET);
- }
- for (ControlFlowEntry entry : rootList) {
- buildStatusEvents(entry);
+
+ start = end;
}
}
- private static void buildTree(ArrayList<ControlFlowEntry> entryList,
- ArrayList<ControlFlowEntry> rootList) {
+ private void updateTree(List<ControlFlowEntry> entryList, ITmfTrace parentTrace) {
+ List<TimeGraphEntry> rootListToAdd = new ArrayList<>();
+ List<TimeGraphEntry> rootListToRemove = new ArrayList<>();
+ List<TimeGraphEntry> rootList = getEntryList(parentTrace);
+
for (ControlFlowEntry entry : entryList) {
- boolean root = true;
- if (entry.getParentThreadId() > 0) {
+ boolean root = (entry.getParent() == null);
+ if (root && entry.getParentThreadId() > 0) {
for (ControlFlowEntry parent : entryList) {
if (parent.getThreadId() == entry.getParentThreadId() &&
entry.getStartTime() >= parent.getStartTime() &&
entry.getStartTime() <= parent.getEndTime()) {
parent.addChild(entry);
root = false;
+ if (rootList != null && rootList.contains(entry)) {
+ rootListToRemove.add(entry);
+ }
break;
}
}
}
- if (root) {
- rootList.add(entry);
+ if (root && (rootList == null || !rootList.contains(entry))) {
+ rootListToAdd.add(entry);
}
}
+
+ addToEntryList(parentTrace, rootListToAdd);
+ removeFromEntryList(parentTrace, rootListToRemove);
}
- private void buildStatusEvents(ControlFlowEntry entry) {
- ITmfStateSystem ssq = entry.getTrace().getStateSystem();
- long start = ssq.getStartTime();
- long end = ssq.getCurrentEndTime() + 1;
- long resolution = Math.max(1, (end - start) / fDisplayWidth);
- List<ITimeEvent> eventList = getEventList(entry, entry.getStartTime(), entry.getEndTime(), resolution, new NullProgressMonitor());
- entry.setEventList(eventList);
- redraw();
+ private void buildStatusEvents(ITmfTrace trace, ControlFlowEntry entry, IProgressMonitor monitor, long start, long end) {
+ if (start < entry.getEndTime() && end > entry.getStartTime()) {
+ ITmfStateSystem ssq = TmfStateSystemAnalysisModule.getStateSystem(entry.getTrace(), LttngKernelAnalysisModule.ID);
+ if (ssq == null) {
+ return;
+ }
+
+ long startTime = Math.max(start, entry.getStartTime());
+ long endTime = Math.min(end + 1, entry.getEndTime());
+ long resolution = Math.max(1, (end - ssq.getStartTime()) / getDisplayWidth());
+ List<ITimeEvent> eventList = getEventList(entry, startTime, endTime, resolution, monitor);
+ if (eventList == null) {
+ return;
+ }
+ for (ITimeEvent event : eventList) {
+ entry.addEvent(event);
+ }
+ if (trace.equals(getTrace())) {
+ redraw();
+ }
+ }
for (ITimeGraphEntry child : entry.getChildren()) {
- buildStatusEvents((ControlFlowEntry) child);
+ if (monitor.isCanceled()) {
+ return;
+ }
+ buildStatusEvents(trace, (ControlFlowEntry) child, monitor, start, end);
}
}
- private static List<ITimeEvent> getEventList(ControlFlowEntry entry,
- long startTime, long endTime, long resolution,
- IProgressMonitor monitor) {
- startTime = Math.max(startTime, entry.getStartTime());
- endTime = Math.min(endTime, entry.getEndTime());
- if (endTime <= startTime) {
+ @Override
+ protected @Nullable List<ITimeEvent> getEventList(TimeGraphEntry tgentry, long startTime, long endTime, long resolution, IProgressMonitor monitor) {
+ List<ITimeEvent> eventList = null;
+ if (!(tgentry instanceof ControlFlowEntry)) {
+ return eventList;
+ }
+ ControlFlowEntry entry = (ControlFlowEntry) tgentry;
+ final long realStart = Math.max(startTime, entry.getStartTime());
+ final long realEnd = Math.min(endTime, entry.getEndTime());
+ if (realEnd <= realStart) {
+ return null;
+ }
+ ITmfStateSystem ssq = TmfStateSystemAnalysisModule.getStateSystem(entry.getTrace(), LttngKernelAnalysisModule.ID);
+ if (ssq == null) {
return null;
}
- ITmfStateSystem ssq = entry.getTrace().getStateSystem();
- List<ITimeEvent> eventList = null;
try {
int statusQuark = ssq.getQuarkRelative(entry.getThreadQuark(), Attributes.STATUS);
- List<ITmfStateInterval> statusIntervals = ssq.queryHistoryRange(statusQuark, startTime, endTime - 1, resolution, monitor);
- eventList = new ArrayList<ITimeEvent>(statusIntervals.size());
+ List<ITmfStateInterval> statusIntervals = ssq.queryHistoryRange(statusQuark, realStart, realEnd - 1, resolution, monitor);
+ eventList = new ArrayList<>(statusIntervals.size());
long lastEndTime = -1;
for (ITmfStateInterval statusInterval : statusIntervals) {
if (monitor.isCanceled()) {
e.printStackTrace();
}
if (lastEndTime != time && lastEndTime != -1) {
- eventList.add(new ControlFlowEvent(entry, lastEndTime, time - lastEndTime, 0));
+ eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime));
}
- eventList.add(new ControlFlowEvent(entry, time, duration, status));
+ eventList.add(new TimeEvent(entry, time, duration, status));
lastEndTime = time + duration;
}
- } catch (AttributeNotFoundException e) {
- e.printStackTrace();
- } catch (TimeRangeException e) {
+ } catch (AttributeNotFoundException | TimeRangeException e) {
e.printStackTrace();
+ } catch (StateSystemDisposedException e) {
+ /* Ignored */
}
return eventList;
}
- private void refresh(final long windowRange) {
- Display.getDefault().asyncExec(new Runnable() {
- @Override
- public void run() {
- if (fTimeGraphCombo.isDisposed()) {
- return;
- }
- ITimeGraphEntry[] entries = null;
- synchronized (fEntryListSyncObj) {
- entries = fEntryList.toArray(new ITimeGraphEntry[0]);
+ /**
+ * Returns a value corresponding to the selected entry.
+ *
+ * Used in conjunction with synchingToTime to change the selected entry. If
+ * one of these methods is overridden in child class, then both should be.
+ *
+ * @param time
+ * The currently selected time
+ * @return a value identifying the entry
+ */
+ private int getSelectionValue(long time) {
+ int thread = -1;
+ ITmfTrace[] traces = TmfTraceManager.getTraceSet(getTrace());
+ if (traces == null) {
+ return thread;
+ }
+ for (ITmfTrace trace : traces) {
+ if (thread > 0) {
+ break;
+ }
+ if (trace == null) {
+ continue;
+ }
+ ITmfStateSystem ssq = TmfStateSystemAnalysisModule.getStateSystem(trace, LttngKernelAnalysisModule.ID);
+ if (ssq == null) {
+ continue;
+ }
+ if (time >= ssq.getStartTime() && time <= ssq.getCurrentEndTime()) {
+ List<Integer> currentThreadQuarks = ssq.getQuarks(Attributes.CPUS, "*", Attributes.CURRENT_THREAD); //$NON-NLS-1$
+ for (int currentThreadQuark : currentThreadQuarks) {
+ try {
+ ITmfStateInterval currentThreadInterval = ssq.querySingleState(time, currentThreadQuark);
+ int currentThread = currentThreadInterval.getStateValue().unboxInt();
+ if (currentThread > 0) {
+ int statusQuark = ssq.getQuarkAbsolute(Attributes.THREADS, Integer.toString(currentThread), Attributes.STATUS);
+ ITmfStateInterval statusInterval = ssq.querySingleState(time, statusQuark);
+ if (statusInterval.getStartTime() == time) {
+ thread = currentThread;
+ break;
+ }
+ }
+ } catch (AttributeNotFoundException | TimeRangeException | StateValueTypeException e) {
+ e.printStackTrace();
+ } catch (StateSystemDisposedException e) {
+ /* Ignored */
+ }
}
- Arrays.sort(entries, fControlFlowEntryComparator);
- fTimeGraphCombo.setInput(entries);
- fTimeGraphCombo.getTimeGraphViewer().setTimeBounds(fStartTime, fEndTime);
-
- long endTime = fStartTime + windowRange;
+ }
+ }
+ return thread;
+ }
- if (fEndTime < endTime) {
- endTime = fEndTime;
- }
- fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(fStartTime, endTime);
- for (TreeColumn column : fTimeGraphCombo.getTreeViewer().getTree().getColumns()) {
- column.pack();
+ @Override
+ protected void synchingToTime(long time) {
+ int selected = getSelectionValue(time);
+ if (selected > 0) {
+ for (Object element : getTimeGraphViewer().getExpandedElements()) {
+ if (element instanceof ControlFlowEntry) {
+ ControlFlowEntry entry = (ControlFlowEntry) element;
+ if (entry.getThreadId() == selected) {
+ getTimeGraphCombo().setSelection(entry);
+ break;
+ }
}
-
- startZoomThread(fStartTime, endTime);
}
- });
+ }
}
- private void redraw() {
- synchronized (fSyncObj) {
- if (fRedrawState == State.IDLE) {
- fRedrawState = State.BUSY;
- } else {
- fRedrawState = State.PENDING;
- return;
+ @Override
+ protected List<ILinkEvent> getLinkList(long startTime, long endTime, long resolution, IProgressMonitor monitor) {
+ List<ILinkEvent> list = new ArrayList<>();
+ ITmfTrace[] traces = TmfTraceManager.getTraceSet(getTrace());
+ List<TimeGraphEntry> entryList = getEntryList(getTrace());
+ if (traces == null || entryList == null) {
+ return list;
+ }
+ for (ITmfTrace trace : traces) {
+ if (trace == null) {
+ continue;
}
- }
- Display.getDefault().asyncExec(new Runnable() {
- @Override
- public void run() {
- if (fTimeGraphCombo.isDisposed()) {
- return;
+ ITmfStateSystem ssq = TmfStateSystemAnalysisModule.getStateSystem(trace, LttngKernelAnalysisModule.ID);
+ if (ssq == null) {
+ continue;
+ }
+ try {
+ long start = Math.max(startTime, ssq.getStartTime());
+ long end = Math.min(endTime, ssq.getCurrentEndTime());
+ if (end < start) {
+ continue;
}
- fTimeGraphCombo.redraw();
- fTimeGraphCombo.update();
- synchronized (fSyncObj) {
- if (fRedrawState == State.PENDING) {
- fRedrawState = State.IDLE;
- redraw();
- } else {
- fRedrawState = State.IDLE;
+ List<Integer> currentThreadQuarks = ssq.getQuarks(Attributes.CPUS, "*", Attributes.CURRENT_THREAD); //$NON-NLS-1$
+ for (int currentThreadQuark : currentThreadQuarks) {
+ // adjust the query range to include the previous and following intervals
+ long qstart = Math.max(ssq.querySingleState(start, currentThreadQuark).getStartTime() - 1, ssq.getStartTime());
+ long qend = Math.min(ssq.querySingleState(end, currentThreadQuark).getEndTime() + 1, ssq.getCurrentEndTime());
+ List<ITmfStateInterval> currentThreadIntervals = ssq.queryHistoryRange(currentThreadQuark, qstart, qend, resolution, monitor);
+ int prevThread = 0;
+ long prevEnd = 0;
+ long lastEnd = 0;
+ for (ITmfStateInterval currentThreadInterval : currentThreadIntervals) {
+ if (monitor.isCanceled()) {
+ return null;
+ }
+ long time = currentThreadInterval.getStartTime();
+ if (time != lastEnd) {
+ // don't create links where there are gaps in intervals due to the resolution
+ prevThread = 0;
+ prevEnd = 0;
+ }
+ int thread = currentThreadInterval.getStateValue().unboxInt();
+ if (thread > 0 && prevThread > 0) {
+ ITimeGraphEntry prevEntry = findEntry(entryList, trace, prevThread);
+ ITimeGraphEntry nextEntry = findEntry(entryList, trace, thread);
+ list.add(new TimeLinkEvent(prevEntry, nextEntry, prevEnd, time - prevEnd, 0));
+ }
+ lastEnd = currentThreadInterval.getEndTime() + 1;
+ if (thread != 0) {
+ prevThread = thread;
+ prevEnd = lastEnd;
+ }
}
}
+ } catch (TimeRangeException | AttributeNotFoundException | StateValueTypeException e) {
+ e.printStackTrace();
+ } catch (StateSystemDisposedException e) {
+ /* Ignored */
}
- });
- }
-
- private void startZoomThread(long startTime, long endTime) {
- if (fZoomThread != null) {
- fZoomThread.cancel();
}
- fZoomThread = new ZoomThread(startTime, endTime);
- fZoomThread.start();
- }
-
- private void makeActions() {
- fPreviousResourceAction = fTimeGraphCombo.getTimeGraphViewer().getPreviousItemAction();
- fPreviousResourceAction.setText(Messages.ControlFlowView_previousProcessActionNameText);
- fPreviousResourceAction.setToolTipText(Messages.ControlFlowView_previousProcessActionToolTipText);
- fNextResourceAction = fTimeGraphCombo.getTimeGraphViewer().getNextItemAction();
- fNextResourceAction.setText(Messages.ControlFlowView_nextProcessActionNameText);
- fNextResourceAction.setToolTipText(Messages.ControlFlowView_nextProcessActionToolTipText);
- }
-
- private void contributeToActionBars() {
- IActionBars bars = getViewSite().getActionBars();
- fillLocalToolBar(bars.getToolBarManager());
+ return list;
}
- private void fillLocalToolBar(IToolBarManager manager) {
- manager.add(fTimeGraphCombo.getTimeGraphViewer().getShowLegendAction());
- manager.add(new Separator());
- manager.add(fTimeGraphCombo.getTimeGraphViewer().getResetScaleAction());
- manager.add(fTimeGraphCombo.getTimeGraphViewer().getPreviousEventAction());
- manager.add(fTimeGraphCombo.getTimeGraphViewer().getNextEventAction());
- manager.add(fPreviousResourceAction);
- manager.add(fNextResourceAction);
- manager.add(fTimeGraphCombo.getTimeGraphViewer().getZoomInAction());
- manager.add(fTimeGraphCombo.getTimeGraphViewer().getZoomOutAction());
- manager.add(new Separator());
+ private ControlFlowEntry findEntry(List<? extends ITimeGraphEntry> entryList, ITmfTrace trace, int threadId) {
+ for (ITimeGraphEntry entry : entryList) {
+ if (entry instanceof ControlFlowEntry) {
+ ControlFlowEntry controlFlowEntry = (ControlFlowEntry) entry;
+ if (controlFlowEntry.getThreadId() == threadId && controlFlowEntry.getTrace() == trace) {
+ return controlFlowEntry;
+ } else if (entry.hasChildren()) {
+ controlFlowEntry = findEntry(entry.getChildren(), trace, threadId);
+ if (controlFlowEntry != null) {
+ return controlFlowEntry;
+ }
+ }
+ }
+ }
+ return null;
}
}