X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=org.eclipse.linuxtools.lttng2.kernel.ui%2Fsrc%2Forg%2Feclipse%2Flinuxtools%2Finternal%2Flttng2%2Fkernel%2Fui%2Fviews%2Fcontrolflow%2FControlFlowView.java;h=3627e80aa9e8eff4edb536512fb2f94e6ead7813;hb=374cd3cd1bbe4f765b84b3032ddcfecc4e65f71c;hp=56464358be3021f190b10abb165c96d9d3d29ea6;hpb=b987050f865ecec8052e8323eab4f7bf3f344d2c;p=deliverable%2Ftracecompass.git diff --git a/org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/controlflow/ControlFlowView.java b/org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/controlflow/ControlFlowView.java index 56464358be..3627e80aa9 100644 --- a/org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/controlflow/ControlFlowView.java +++ b/org.eclipse.linuxtools.lttng2.kernel.ui/src/org/eclipse/linuxtools/internal/lttng2/kernel/ui/views/controlflow/ControlFlowView.java @@ -1,729 +1,592 @@ -/******************************************************************************* - * Copyright (c) 2012 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Patrick Tasse - Initial API and implementation - *******************************************************************************/ - -package org.eclipse.linuxtools.internal.lttng2.kernel.ui.views.controlflow; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.jface.action.Action; -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.linuxtools.internal.lttng2.kernel.core.Attributes; -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.ITmfEvent; -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.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.IStateSystemQuerier; -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.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.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; - -public class ControlFlowView extends TmfView { - - // ------------------------------------------------------------------------ - // Constants - // ------------------------------------------------------------------------ - - /** - * View ID. - */ - 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 BIRTH_TIME_COLUMN = Messages.ControlFlowView_birthTimeColumn; - private static final String TRACE_COLUMN = Messages.ControlFlowView_traceColumn; - - private final String[] COLUMN_NAMES = new String[] { - PROCESS_COLUMN, - TID_COLUMN, - PTID_COLUMN, - BIRTH_TIME_COLUMN, - TRACE_COLUMN - }; - - // ------------------------------------------------------------------------ - // Fields - // ------------------------------------------------------------------------ - - // The timegraph combo - private TimeGraphCombo fTimeGraphCombo; - - // The selected experiment - private TmfExperiment fSelectedExperiment; - - // The timegraph entry list - private ArrayList fEntryList; - - // The start time - private long fStartTime; - - // The end time - private long fEndTime; - - // The display width - private 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 ControlFlowEntryComparator fControlFlowEntryComparator = new ControlFlowEntryComparator(); - - // ------------------------------------------------------------------------ - // Classes - // ------------------------------------------------------------------------ - - 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; - return entry.getChildren(); - } - - @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(); - } - - } - - 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 - public void removeListener(ILabelProviderListener listener) { - } - - @Override - public Image getColumnImage(Object element, int columnIndex) { - return null; - } - - @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$ - } - - } - - private static class ControlFlowEntryComparator implements Comparator { - - @Override - public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) { - int result = 0; - - if ((o1 instanceof ControlFlowEntry) && (o2 instanceof ControlFlowEntry)) { - ControlFlowEntry entry1 = (ControlFlowEntry) o1; - ControlFlowEntry entry2 = (ControlFlowEntry) o2; - result = entry1.getTrace().getStartTime().compareTo(entry2.getTrace().getStartTime()); - if (result == 0) { - result = entry1.getThreadId() < entry2.getThreadId() ? -1 : entry1.getThreadId() > entry2.getThreadId() ? 1 : 0; - } - } - - if (result == 0) { - result = o1.getStartTime() < o2.getStartTime() ? -1 : o1.getStartTime() > o2.getStartTime() ? 1 : 0; - } - - return result; - } - } - - - private class ZoomThread extends Thread { - private long fZoomStartTime; - private long fZoomEndTime; - private long fResolution; - private 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(); - } - - @Override - public void run() { - ArrayList entryList = fEntryList; - if (entryList == null) { - return; - } - for (ControlFlowEntry entry : entryList) { - if (fMonitor.isCanceled()) { - return; - } - zoom(entry, fMonitor); - } - redraw(); - } - - private void zoom(ControlFlowEntry entry, IProgressMonitor monitor) { - if (fZoomStartTime <= entry.getStartTime() && fZoomEndTime >= entry.getEndTime()) { - entry.setZoomedEventList(null); - return; - } - List zoomedEventList = getEventList(entry, fZoomStartTime, fZoomEndTime, fResolution, monitor); - if (fMonitor.isCanceled()) { - return; - } - entry.setZoomedEventList(zoomedEventList); - for (ControlFlowEntry child : entry.getChildren()) { - if (fMonitor.isCanceled()) { - return; - } - zoom(child, monitor); - } - } - - public void cancel() { - fMonitor.setCanceled(true); - } - } - - // ------------------------------------------------------------------------ - // Constructors - // ------------------------------------------------------------------------ - - 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(); - } - }); - - fTimeGraphCombo.getTimeGraphViewer().setTimeCalendarFormat(true); - - final Thread thread = new Thread("ControlFlowView build") { //$NON-NLS-1$ - @Override - public void run() { - if (TmfExperiment.getCurrentExperiment() != null) { - selectExperiment(TmfExperiment.getCurrentExperiment()); - } - } - }; - thread.start(); - - // View Action Handling - makeActions(); - contributeToActionBars(); - } - - /* (non-Javadoc) - * @see org.eclipse.ui.part.WorkbenchPart#setFocus() - */ - @Override - public void setFocus() { - fTimeGraphCombo.setFocus(); - } - - // ------------------------------------------------------------------------ - // Signal handlers - // ------------------------------------------------------------------------ - - @TmfSignalHandler - public void experimentSelected(final TmfExperimentSelectedSignal signal) { - if (signal.getExperiment().equals(fSelectedExperiment)) { - return; - } - - final Thread thread = new Thread("ControlFlowView build") { //$NON-NLS-1$ - @Override - public void run() { - selectExperiment(signal.getExperiment()); - } - }; - thread.start(); - } - - @TmfSignalHandler - public void synchToTime(final TmfTimeSynchSignal signal) { - if (signal.getSource() == this) { - return; - } - final long time = signal.getCurrentTime().normalize(0, -9).getValue(); - - int thread = -1; - for (ITmfTrace trace : fSelectedExperiment.getTraces()) { - if (thread > 0) { - break; - } - if (trace instanceof CtfKernelTrace) { - CtfKernelTrace ctfKernelTrace = (CtfKernelTrace) trace; - IStateSystemQuerier ssq = ctfKernelTrace.getStateSystem(); - if (time >= ssq.getStartTime() && time <= ssq.getCurrentEndTime()) { - List 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(); - } - } - } - } - } - final int selectedThread = thread; - - Display.getDefault().asyncExec(new Runnable() { - @Override - public void run() { - if (fTimeGraphCombo.isDisposed()) { - 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); - break; - } - } - } - } - } - }); - } - - @TmfSignalHandler - public void synchToRange(final TmfRangeSynchSignal signal) { - if (signal.getSource() == this) { - 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); - } - }); - } - - @TmfSignalHandler - public void stateSystemBuildCompleted (final TmfStateSystemBuildCompleted signal) { - final TmfExperiment selectedExperiment = fSelectedExperiment; - if (selectedExperiment == 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(); - } - } - } - - // ------------------------------------------------------------------------ - // Internal - // ------------------------------------------------------------------------ - - @SuppressWarnings("unchecked") - private void selectExperiment(TmfExperiment experiment) { - fStartTime = Long.MAX_VALUE; - fEndTime = Long.MIN_VALUE; - fSelectedExperiment = (TmfExperiment) experiment; - ArrayList entryList = new ArrayList(); - for (ITmfTrace trace : experiment.getTraces()) { - if (trace instanceof CtfKernelTrace) { - CtfKernelTrace ctfKernelTrace = (CtfKernelTrace) trace; - IStateSystemQuerier ssq = ctfKernelTrace.getStateSystem(); - long start = ssq.getStartTime(); - long end = ssq.getCurrentEndTime() + 1; - fStartTime = Math.min(fStartTime, start); - fEndTime = Math.max(fEndTime, end); - List 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 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(); - } - } - } - buildTree(entryList); - refresh(INITIAL_WINDOW_OFFSET); - ControlFlowEntry[] entries = fEntryList.toArray(new ControlFlowEntry[0]); - Arrays.sort(entries, fControlFlowEntryComparator); - for (ControlFlowEntry entry : entries) { - buildStatusEvents(entry); - } - } - } - - private void buildTree(ArrayList entryList) { - ArrayList rootList = new ArrayList(); - for (ControlFlowEntry entry : entryList) { - boolean root = true; - if (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; - break; - } - } - } - if (root) { - rootList.add(entry); - } - } - fEntryList = rootList; - } - - private void buildStatusEvents(ControlFlowEntry entry) { - IStateSystemQuerier ssq = entry.getTrace().getStateSystem(); - long start = ssq.getStartTime(); - long end = ssq.getCurrentEndTime() + 1; - long resolution = Math.max(1, (end - start) / fDisplayWidth); - List eventList = getEventList(entry, entry.getStartTime(), entry.getEndTime(), resolution, new NullProgressMonitor()); - entry.setEventList(eventList); - redraw(); - for (ITimeGraphEntry child : entry.getChildren()) { - buildStatusEvents((ControlFlowEntry) child); - } - } - - private List 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) { - return null; - } - IStateSystemQuerier ssq = entry.getTrace().getStateSystem(); - List eventList = null; - try { - int statusQuark = ssq.getQuarkRelative(entry.getThreadQuark(), Attributes.STATUS); - List statusIntervals = ssq.queryHistoryRange(statusQuark, startTime, endTime - 1, resolution); - eventList = new ArrayList(statusIntervals.size()); - long lastEndTime = -1; - for (ITmfStateInterval statusInterval : statusIntervals) { - if (monitor.isCanceled()) { - return null; - } - long time = statusInterval.getStartTime(); - long duration = statusInterval.getEndTime() - time + 1; - int status = -1; - try { - status = statusInterval.getStateValue().unboxInt(); - } catch (StateValueTypeException e) { - e.printStackTrace(); - } - if (lastEndTime != time && lastEndTime != -1) { - eventList.add(new ControlFlowEvent(entry, lastEndTime, time - lastEndTime, 0)); - } - eventList.add(new ControlFlowEvent(entry, time, duration, status)); - lastEndTime = time + duration; - } - } catch (AttributeNotFoundException e) { - e.printStackTrace(); - } catch (TimeRangeException e) { - e.printStackTrace(); - } - return eventList; - } - - private void refresh(final long windowRange) { - Display.getDefault().asyncExec(new Runnable() { - @Override - public void run() { - if (fTimeGraphCombo.isDisposed()) { - return; - } - ITimeGraphEntry[] entries = fEntryList.toArray(new ITimeGraphEntry[0]); - Arrays.sort(entries, fControlFlowEntryComparator); - fTimeGraphCombo.setInput(entries); - fTimeGraphCombo.getTimeGraphViewer().setTimeBounds(fStartTime, fEndTime); - - long endTime = fStartTime + windowRange; - - if (fEndTime < endTime) { - endTime = fEndTime; - } - fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(fStartTime, endTime); - for (TreeColumn column : fTimeGraphCombo.getTreeViewer().getTree().getColumns()) { - column.pack(); - } - - startZoomThread(fStartTime, endTime); - } - }); - } - - private void redraw() { - Display.getDefault().asyncExec(new Runnable() { - @Override - public void run() { - if (fTimeGraphCombo.isDisposed()) { - return; - } - fTimeGraphCombo.redraw(); - fTimeGraphCombo.update(); - } - }); - } - - 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()); - } - - 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()); - } -} +/******************************************************************************* + * 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 + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * 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.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IToolBarManager; +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.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.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; + +/** + * The Control Flow view main object + * + */ +public class ControlFlowView extends AbstractTimeGraphView { + + // ------------------------------------------------------------------------ + // Constants + // ------------------------------------------------------------------------ + + /** + * View ID. + */ + public static final String ID = "org.eclipse.linuxtools.lttng2.kernel.ui.views.controlflow"; //$NON-NLS-1$ + + 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[] COLUMN_NAMES = new String[] { + PROCESS_COLUMN, + TID_COLUMN, + PTID_COLUMN, + BIRTH_TIME_COLUMN, + TRACE_COLUMN + }; + + private static final String[] FILTER_COLUMN_NAMES = new String[] { + PROCESS_COLUMN, + TID_COLUMN + }; + + // Timeout between updates in the build thread in ms + private static final long BUILD_UPDATE_TIMEOUT = 500; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructor + */ + public ControlFlowView() { + super(ID, new ControlFlowPresentationProvider()); + setTreeColumns(COLUMN_NAMES); + setTreeLabelProvider(new ControlFlowTreeLabelProvider()); + setFilterColumns(FILTER_COLUMN_NAMES); + setFilterLabelProvider(new ControlFlowFilterLabelProvider()); + setEntryComparator(new ControlFlowEntryComparator()); + } + + @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 + protected String getNextText() { + return Messages.ControlFlowView_nextProcessActionNameText; + } + + @Override + protected String getNextTooltip() { + return Messages.ControlFlowView_nextProcessActionToolTipText; + } + + @Override + protected String getPrevText() { + return Messages.ControlFlowView_previousProcessActionNameText; + } + + @Override + protected String getPrevTooltip() { + return Messages.ControlFlowView_previousProcessActionToolTipText; + } + + private static class ControlFlowEntryComparator implements Comparator { + + @Override + public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) { + + int result = 0; + + if ((o1 instanceof ControlFlowEntry) && (o2 instanceof ControlFlowEntry)) { + ControlFlowEntry entry1 = (ControlFlowEntry) o1; + ControlFlowEntry entry2 = (ControlFlowEntry) o2; + result = entry1.getTrace().getStartTime().compareTo(entry2.getTrace().getStartTime()); + if (result == 0) { + result = entry1.getTrace().getName().compareTo(entry2.getTrace().getName()); + } + if (result == 0) { + result = entry1.getThreadId() < entry2.getThreadId() ? -1 : entry1.getThreadId() > entry2.getThreadId() ? 1 : 0; + } + } + + if (result == 0) { + result = o1.getStartTime() < o2.getStartTime() ? -1 : o1.getStartTime() > o2.getStartTime() ? 1 : 0; + } + + return result; + } + } + + /** + * @author gbastien + * + */ + protected static class ControlFlowTreeLabelProvider extends TreeLabelProvider { + + @Override + public String getColumnText(Object element, int columnIndex) { + ControlFlowEntry entry = (ControlFlowEntry) element; + + 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()); + } + } 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$ + } + + } + + private static class ControlFlowFilterLabelProvider extends TreeLabelProvider { + + @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()); + } + return ""; //$NON-NLS-1$ + } + + } + + // ------------------------------------------------------------------------ + // Internal + // ------------------------------------------------------------------------ + + @Override + protected void buildEventList(final ITmfTrace trace, ITmfTrace parentTrace, IProgressMonitor monitor) { + if (trace == null) { + return; + } + ITmfStateSystem ssq = TmfStateSystemAnalysisModule.getStateSystem(trace, LttngKernelAnalysisModule.ID); + if (ssq == null) { + return; + } + + List entryList = new ArrayList<>(); + Map entryMap = new HashMap<>(); + + long start = ssq.getStartTime(); + setStartTime(Math.min(getStartTime(), start)); + + boolean complete = false; + while (!complete) { + if (monitor.isCanceled()) { + return; + } + complete = ssq.waitUntilBuilt(BUILD_UPDATE_TIMEOUT); + if (ssq.isCancelled()) { + return; + } + 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 threadQuarks = ssq.getQuarks(Attributes.THREADS, "*"); //$NON-NLS-1$ + for (int threadQuark : threadQuarks) { + if (monitor.isCanceled()) { + return; + } + 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 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); + } + } + } + + updateTree(entryList, parentTrace); + + if (parentTrace.equals(getTrace())) { + refresh(); + } + + for (ControlFlowEntry entry : entryList) { + if (monitor.isCanceled()) { + return; + } + buildStatusEvents(entry.getTrace(), entry, monitor, start, end); + } + + start = end; + } + } + + private void updateTree(List entryList, ITmfTrace parentTrace) { + List rootListToAdd = new ArrayList<>(); + List rootListToRemove = new ArrayList<>(); + List rootList = getEntryList(parentTrace); + + for (ControlFlowEntry entry : entryList) { + 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 == null || !rootList.contains(entry))) { + rootListToAdd.add(entry); + } + } + + addToEntryList(parentTrace, rootListToAdd); + removeFromEntryList(parentTrace, rootListToRemove); + } + + 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 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()) { + if (monitor.isCanceled()) { + return; + } + buildStatusEvents(trace, (ControlFlowEntry) child, monitor, start, end); + } + } + + @Override + protected @Nullable List getEventList(TimeGraphEntry tgentry, long startTime, long endTime, long resolution, IProgressMonitor monitor) { + List 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; + } + try { + int statusQuark = ssq.getQuarkRelative(entry.getThreadQuark(), Attributes.STATUS); + List statusIntervals = ssq.queryHistoryRange(statusQuark, realStart, realEnd - 1, resolution, monitor); + eventList = new ArrayList<>(statusIntervals.size()); + long lastEndTime = -1; + for (ITmfStateInterval statusInterval : statusIntervals) { + if (monitor.isCanceled()) { + return null; + } + long time = statusInterval.getStartTime(); + long duration = statusInterval.getEndTime() - time + 1; + int status = -1; + try { + status = statusInterval.getStateValue().unboxInt(); + } catch (StateValueTypeException e) { + e.printStackTrace(); + } + if (lastEndTime != time && lastEndTime != -1) { + eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime)); + } + eventList.add(new TimeEvent(entry, time, duration, status)); + lastEndTime = time + duration; + } + } catch (AttributeNotFoundException | TimeRangeException e) { + e.printStackTrace(); + } catch (StateSystemDisposedException e) { + /* Ignored */ + } + return eventList; + } + + /** + * 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 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 */ + } + } + } + } + return thread; + } + + @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; + } + } + } + } + } + + @Override + protected List getLinkList(long startTime, long endTime, long resolution, IProgressMonitor monitor) { + List list = new ArrayList<>(); + ITmfTrace[] traces = TmfTraceManager.getTraceSet(getTrace()); + List entryList = getEntryList(getTrace()); + if (traces == null || entryList == null) { + return list; + } + for (ITmfTrace trace : traces) { + if (trace == null) { + continue; + } + 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; + } + List 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 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 */ + } + } + return list; + } + + private ControlFlowEntry findEntry(List 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; + } +}