-/*******************************************************************************\r
- * Copyright (c) 2012 Ericsson\r
- * \r
- * All rights reserved. This program and the accompanying materials are\r
- * made available under the terms of the Eclipse Public License v1.0 which\r
- * accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- * \r
- * Contributors:\r
- * Patrick Tasse - Initial API and implementation\r
- *******************************************************************************/\r
-\r
-package org.eclipse.linuxtools.internal.lttng2.kernel.ui.views.controlflow;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-import java.util.HashMap;\r
-import java.util.List;\r
-import java.util.Map;\r
-\r
-import org.eclipse.jface.action.Action;\r
-import org.eclipse.jface.action.IToolBarManager;\r
-import org.eclipse.jface.action.Separator;\r
-import org.eclipse.jface.viewers.ILabelProviderListener;\r
-import org.eclipse.jface.viewers.ITableLabelProvider;\r
-import org.eclipse.jface.viewers.ITreeContentProvider;\r
-import org.eclipse.jface.viewers.Viewer;\r
-import org.eclipse.linuxtools.internal.lttng2.kernel.ui.Messages;\r
-import org.eclipse.linuxtools.lttng2.kernel.core.trace.Attributes;\r
-import org.eclipse.linuxtools.lttng2.kernel.core.trace.CtfKernelTrace;\r
-import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfTmfTimestamp;\r
-import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;\r
-import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;\r
-import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;\r
-import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;\r
-import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;\r
-import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;\r
-import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;\r
-import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentSelectedSignal;\r
-import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal;\r
-import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;\r
-import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;\r
-import org.eclipse.linuxtools.tmf.core.statesystem.IStateSystemQuerier;\r
-import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;\r
-import org.eclipse.linuxtools.tmf.core.trace.TmfExperiment;\r
-import org.eclipse.linuxtools.tmf.ui.views.TmfView;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphRangeListener;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphSelectionListener;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.StateItem;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphCombo;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphRangeUpdateEvent;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphSelectionEvent;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphTimeEvent;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeEvent;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.TimeEvent;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils.Resolution;\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.graphics.Image;\r
-import org.eclipse.swt.graphics.RGB;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Display;\r
-import org.eclipse.swt.widgets.TreeColumn;\r
-import org.eclipse.ui.IActionBars;\r
-\r
-public class ControlFlowView extends TmfView {\r
-\r
- // ------------------------------------------------------------------------\r
- // Constants\r
- // ------------------------------------------------------------------------\r
-\r
- /**\r
- * View ID.\r
- */\r
- public static final String ID = "org.eclipse.linuxtools.lttng2.kernel.ui.views.controlflow"; //$NON-NLS-1$\r
-\r
- private static final String PROCESS_COLUMN = Messages.ControlFlowView_processColumn;\r
- private static final String TID_COLUMN = Messages.ControlFlowView_tidColumn;\r
- private static final String PPID_COLUMN = Messages.ControlFlowView_ppidColumn;\r
- private static final String BIRTH_TIME_COLUMN = Messages.ControlFlowView_birthTimeColumn;\r
- private static final String TRACE_COLUMN = Messages.ControlFlowView_traceColumn;\r
-\r
- private final String[] COLUMN_NAMES = new String[] {\r
- PROCESS_COLUMN,\r
- TID_COLUMN,\r
- PPID_COLUMN,\r
- BIRTH_TIME_COLUMN,\r
- TRACE_COLUMN\r
- };\r
-\r
- // ------------------------------------------------------------------------\r
- // Fields\r
- // ------------------------------------------------------------------------\r
-\r
- // The timegraph combo\r
- private TimeGraphCombo fTimeGraphCombo;\r
-\r
- // The selected experiment\r
- private TmfExperiment<ITmfEvent> fSelectedExperiment;\r
-\r
- // The timegraph entry list\r
- private ArrayList<ControlFlowEntry> fEntryList;\r
-\r
- // The start time\r
- private long fStartTime;\r
-\r
- // The end time\r
- private long fEndTime;\r
-\r
- // The display width\r
- private int fDisplayWidth;\r
-\r
- // The zoom thread\r
- private ZoomThread fZoomThread;\r
- \r
- // The next resource action\r
- private Action fNextResourceAction;\r
- \r
- // The previous resource action\r
- private Action fPreviousResourceAction;\r
-\r
- // ------------------------------------------------------------------------\r
- // Classes\r
- // ------------------------------------------------------------------------\r
-\r
- private class TreeContentProvider implements ITreeContentProvider {\r
-\r
- @Override\r
- public void dispose() {\r
- }\r
-\r
- @Override\r
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
- }\r
-\r
- @Override\r
- public Object[] getElements(Object inputElement) {\r
- return (ITimeGraphEntry[]) inputElement;\r
- }\r
-\r
- @Override\r
- public Object[] getChildren(Object parentElement) {\r
- ITimeGraphEntry entry = (ITimeGraphEntry) parentElement;\r
- return entry.getChildren();\r
- }\r
-\r
- @Override\r
- public Object getParent(Object element) {\r
- ITimeGraphEntry entry = (ITimeGraphEntry) element;\r
- return entry.getParent();\r
- }\r
-\r
- @Override\r
- public boolean hasChildren(Object element) {\r
- ITimeGraphEntry entry = (ITimeGraphEntry) element;\r
- return entry.hasChildren();\r
- }\r
- \r
- }\r
-\r
- private class TreeLabelProvider implements ITableLabelProvider {\r
-\r
- @Override\r
- public void addListener(ILabelProviderListener listener) {\r
- }\r
-\r
- @Override\r
- public void dispose() {\r
- }\r
-\r
- @Override\r
- public boolean isLabelProperty(Object element, String property) {\r
- return false;\r
- }\r
-\r
- @Override\r
- public void removeListener(ILabelProviderListener listener) {\r
- }\r
-\r
- @Override\r
- public Image getColumnImage(Object element, int columnIndex) {\r
- return null;\r
- }\r
-\r
- @Override\r
- public String getColumnText(Object element, int columnIndex) {\r
- ControlFlowEntry entry = (ControlFlowEntry) element;\r
- if (columnIndex == 0) {\r
- return entry.getName();\r
- } else if (columnIndex == 1) {\r
- return Integer.toString(entry.getThreadId());\r
- } else if (columnIndex == 2) {\r
- if (entry.getPPID() > 0) {\r
- return Integer.toString(entry.getPPID());\r
- }\r
- } else if (columnIndex == 3) {\r
- return Utils.formatTime(entry.getBirthTime(), TimeFormat.ABSOLUTE, Resolution.NANOSEC);\r
- } else if (columnIndex == 4) {\r
- return entry.getTrace().getName();\r
- }\r
- return ""; //$NON-NLS-1$\r
- }\r
- \r
- }\r
-\r
- private class ZoomThread extends Thread {\r
- private long fStartTime;\r
- private long fEndTime;\r
- private long fResolution;\r
- private boolean fCancelled = false;\r
-\r
- public ZoomThread(long startTime, long endTime) {\r
- super("ControlFlowView zoom"); //$NON-NLS-1$\r
- fStartTime = startTime;\r
- fEndTime = endTime;\r
- fResolution = Math.max(1, (fEndTime - fStartTime) / fDisplayWidth);\r
- }\r
-\r
- @Override\r
- public void run() {\r
- if (fEntryList == null) {\r
- return;\r
- }\r
- for (ControlFlowEntry entry : fEntryList) {\r
- if (fCancelled) {\r
- return;\r
- }\r
- zoom(entry);\r
- }\r
- redraw();\r
- }\r
-\r
- private void zoom(ControlFlowEntry entry) {\r
- List<ITimeEvent> zoomedEventList = getEventList(entry, fStartTime, fEndTime, fResolution);\r
- entry.setZoomedEventList(zoomedEventList);\r
- for (ControlFlowEntry child : entry.getChildren()) {\r
- if (fCancelled) {\r
- return;\r
- }\r
- zoom(child);\r
- }\r
- }\r
-\r
- public void cancel() {\r
- fCancelled = true;\r
- }\r
- }\r
-\r
- // ------------------------------------------------------------------------\r
- // Constructors\r
- // ------------------------------------------------------------------------\r
-\r
- public ControlFlowView() {\r
- super(ID);\r
- fDisplayWidth = Display.getDefault().getBounds().width;\r
- }\r
-\r
- // ------------------------------------------------------------------------\r
- // ViewPart\r
- // ------------------------------------------------------------------------\r
-\r
- /* (non-Javadoc)\r
- * @see org.eclipse.linuxtools.tmf.ui.views.TmfView#createPartControl(org.eclipse.swt.widgets.Composite)\r
- */\r
- @Override\r
- public void createPartControl(Composite parent) {\r
- fTimeGraphCombo = new TimeGraphCombo(parent, SWT.NONE);\r
-\r
- fTimeGraphCombo.setTreeContentProvider(new TreeContentProvider());\r
-\r
- fTimeGraphCombo.setTreeLabelProvider(new TreeLabelProvider());\r
-\r
- fTimeGraphCombo.setTimeGraphProvider(new TimeGraphPresentationProvider() {\r
- private static final String UNKNOWN = "UNKNOWN"; //$NON-NLS-1$\r
- private static final String WAIT = "WAIT"; //$NON-NLS-1$\r
- private static final String USERMODE = "USERMODE"; //$NON-NLS-1$\r
- private static final String SYSCALL = "SYSCALL"; //$NON-NLS-1$\r
- private static final String INTERRUPTED = "INTERRUPTED"; //$NON-NLS-1$\r
-\r
- @Override \r
- public String getStateTypeName() {\r
- return Messages.ControlFlowView_stateTypeName;\r
- }\r
- \r
- @Override\r
- public StateItem[] getStateTable() {\r
- return new StateItem[] {\r
- new StateItem(new RGB(100, 100, 100), UNKNOWN),\r
- new StateItem(new RGB(150, 150, 0), WAIT),\r
- new StateItem(new RGB(0, 200, 0), USERMODE),\r
- new StateItem(new RGB(0, 0, 200), SYSCALL),\r
- new StateItem(new RGB(200, 100, 100), INTERRUPTED)\r
- };\r
- }\r
-\r
- @Override\r
- public int getEventTableIndex(ITimeEvent event) {\r
- if (event instanceof ControlFlowEvent) {\r
- int status = ((ControlFlowEvent) event).getStatus();\r
- if (status == Attributes.STATUS_WAIT) {\r
- return 1;\r
- } else if (status == Attributes.STATUS_RUN_USERMODE) {\r
- return 2;\r
- } else if (status == Attributes.STATUS_RUN_SYSCALL) {\r
- return 3;\r
- } else if (status == Attributes.STATUS_INTERRUPTED) {\r
- return 4;\r
- }\r
- }\r
- return 0;\r
- }\r
-\r
- @Override\r
- public String getEventName(ITimeEvent event) {\r
- if (event instanceof ControlFlowEvent) {\r
- int status = ((ControlFlowEvent) event).getStatus();\r
- if (status == Attributes.STATUS_WAIT) {\r
- return WAIT;\r
- } else if (status == Attributes.STATUS_RUN_USERMODE) {\r
- return USERMODE;\r
- } else if (status == Attributes.STATUS_RUN_SYSCALL) {\r
- return SYSCALL;\r
- } else if (status == Attributes.STATUS_INTERRUPTED) {\r
- return INTERRUPTED;\r
- }\r
- }\r
- return UNKNOWN;\r
- }\r
- \r
- @Override\r
- public Map<String, String> getEventHoverToolTipInfo(ITimeEvent event) {\r
- return new HashMap<String, String>();\r
- }\r
- });\r
-\r
- fTimeGraphCombo.setTreeColumns(COLUMN_NAMES);\r
-\r
- fTimeGraphCombo.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {\r
- @Override\r
- public void timeRangeUpdated(TimeGraphRangeUpdateEvent event) {\r
- final long startTime = event.getStartTime();\r
- final long endTime = event.getEndTime();\r
- TmfTimeRange range = new TmfTimeRange(new CtfTmfTimestamp(startTime), new CtfTmfTimestamp(endTime));\r
- TmfTimestamp time = new CtfTmfTimestamp(fTimeGraphCombo.getTimeGraphViewer().getSelectedTime());\r
- broadcast(new TmfRangeSynchSignal(ControlFlowView.this, range, time));\r
- if (fZoomThread != null) {\r
- fZoomThread.cancel();\r
- }\r
- fZoomThread = new ZoomThread(startTime, endTime);\r
- fZoomThread.start();\r
- }\r
- });\r
-\r
- fTimeGraphCombo.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {\r
- @Override\r
- public void timeSelected(TimeGraphTimeEvent event) {\r
- long time = event.getTime();\r
- broadcast(new TmfTimeSynchSignal(ControlFlowView.this, new CtfTmfTimestamp(time)));\r
- }\r
- });\r
-\r
- fTimeGraphCombo.addSelectionListener(new ITimeGraphSelectionListener() {\r
- @Override\r
- public void selectionChanged(TimeGraphSelectionEvent event) {\r
- //ITimeGraphEntry selection = event.getSelection();\r
- }\r
- });\r
-\r
- fTimeGraphCombo.getTimeGraphViewer().setTimeCalendarFormat(true);\r
-\r
- final Thread thread = new Thread("ControlFlowView build") { //$NON-NLS-1$\r
- @Override\r
- public void run() {\r
- if (TmfExperiment.getCurrentExperiment() != null) {\r
- selectExperiment(TmfExperiment.getCurrentExperiment());\r
- }\r
- }\r
- };\r
- thread.start();\r
- \r
- // View Action Handling\r
- makeActions();\r
- contributeToActionBars();\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see org.eclipse.ui.part.WorkbenchPart#setFocus()\r
- */\r
- @Override\r
- public void setFocus() {\r
- fTimeGraphCombo.setFocus();\r
- }\r
-\r
- // ------------------------------------------------------------------------\r
- // Signal handlers\r
- // ------------------------------------------------------------------------\r
-\r
- @TmfSignalHandler\r
- public void experimentSelected(final TmfExperimentSelectedSignal<? extends ITmfEvent> signal) {\r
- if (signal.getExperiment().equals(fSelectedExperiment)) {\r
- return;\r
- }\r
-\r
- final Thread thread = new Thread("ControlFlowView build") { //$NON-NLS-1$\r
- @Override\r
- public void run() {\r
- selectExperiment(signal.getExperiment());\r
- }};\r
- thread.start();\r
- }\r
-\r
- @TmfSignalHandler\r
- public void synchToTime(final TmfTimeSynchSignal signal) {\r
- if (signal.getSource() == this) {\r
- return;\r
- }\r
- final long time = signal.getCurrentTime().normalize(0, -9).getValue();\r
- Display.getDefault().asyncExec(new Runnable() {\r
- @Override\r
- public void run() {\r
- if (fTimeGraphCombo.isDisposed()) {\r
- return;\r
- }\r
- fTimeGraphCombo.getTimeGraphViewer().setSelectedTime(time, true, signal.getSource());\r
- }\r
- });\r
- }\r
-\r
- @TmfSignalHandler\r
- public void synchToRange(final TmfRangeSynchSignal signal) {\r
- if (signal.getSource() == this) {\r
- return;\r
- }\r
- final long startTime = signal.getCurrentRange().getStartTime().normalize(0, -9).getValue();\r
- final long endTime = signal.getCurrentRange().getEndTime().normalize(0, -9).getValue();\r
- final long time = signal.getCurrentTime().normalize(0, -9).getValue();\r
- Display.getDefault().asyncExec(new Runnable() {\r
- @Override\r
- public void run() {\r
- if (fTimeGraphCombo.isDisposed()) {\r
- return;\r
- }\r
- fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(startTime, endTime);\r
- fTimeGraphCombo.getTimeGraphViewer().setSelectedTime(time, false, signal.getSource());\r
- }\r
- });\r
- }\r
-\r
- // ------------------------------------------------------------------------\r
- // Internal\r
- // ------------------------------------------------------------------------\r
-\r
- @SuppressWarnings("unchecked")\r
- private void selectExperiment(TmfExperiment<?> experiment) {\r
- fStartTime = Long.MAX_VALUE;\r
- fEndTime = Long.MIN_VALUE;\r
- fSelectedExperiment = (TmfExperiment<ITmfEvent>) experiment;\r
- fEntryList = new ArrayList<ControlFlowEntry>();\r
- for (ITmfTrace<?> trace : experiment.getTraces()) {\r
- if (trace instanceof CtfKernelTrace) {\r
- CtfKernelTrace ctfKernelTrace = (CtfKernelTrace) trace;\r
- IStateSystemQuerier ssq = ctfKernelTrace.getStateSystem();\r
- long start = ssq.getStartTime();\r
- long end = ssq.getCurrentEndTime();\r
- fStartTime = Math.min(fStartTime, start);\r
- fEndTime = Math.max(fEndTime, end);\r
- List<Integer> threadQuarks = ssq.getQuarks(Attributes.THREADS, "*"); //$NON-NLS-1$\r
- for (int threadQuark : threadQuarks) {\r
- String threadName = ssq.getAttributeName(threadQuark);\r
- int threadId = -1;\r
- try {\r
- threadId = Integer.parseInt(threadName);\r
- } catch (NumberFormatException e1) {\r
- continue;\r
- }\r
- if (threadId == 0) { // ignore the swapper thread\r
- continue;\r
- }\r
- int execNameQuark = -1;\r
- try {\r
- try {\r
- execNameQuark = ssq.getQuarkRelative(threadQuark, Attributes.EXEC_NAME);\r
- } catch (AttributeNotFoundException e) {\r
- continue;\r
- }\r
- int ppidQuark = ssq.getQuarkRelative(threadQuark, Attributes.PPID);\r
- List<ITmfStateInterval> execNameIntervals = ssq.queryHistoryRange(execNameQuark, start, end);\r
- long birthTime = -1;\r
- for (ITmfStateInterval execNameInterval : execNameIntervals) {\r
- if (!execNameInterval.getStateValue().isNull() && execNameInterval.getStateValue().getType() == 1) {\r
- String execName = execNameInterval.getStateValue().unboxStr();\r
- long startTime = execNameInterval.getStartTime();\r
- long endTime = execNameInterval.getEndTime() + 1;\r
- if (birthTime == -1) {\r
- birthTime = startTime;\r
- }\r
- int ppid = -1;\r
- if (ppidQuark != -1) {\r
- ITmfStateInterval ppidInterval = ssq.querySingleState(startTime, ppidQuark);\r
- ppid = ppidInterval.getStateValue().unboxInt();\r
- }\r
- ControlFlowEntry entry = new ControlFlowEntry(threadQuark, ctfKernelTrace, execName, threadId, ppid, birthTime, startTime, endTime);\r
- fEntryList.add(entry);\r
- entry.addEvent(new TimeEvent(entry, startTime, endTime - startTime));\r
- } else {\r
- birthTime = -1;\r
- }\r
- }\r
- } catch (AttributeNotFoundException e) {\r
- e.printStackTrace();\r
- } catch (TimeRangeException e) {\r
- e.printStackTrace();\r
- } catch (StateValueTypeException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
- }\r
- buildTree();\r
- refresh();\r
- ControlFlowEntry[] entries = fEntryList.toArray(new ControlFlowEntry[0]);\r
- Arrays.sort(entries);\r
- for (ControlFlowEntry entry : entries) {\r
- buildStatusEvents(entry);\r
- }\r
- }\r
- }\r
-\r
- private void buildTree() {\r
- ArrayList<ControlFlowEntry> rootList = new ArrayList<ControlFlowEntry>();\r
- for (ControlFlowEntry entry : fEntryList) {\r
- boolean root = true;\r
- if (entry.getPPID() > 0) {\r
- for (ControlFlowEntry parent : fEntryList) {\r
- if (parent.getThreadId() == entry.getPPID() &&\r
- entry.getStartTime() >= parent.getStartTime() &&\r
- entry.getStartTime() <= parent.getEndTime()) {\r
- parent.addChild(entry);\r
- root = false;\r
- break;\r
- }\r
- }\r
- }\r
- if (root) {\r
- rootList.add(entry);\r
- }\r
- }\r
- fEntryList = rootList;\r
- }\r
-\r
- private void buildStatusEvents(ControlFlowEntry entry) {\r
- IStateSystemQuerier ssq = entry.getTrace().getStateSystem();\r
- long start = ssq.getStartTime();\r
- long end = ssq.getCurrentEndTime();\r
- long resolution = Math.max(1, (end - start) / fDisplayWidth);\r
- List<ITimeEvent> eventList = getEventList(entry, entry.getStartTime(), entry.getEndTime(), resolution);\r
- entry.setEventList(eventList);\r
- redraw();\r
- for (ITimeGraphEntry child : entry.getChildren()) {\r
- buildStatusEvents((ControlFlowEntry) child);\r
- }\r
- }\r
-\r
- private List<ITimeEvent> getEventList(ControlFlowEntry entry, long startTime, long endTime, long resolution) {\r
- startTime = Math.max(startTime, entry.getStartTime());\r
- endTime = Math.min(endTime, entry.getEndTime());\r
- if (endTime <= startTime) {\r
- return null;\r
- }\r
- IStateSystemQuerier ssq = entry.getTrace().getStateSystem();\r
- List<ITimeEvent> eventList = null;\r
- try {\r
- int statusQuark = ssq.getQuarkRelative(entry.getThreadQuark(), Attributes.STATUS);\r
- List<ITmfStateInterval> statusIntervals = ssq.queryHistoryRange(statusQuark, startTime, endTime - 1, resolution);\r
- eventList = new ArrayList<ITimeEvent>(statusIntervals.size());\r
- long lastEndTime = -1;\r
- for (ITmfStateInterval statusInterval : statusIntervals) {\r
- long time = statusInterval.getStartTime();\r
- long duration = statusInterval.getEndTime() - time + 1;\r
- int status = -1;\r
- try {\r
- status = statusInterval.getStateValue().unboxInt();\r
- } catch (StateValueTypeException e) {\r
- e.printStackTrace();\r
- }\r
- if (lastEndTime != time && lastEndTime != -1) {\r
- eventList.add(new ControlFlowEvent(entry, lastEndTime, time - lastEndTime, 0));\r
- }\r
- eventList.add(new ControlFlowEvent(entry, time, duration, status));\r
- lastEndTime = time + duration;\r
- }\r
- } catch (AttributeNotFoundException e) {\r
- e.printStackTrace();\r
- } catch (TimeRangeException e) {\r
- e.printStackTrace();\r
- }\r
- return eventList;\r
- }\r
-\r
- private void refresh() {\r
- Display.getDefault().asyncExec(new Runnable() {\r
- @Override\r
- public void run() {\r
- if (fTimeGraphCombo.isDisposed()) {\r
- return;\r
- }\r
- ITimeGraphEntry[] entries = fEntryList.toArray(new ITimeGraphEntry[0]);\r
- Arrays.sort(entries);\r
- fTimeGraphCombo.setInput(entries);\r
- fTimeGraphCombo.getTimeGraphViewer().setTimeBounds(fStartTime, fEndTime);\r
- fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(fStartTime, fEndTime);\r
- for (TreeColumn column : fTimeGraphCombo.getTreeViewer().getTree().getColumns()) {\r
- column.pack();\r
- }\r
- }\r
- });\r
- }\r
-\r
- private void redraw() {\r
- Display.getDefault().asyncExec(new Runnable() {\r
- @Override\r
- public void run() {\r
- if (fTimeGraphCombo.isDisposed()) {\r
- return;\r
- }\r
- fTimeGraphCombo.redraw();\r
- fTimeGraphCombo.update();\r
- }\r
- });\r
- }\r
-\r
- private void makeActions() {\r
- fPreviousResourceAction = fTimeGraphCombo.getTimeGraphViewer().getPreviousItemAction();\r
- fPreviousResourceAction.setText(Messages.ControlFlowView_previousProcessActionNameText);\r
- fPreviousResourceAction.setToolTipText(Messages.ControlFlowView_previousProcessActionToolTipText);\r
- fNextResourceAction = fTimeGraphCombo.getTimeGraphViewer().getNextItemAction();\r
- fNextResourceAction.setText(Messages.ControlFlowView_nextProcessActionNameText);\r
- fNextResourceAction.setToolTipText(Messages.ControlFlowView_nextProcessActionToolTipText);\r
- }\r
- \r
- private void contributeToActionBars() {\r
- IActionBars bars = getViewSite().getActionBars();\r
- fillLocalToolBar(bars.getToolBarManager());\r
- }\r
-\r
- private void fillLocalToolBar(IToolBarManager manager) {\r
- manager.add(fTimeGraphCombo.getTimeGraphViewer().getShowLegendAction());\r
- manager.add(new Separator());\r
- manager.add(fTimeGraphCombo.getTimeGraphViewer().getResetScaleAction());\r
- manager.add(fTimeGraphCombo.getTimeGraphViewer().getPreviousEventAction());\r
- manager.add(fTimeGraphCombo.getTimeGraphViewer().getNextEventAction());\r
- manager.add(fPreviousResourceAction);\r
- manager.add(fNextResourceAction);\r
- manager.add(fTimeGraphCombo.getTimeGraphViewer().getZoomInAction());\r
- manager.add(fTimeGraphCombo.getTimeGraphViewer().getZoomOutAction());\r
- manager.add(new Separator());\r
- }\r
-}\r
+/*******************************************************************************
+ * 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.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.tmf.core.exceptions.AttributeNotFoundException;
+import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException;
+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.statesystem.ITmfStateSystem;
+import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
+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<ITimeGraphEntry> {
+
+ @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) {
+ LttngKernelAnalysisModule module = trace.getAnalysisModuleOfClass(LttngKernelAnalysisModule.class, LttngKernelAnalysisModule.ID);
+ if (module == null) {
+ return;
+ }
+ module.schedule();
+ module.waitForInitialization();
+ ITmfStateSystem ssq = module.getStateSystem();
+ if (ssq == null) {
+ return;
+ }
+
+ 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;
+ }
+ 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<Integer> 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<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);
+ }
+ }
+ }
+
+ 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<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 = (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()) {
+ LttngKernelAnalysisModule module = entry.getTrace().getAnalysisModuleOfClass(LttngKernelAnalysisModule.class, LttngKernelAnalysisModule.ID);
+ if (module == null) {
+ return;
+ }
+ ITmfStateSystem ssq = module.getStateSystem();
+ 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 (monitor.isCanceled()) {
+ 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 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;
+ }
+ LttngKernelAnalysisModule module = entry.getTrace().getAnalysisModuleOfClass(LttngKernelAnalysisModule.class, LttngKernelAnalysisModule.ID);
+ if (module == null) {
+ return null;
+ }
+ ITmfStateSystem ssq = module.getStateSystem();
+ if (ssq == null) {
+ return null;
+ }
+ try {
+ int statusQuark = ssq.getQuarkRelative(entry.getThreadQuark(), Attributes.STATUS);
+ 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()) {
+ 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;
+ }
+ LttngKernelAnalysisModule module = trace.getAnalysisModuleOfClass(LttngKernelAnalysisModule.class, LttngKernelAnalysisModule.ID);
+ if (module == null) {
+ continue;
+ }
+ ITmfStateSystem ssq = module.getStateSystem();
+ 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 */
+ }
+ }
+ }
+ }
+ 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<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) {
+ LttngKernelAnalysisModule module = trace.getAnalysisModuleOfClass(LttngKernelAnalysisModule.class, LttngKernelAnalysisModule.ID);
+ if (module == null) {
+ continue;
+ }
+ ITmfStateSystem ssq = module.getStateSystem();
+ if (ssq == null) {
+ continue;
+ }
+ try {
+ long start = Math.max(startTime, ssq.getStartTime());
+ long end = Math.min(endTime, ssq.getCurrentEndTime());
+ if (end < start) {
+ continue;
+ }
+ 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 */
+ }
+ }
+ return list;
+ }
+
+ private ControlFlowEntry findEntry(List<TimeGraphEntry> entryList, ITmfTrace trace, int threadId) {
+ for (TimeGraphEntry 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;
+ }
+}