-/*******************************************************************************\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.Collections;\r
-import java.util.Comparator;\r
-import java.util.List;\r
-\r
-import org.eclipse.core.runtime.IProgressMonitor;\r
-import org.eclipse.core.runtime.NullProgressMonitor;\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.core.Attributes;\r
-import org.eclipse.linuxtools.internal.lttng2.kernel.ui.Messages;\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.TmfStateSystemBuildCompleted;\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.TimeGraphCombo;\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.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
- /**\r
- * Initial time range\r
- */\r
- private static final long INITIAL_WINDOW_OFFSET = (1L * 100 * 1000 * 1000); // .1sec\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 PTID_COLUMN = Messages.ControlFlowView_ptidColumn;\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
- PTID_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
- // A comparator class\r
- private ControlFlowEntryComparator fControlFlowEntryComparator = new ControlFlowEntryComparator();\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.getParentThreadId() > 0) {\r
- return Integer.toString(entry.getParentThreadId());\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 static class ControlFlowEntryComparator implements Comparator<ITimeGraphEntry> {\r
-\r
- @Override\r
- public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {\r
- int result = 0;\r
-\r
- if ((o1 instanceof ControlFlowEntry) && (o2 instanceof ControlFlowEntry)) {\r
- ControlFlowEntry entry1 = (ControlFlowEntry) o1;\r
- ControlFlowEntry entry2 = (ControlFlowEntry) o2;\r
- result = entry1.getTrace().getStartTime().compareTo(entry2.getTrace().getStartTime());\r
- if (result == 0) {\r
- result = entry1.getTrace().getName().compareTo(entry2.getTrace().getName());\r
- }\r
- if (result == 0) {\r
- result = entry1.getThreadId() < entry2.getThreadId() ? -1 : entry1.getThreadId() > entry2.getThreadId() ? 1 : 0;\r
- }\r
- }\r
-\r
- if (result == 0) {\r
- result = o1.getStartTime() < o2.getStartTime() ? -1 : o1.getStartTime() > o2.getStartTime() ? 1 : 0;\r
- }\r
-\r
- return result;\r
- }\r
- }\r
-\r
- \r
- private class ZoomThread extends Thread {\r
- private long fZoomStartTime;\r
- private long fZoomEndTime;\r
- private long fResolution;\r
- private IProgressMonitor fMonitor;\r
-\r
- public ZoomThread(long startTime, long endTime) {\r
- super("ControlFlowView zoom"); //$NON-NLS-1$\r
- fZoomStartTime = startTime;\r
- fZoomEndTime = endTime;\r
- fResolution = Math.max(1, (fZoomEndTime - fZoomStartTime) / fDisplayWidth);\r
- fMonitor = new NullProgressMonitor();\r
- }\r
-\r
- @Override\r
- public void run() {\r
- ArrayList<ControlFlowEntry> entryList = fEntryList;\r
- if (entryList == null) {\r
- return;\r
- }\r
- for (ControlFlowEntry entry : entryList) {\r
- if (fMonitor.isCanceled()) {\r
- break;\r
- }\r
- zoom(entry, fMonitor);\r
- }\r
- redraw();\r
- }\r
-\r
- private void zoom(ControlFlowEntry entry, IProgressMonitor monitor) {\r
- if (fZoomStartTime <= fStartTime && fZoomEndTime >= fEndTime) {\r
- entry.setZoomedEventList(null);\r
- } else {\r
- List<ITimeEvent> zoomedEventList = getEventList(entry, fZoomStartTime, fZoomEndTime, fResolution, monitor);\r
- if (zoomedEventList != null) {\r
- entry.setZoomedEventList(zoomedEventList);\r
- }\r
- }\r
- for (ControlFlowEntry child : entry.getChildren()) {\r
- if (fMonitor.isCanceled()) {\r
- return;\r
- }\r
- zoom(child, monitor);\r
- }\r
- }\r
-\r
- public void cancel() {\r
- fMonitor.setCanceled(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 ControlFlowPresentationProvider());\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
- startZoomThread(startTime, endTime);\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
- };\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
-\r
- int thread = -1;\r
- for (ITmfTrace<?> trace : fSelectedExperiment.getTraces()) {\r
- if (thread > 0) {\r
- break;\r
- }\r
- if (trace instanceof CtfKernelTrace) {\r
- CtfKernelTrace ctfKernelTrace = (CtfKernelTrace) trace;\r
- IStateSystemQuerier ssq = ctfKernelTrace.getStateSystem();\r
- if (time >= ssq.getStartTime() && time <= ssq.getCurrentEndTime()) {\r
- List<Integer> currentThreadQuarks = ssq.getQuarks(Attributes.CPUS, "*", Attributes.CURRENT_THREAD); //$NON-NLS-1$\r
- for (int currentThreadQuark : currentThreadQuarks) {\r
- try {\r
- ITmfStateInterval currentThreadInterval = ssq.querySingleState(time, currentThreadQuark);\r
- int currentThread = currentThreadInterval.getStateValue().unboxInt();\r
- if (currentThread > 0) {\r
- int statusQuark = ssq.getQuarkAbsolute(Attributes.THREADS, Integer.toString(currentThread), Attributes.STATUS);\r
- ITmfStateInterval statusInterval = ssq.querySingleState(time, statusQuark);\r
- if (statusInterval.getStartTime() == time) {\r
- thread = currentThread;\r
- break;\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
- }\r
- }\r
- final int selectedThread = thread;\r
- \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);\r
- startZoomThread(fTimeGraphCombo.getTimeGraphViewer().getTime0(), fTimeGraphCombo.getTimeGraphViewer().getTime1());\r
-\r
- if (selectedThread > 0) {\r
- for (Object element : fTimeGraphCombo.getTimeGraphViewer().getExpandedElements()) {\r
- if (element instanceof ControlFlowEntry) {\r
- ControlFlowEntry entry = (ControlFlowEntry) element;\r
- if (entry.getThreadId() == selectedThread) {\r
- fTimeGraphCombo.setSelection(entry);\r
- break;\r
- }\r
- }\r
- }\r
- }\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);\r
- startZoomThread(startTime, endTime);\r
- }\r
- });\r
- }\r
-\r
- @TmfSignalHandler\r
- public void stateSystemBuildCompleted (final TmfStateSystemBuildCompleted signal) {\r
- final TmfExperiment<?> selectedExperiment = fSelectedExperiment;\r
- if (selectedExperiment == null) {\r
- return;\r
- }\r
- for (ITmfTrace<?> trace : selectedExperiment.getTraces()) {\r
- if (trace == signal.getTrace() && trace instanceof CtfKernelTrace) {\r
- final Thread thread = new Thread("ControlFlowView build") { //$NON-NLS-1$\r
- @Override\r
- public void run() {\r
- // rebuild the model\r
- selectExperiment(selectedExperiment);\r
- }\r
- };\r
- thread.start();\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
- ArrayList<ControlFlowEntry> rootList = new ArrayList<ControlFlowEntry>();\r
- for (ITmfTrace<?> trace : experiment.getTraces()) {\r
- if (trace instanceof CtfKernelTrace) {\r
- ArrayList<ControlFlowEntry> entryList = new ArrayList<ControlFlowEntry>();\r
- CtfKernelTrace ctfKernelTrace = (CtfKernelTrace) trace;\r
- IStateSystemQuerier ssq = ctfKernelTrace.getStateSystem();\r
- long start = ssq.getStartTime();\r
- long end = ssq.getCurrentEndTime() + 1;\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 - 1);\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
- entryList.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
- buildTree(entryList, rootList);\r
- }\r
- Collections.sort(rootList, fControlFlowEntryComparator);\r
- fEntryList = rootList;\r
- refresh(INITIAL_WINDOW_OFFSET);\r
- }\r
- for (ControlFlowEntry entry : rootList) {\r
- buildStatusEvents(entry);\r
- }\r
- }\r
-\r
- private void buildTree(ArrayList<ControlFlowEntry> entryList, ArrayList<ControlFlowEntry> rootList) {\r
- for (ControlFlowEntry entry : entryList) {\r
- boolean root = true;\r
- if (entry.getParentThreadId() > 0) {\r
- for (ControlFlowEntry parent : entryList) {\r
- if (parent.getThreadId() == entry.getParentThreadId() &&\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
- }\r
-\r
- private void buildStatusEvents(ControlFlowEntry entry) {\r
- IStateSystemQuerier ssq = entry.getTrace().getStateSystem();\r
- long start = ssq.getStartTime();\r
- long end = ssq.getCurrentEndTime() + 1;\r
- long resolution = Math.max(1, (end - start) / fDisplayWidth);\r
- List<ITimeEvent> eventList = getEventList(entry, entry.getStartTime(), entry.getEndTime(), resolution, new NullProgressMonitor());\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, IProgressMonitor monitor) {\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
- if (monitor.isCanceled()) {\r
- return null;\r
- }\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(final long windowRange) {\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, fControlFlowEntryComparator);\r
- fTimeGraphCombo.setInput(entries);\r
- fTimeGraphCombo.getTimeGraphViewer().setTimeBounds(fStartTime, fEndTime);\r
-\r
- long endTime = fStartTime + windowRange;\r
-\r
- if (fEndTime < endTime) {\r
- endTime = fEndTime;\r
- }\r
- fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(fStartTime, endTime);\r
- for (TreeColumn column : fTimeGraphCombo.getTreeViewer().getTree().getColumns()) {\r
- column.pack();\r
- }\r
-\r
- startZoomThread(fStartTime, endTime);\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 startZoomThread(long startTime, long endTime) {\r
- if (fZoomThread != null) {\r
- fZoomThread.cancel();\r
- }\r
- fZoomThread = new ZoomThread(startTime, endTime);\r
- fZoomThread.start();\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, 2013 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.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+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.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.signal.TmfRangeSynchSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfTraceClosedSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfTraceSelectedSignal;
+import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
+import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
+import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+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;
+
+/**
+ * The Control Flow view main object
+ *
+ */
+public class ControlFlowView extends TmfView {
+
+ // ------------------------------------------------------------------------
+ // 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 final String[] COLUMN_NAMES = new String[] {
+ PROCESS_COLUMN,
+ TID_COLUMN,
+ PTID_COLUMN,
+ BIRTH_TIME_COLUMN,
+ TRACE_COLUMN
+ };
+
+ private final String[] FILTER_COLUMN_NAMES = new String[] {
+ PROCESS_COLUMN,
+ TID_COLUMN
+ };
+
+ /**
+ * Redraw state enum
+ */
+ private enum State { IDLE, BUSY, PENDING }
+
+ // ------------------------------------------------------------------------
+ // Fields
+ // ------------------------------------------------------------------------
+
+ // The timegraph combo
+ private TimeGraphCombo fTimeGraphCombo;
+
+ // The selected trace
+ private ITmfTrace fTrace;
+
+ // The timegraph entry list
+ private ArrayList<ControlFlowEntry> fEntryList;
+
+ // The trace to entry list hash map
+ final private HashMap<ITmfTrace, ArrayList<ControlFlowEntry>> fEntryListMap = new HashMap<ITmfTrace, ArrayList<ControlFlowEntry>>();
+
+ // The trace to build thread hash map
+ final private HashMap<ITmfTrace, BuildThread> fBuildThreadMap = new HashMap<ITmfTrace, BuildThread>();
+
+ // 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;
+
+ // The redraw synchronization object
+ final private Object fSyncObj = new Object();
+
+ // ------------------------------------------------------------------------
+ // 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;
+ 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();
+ }
+
+ }
+
+ 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.getStartTime(), TimeFormat.CALENDAR, Resolution.NANOSEC);
+ } else if (columnIndex == 4) {
+ return entry.getTrace().getName();
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ }
+
+ 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;
+ }
+ }
+
+ private class BuildThread extends Thread {
+ private final ITmfTrace fBuildTrace;
+ private final IProgressMonitor fMonitor;
+
+ public BuildThread(ITmfTrace trace) {
+ super("ControlFlowView build"); //$NON-NLS-1$
+ fBuildTrace = trace;
+ fMonitor = new NullProgressMonitor();
+ }
+
+ @Override
+ public void run() {
+ buildEventList(fBuildTrace, fMonitor);
+ synchronized (fBuildThreadMap) {
+ fBuildThreadMap.remove(this);
+ }
+ }
+
+ public void cancel() {
+ fMonitor.setCanceled(true);
+ }
+ }
+
+ private class ZoomThread extends Thread {
+ private final ArrayList<ControlFlowEntry> fZoomEntryList;
+ private final long fZoomStartTime;
+ private final long fZoomEndTime;
+ private final long fResolution;
+ private final IProgressMonitor fMonitor;
+
+ public ZoomThread(ArrayList<ControlFlowEntry> entryList, long startTime, long endTime) {
+ super("ControlFlowView zoom"); //$NON-NLS-1$
+ fZoomEntryList = entryList;
+ fZoomStartTime = startTime;
+ fZoomEndTime = endTime;
+ fResolution = Math.max(1, (fZoomEndTime - fZoomStartTime) / fDisplayWidth);
+ fMonitor = new NullProgressMonitor();
+ }
+
+ @Override
+ public void run() {
+ if (fZoomEntryList == null) {
+ return;
+ }
+ for (ControlFlowEntry entry : fZoomEntryList) {
+ if (fMonitor.isCanceled()) {
+ break;
+ }
+ zoom(entry, fMonitor);
+ }
+ }
+
+ 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;
+ }
+ zoom(child, monitor);
+ }
+ }
+
+ public void cancel() {
+ fMonitor.setCanceled(true);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructor
+ */
+ public ControlFlowView() {
+ super(ID);
+ fDisplayWidth = Display.getDefault().getBounds().width;
+ }
+
+ // ------------------------------------------------------------------------
+ // ViewPart
+ // ------------------------------------------------------------------------
+
+ @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.setFilterContentProvider(new TreeContentProvider());
+
+ fTimeGraphCombo.setFilterLabelProvider(new TreeLabelProvider());
+
+ fTimeGraphCombo.setFilterColumns(FILTER_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().setTimeFormat(TimeFormat.CALENDAR);
+
+ // View Action Handling
+ makeActions();
+ contributeToActionBars();
+
+ ITmfTrace trace = getActiveTrace();
+ if (trace != null) {
+ traceSelected(new TmfTraceSelectedSignal(this, trace));
+ }
+
+ // make selection available to other views
+ getSite().setSelectionProvider(fTimeGraphCombo.getTreeViewer());
+ }
+
+ @Override
+ public void setFocus() {
+ fTimeGraphCombo.setFocus();
+ }
+
+ // ------------------------------------------------------------------------
+ // Signal handlers
+ // ------------------------------------------------------------------------
+
+ /**
+ * Handler for the trace selected signal
+ *
+ * @param signal
+ * The signal that's received
+ */
+ @TmfSignalHandler
+ public void traceSelected(final TmfTraceSelectedSignal signal) {
+ if (signal.getTrace() == fTrace) {
+ return;
+ }
+ fTrace = signal.getTrace();
+
+ synchronized (fEntryListMap) {
+ fEntryList = fEntryListMap.get(fTrace);
+ if (fEntryList == null) {
+ synchronized (fBuildThreadMap) {
+ BuildThread buildThread = new BuildThread(fTrace);
+ fBuildThreadMap.put(fTrace, buildThread);
+ buildThread.start();
+ }
+ } else {
+ fStartTime = fTrace.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ fEndTime = fTrace.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ refresh();
+ }
+ }
+ }
+
+ /**
+ * Trace is closed: clear the data structures and the view
+ *
+ * @param signal the signal received
+ */
+ @TmfSignalHandler
+ public void traceClosed(final TmfTraceClosedSignal signal) {
+ synchronized (fBuildThreadMap) {
+ BuildThread buildThread = fBuildThreadMap.remove(signal.getTrace());
+ if (buildThread != null) {
+ buildThread.cancel();
+ }
+ }
+ synchronized (fEntryListMap) {
+ fEntryListMap.remove(signal.getTrace());
+ }
+ if (signal.getTrace() == fTrace) {
+ fTrace = null;
+ fStartTime = 0;
+ fEndTime = 0;
+ if (fZoomThread != null) {
+ fZoomThread.cancel();
+ }
+ refresh();
+ }
+ }
+
+ /**
+ * Handler for the synch signal
+ *
+ * @param signal
+ * The signal that's received
+ */
+ @TmfSignalHandler
+ public void synchToTime(final TmfTimeSynchSignal signal) {
+ if (signal.getSource() == this || fTrace == null) {
+ return;
+ }
+ final long time = signal.getCurrentTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+
+ int thread = -1;
+ for (ITmfTrace trace : fTrace.getTraces()) {
+ if (thread > 0) {
+ break;
+ }
+ if (trace instanceof CtfKernelTrace) {
+ CtfKernelTrace ctfKernelTrace = (CtfKernelTrace) trace;
+ ITmfStateSystem ssq = ctfKernelTrace.getStateSystems().get(CtfKernelTrace.STATE_ID);
+ 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();
+ } catch (StateSystemDisposedException e) {
+ /* Ignored */
+ }
+ }
+ }
+ }
+ }
+ 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;
+ }
+ }
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Handler for the range sync signal
+ *
+ * @param signal
+ * The signal that's received
+ */
+ @TmfSignalHandler
+ public void synchToRange(final TmfRangeSynchSignal signal) {
+ if (signal.getSource() == this || fTrace == null) {
+ return;
+ }
+ if (signal.getCurrentRange().getIntersection(fTrace.getTimeRange()) == null) {
+ return;
+ }
+ final long startTime = signal.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ final long endTime = signal.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ final long time = signal.getCurrentTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).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);
+ }
+ });
+ }
+
+ // ------------------------------------------------------------------------
+ // Internal
+ // ------------------------------------------------------------------------
+
+ private void buildEventList(final ITmfTrace trace, IProgressMonitor monitor) {
+ fStartTime = Long.MAX_VALUE;
+ fEndTime = Long.MIN_VALUE;
+ ArrayList<ControlFlowEntry> rootList = new ArrayList<ControlFlowEntry>();
+ for (ITmfTrace aTrace : trace.getTraces()) {
+ if (monitor.isCanceled()) {
+ return;
+ }
+ if (aTrace instanceof CtfKernelTrace) {
+ ArrayList<ControlFlowEntry> entryList = new ArrayList<ControlFlowEntry>();
+ CtfKernelTrace ctfKernelTrace = (CtfKernelTrace) aTrace;
+ ITmfStateSystem ssq = ctfKernelTrace.getStateSystems().get(CtfKernelTrace.STATE_ID);
+ if (!ssq.waitUntilBuilt()) {
+ return;
+ }
+ 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) {
+ 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 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); // use monitor when available in api
+ if (monitor.isCanceled()) {
+ return;
+ }
+ ControlFlowEntry entry = null;
+ for (ITmfStateInterval execNameInterval : execNameIntervals) {
+ if (monitor.isCanceled()) {
+ return;
+ }
+ if (!execNameInterval.getStateValue().isNull() &&
+ execNameInterval.getStateValue().getType() == ITmfStateValue.Type.STRING) {
+ String execName = execNameInterval.getStateValue().unboxStr();
+ long startTime = execNameInterval.getStartTime();
+ long endTime = execNameInterval.getEndTime() + 1;
+ int ppid = -1;
+ if (ppidQuark != -1) {
+ ITmfStateInterval ppidInterval = ssq.querySingleState(startTime, ppidQuark);
+ ppid = ppidInterval.getStateValue().unboxInt();
+ }
+ if (entry == null) {
+ entry = new ControlFlowEntry(threadQuark, ctfKernelTrace, execName, threadId, ppid, startTime, endTime);
+ entryList.add(entry);
+ } else {
+ // update the name of the entry to the latest execName
+ entry.setName(execName);
+ }
+ entry.addEvent(new TimeEvent(entry, startTime, endTime - startTime));
+ } else {
+ entry = null;
+ }
+ }
+ } catch (AttributeNotFoundException e) {
+ e.printStackTrace();
+ } catch (TimeRangeException e) {
+ e.printStackTrace();
+ } catch (StateValueTypeException e) {
+ e.printStackTrace();
+ } catch (StateSystemDisposedException e) {
+ /* Ignored */
+ }
+ }
+ buildTree(entryList, rootList);
+ }
+ Collections.sort(rootList, fControlFlowEntryComparator);
+ synchronized (fEntryListMap) {
+ fEntryListMap.put(trace, (ArrayList<ControlFlowEntry>) rootList.clone());
+ }
+ if (trace == fTrace) {
+ refresh();
+ }
+ }
+ for (ControlFlowEntry entry : rootList) {
+ if (monitor.isCanceled()) {
+ return;
+ }
+ buildStatusEvents(trace, entry, monitor);
+ }
+ }
+
+ private static void buildTree(ArrayList<ControlFlowEntry> entryList,
+ ArrayList<ControlFlowEntry> rootList) {
+ 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);
+ }
+ }
+ }
+
+ private void buildStatusEvents(ITmfTrace trace, ControlFlowEntry entry, IProgressMonitor monitor) {
+ ITmfStateSystem ssq = entry.getTrace().getStateSystems().get(CtfKernelTrace.STATE_ID);
+ 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, monitor);
+ if (monitor.isCanceled()) {
+ return;
+ }
+ entry.setEventList(eventList);
+ if (trace == fTrace) {
+ redraw();
+ }
+ for (ITimeGraphEntry child : entry.getChildren()) {
+ if (monitor.isCanceled()) {
+ return;
+ }
+ buildStatusEvents(trace, (ControlFlowEntry) child, monitor);
+ }
+ }
+
+ private static List<ITimeEvent> getEventList(ControlFlowEntry entry,
+ long startTime, long endTime, long resolution,
+ IProgressMonitor monitor) {
+ final long realStart = Math.max(startTime, entry.getStartTime());
+ final long realEnd = Math.min(endTime, entry.getEndTime());
+ if (realEnd <= realStart) {
+ return null;
+ }
+ ITmfStateSystem ssq = entry.getTrace().getStateSystems().get(CtfKernelTrace.STATE_ID);
+ List<ITimeEvent> eventList = null;
+ try {
+ int statusQuark = ssq.getQuarkRelative(entry.getThreadQuark(), Attributes.STATUS);
+ List<ITmfStateInterval> statusIntervals = ssq.queryHistoryRange(statusQuark, realStart, realEnd - 1, resolution, monitor);
+ eventList = new ArrayList<ITimeEvent>(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 ControlFlowEvent(entry, time, duration, status));
+ lastEndTime = time + duration;
+ }
+ } catch (AttributeNotFoundException e) {
+ e.printStackTrace();
+ } catch (TimeRangeException e) {
+ e.printStackTrace();
+ } catch (StateSystemDisposedException e) {
+ /* Ignored */
+ }
+ return eventList;
+ }
+
+ private void refresh() {
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (fTimeGraphCombo.isDisposed()) {
+ return;
+ }
+ ITimeGraphEntry[] entries = null;
+ synchronized (fEntryListMap) {
+ fEntryList = fEntryListMap.get(fTrace);
+ if (fEntryList == null) {
+ fEntryList = new ArrayList<ControlFlowEntry>();
+ }
+ entries = fEntryList.toArray(new ITimeGraphEntry[0]);
+ }
+ Arrays.sort(entries, fControlFlowEntryComparator);
+ fTimeGraphCombo.setInput(entries);
+ fTimeGraphCombo.getTimeGraphViewer().setTimeBounds(fStartTime, fEndTime);
+
+ long timestamp = fTrace == null ? 0 : fTrace.getCurrentTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ long startTime = fTrace == null ? 0 : fTrace.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ long endTime = fTrace == null ? 0 : fTrace.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ startTime = Math.max(startTime, fStartTime);
+ endTime = Math.min(endTime, fEndTime);
+ fTimeGraphCombo.getTimeGraphViewer().setSelectedTime(timestamp, false);
+ fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
+
+ for (TreeColumn column : fTimeGraphCombo.getTreeViewer().getTree().getColumns()) {
+ column.pack();
+ }
+
+ startZoomThread(startTime, endTime);
+ }
+ });
+ }
+
+ private void redraw() {
+ synchronized (fSyncObj) {
+ if (fRedrawState == State.IDLE) {
+ fRedrawState = State.BUSY;
+ } else {
+ fRedrawState = State.PENDING;
+ return;
+ }
+ }
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (fTimeGraphCombo.isDisposed()) {
+ return;
+ }
+ fTimeGraphCombo.redraw();
+ fTimeGraphCombo.update();
+ synchronized (fSyncObj) {
+ if (fRedrawState == State.PENDING) {
+ fRedrawState = State.IDLE;
+ redraw();
+ } else {
+ fRedrawState = State.IDLE;
+ }
+ }
+ }
+ });
+ }
+
+ private void startZoomThread(long startTime, long endTime) {
+ if (fZoomThread != null) {
+ fZoomThread.cancel();
+ }
+ fZoomThread = new ZoomThread(fEntryList, 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.getShowFilterAction());
+ 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());
+ }
+}