/*******************************************************************************
- * Copyright (c) 2012, 2015 Ericsson, École Polytechnique de Montréal and others.
+ * Copyright (c) 2012, 2016 Ericsson, École Polytechnique de Montréal and others.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Composite;
-import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.Attributes;
-import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.KernelAnalysisModule;
+import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule;
+import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes;
import org.eclipse.tracecompass.internal.analysis.os.linux.ui.Activator;
import org.eclipse.tracecompass.internal.analysis.os.linux.ui.Messages;
+import org.eclipse.tracecompass.internal.analysis.os.linux.ui.actions.FollowThreadAction;
+import org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow.ControlFlowColumnComparators;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.core.util.Pair;
import org.eclipse.tracecompass.tmf.ui.views.timegraph.AbstractStateSystemTimeGraphView;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ILinkEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.Resolution;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
+import com.google.common.collect.ImmutableList;
+
/**
* The Control Flow view main object
*
// ------------------------------------------------------------------------
// Constants
// ------------------------------------------------------------------------
-
/**
* View ID.
*/
// Timeout between updates in the build thread in ms
private static final long BUILD_UPDATE_TIMEOUT = 500;
+ private static final Comparator<ITimeGraphEntry>[] COLUMN_COMPARATORS;
+
+ private static final int INITIAL_SORT_COLUMN_INDEX = 3;
+
+ static {
+ ImmutableList.Builder<Comparator<ITimeGraphEntry>> builder = ImmutableList.builder();
+ builder.add(ControlFlowColumnComparators.PROCESS_NAME_COLUMN_COMPARATOR)
+ .add(ControlFlowColumnComparators.TID_COLUMN_COMPARATOR)
+ .add(ControlFlowColumnComparators.PTID_COLUMN_COMPARATOR)
+ .add(ControlFlowColumnComparators.BIRTH_TIME_COLUMN_COMPARATOR)
+ .add(ControlFlowColumnComparators.TRACE_COLUMN_COMPARATOR);
+ List<Comparator<ITimeGraphEntry>> l = builder.build();
+ COLUMN_COMPARATORS = l.toArray(new Comparator[l.size()]);
+ }
+
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
*/
public ControlFlowView() {
super(ID, new ControlFlowPresentationProvider());
- setTreeColumns(COLUMN_NAMES);
+ setTreeColumns(COLUMN_NAMES, COLUMN_COMPARATORS, INITIAL_SORT_COLUMN_INDEX);
setTreeLabelProvider(new ControlFlowTreeLabelProvider());
setFilterColumns(FILTER_COLUMN_NAMES);
setFilterLabelProvider(new ControlFlowFilterLabelProvider());
- setEntryComparator(new ControlFlowEntryComparator());
+ setEntryComparator(ControlFlowColumnComparators.BIRTH_TIME_COLUMN_COMPARATOR);
}
@Override
new ControlFlowCheckActiveProvider(Messages.ControlFlowView_uncheckInactiveLabel, Messages.ControlFlowView_uncheckInactiveToolTip));
}
+ /**
+ * @since 2.0
+ */
+ @Override
+ protected void fillTimeGraphEntryContextMenu(@NonNull IMenuManager menuManager) {
+ ISelection selection = getSite().getSelectionProvider().getSelection();
+ if (selection instanceof StructuredSelection) {
+ StructuredSelection sSel = (StructuredSelection) selection;
+ if (sSel.getFirstElement() instanceof ControlFlowEntry) {
+ ControlFlowEntry entry = (ControlFlowEntry) sSel.getFirstElement();
+ menuManager.add(new FollowThreadAction(ControlFlowView.this, entry.getName(), entry.getThreadId(), entry.getTrace()));
+ }
+ }
+ }
+
@Override
protected void fillLocalToolBar(IToolBarManager manager) {
super.fillLocalToolBar(manager);
return Messages.ControlFlowView_previousProcessActionToolTipText;
}
- private static class ControlFlowEntryComparator implements Comparator<ITimeGraphEntry> {
-
- @Override
- public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
-
- if (o1.getParent() != null || o2.getParent() != null) {
- /* Sort all child processes according to birth time. */
- return Long.compare(o1.getStartTime(), o2.getStartTime());
- }
-
- int result = 0;
-
- if ((o1 instanceof ControlFlowEntry) && (o2 instanceof ControlFlowEntry)) {
- /*
- * Sort root processes according to their trace's start time,
- * then by trace name, then by the process thread id.
- */
- 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 = Integer.compare(entry1.getThreadId(), entry2.getThreadId());
- }
- }
-
- if (result == 0) {
- /* Sort root processes with reused thread id by birth time. */
- result = Long.compare(o1.getStartTime(), o2.getStartTime());
- }
-
- return result;
- }
- }
-
/**
* @author gbastien
*
// ------------------------------------------------------------------------
@Override
- protected void buildEventList(final ITmfTrace trace, final ITmfTrace parentTrace, final IProgressMonitor monitor) {
+ protected void buildEntryList(final ITmfTrace trace, final ITmfTrace parentTrace, final IProgressMonitor monitor) {
final ITmfStateSystem ssq = TmfStateSystemAnalysisModule.getStateSystem(trace, KernelAnalysisModule.ID);
if (ssq == null) {
return;
}
final List<ControlFlowEntry> entryList = new ArrayList<>();
- final Map<Integer, ControlFlowEntry> entryMap = new HashMap<>();
+ /** Map of view entries, key is a pair [threadId, cpuId] */
+ final Map<Pair<Integer, Integer>, ControlFlowEntry> entryMap = new HashMap<>();
long start = ssq.getStartTime();
setStartTime(Math.min(getStartTime(), start));
final long resolution = Math.max(1, (end - ssq.getStartTime()) / getDisplayWidth());
setEndTime(Math.max(getEndTime(), end + 1));
final List<Integer> threadQuarks = ssq.getQuarks(Attributes.THREADS, "*"); //$NON-NLS-1$
- final long qStart = start;
- final long qEnd = end;
- queryFullStates(ssq, qStart, qEnd, resolution, monitor, new IQueryHandler() {
+ queryFullStates(ssq, start, end, resolution, monitor, new IQueryHandler() {
@Override
public void handle(List<List<ITmfStateInterval>> fullStates, List<ITmfStateInterval> prevFullState) {
for (int threadQuark : threadQuarks) {
- String threadName = ssq.getAttributeName(threadQuark);
- int threadId = -1;
- try {
- threadId = Integer.parseInt(threadName);
- } catch (NumberFormatException e1) {
- continue;
- }
- if (threadId <= 0) { // ignore the 'unknown' (-1) and swapper (0) threads
+ String threadAttributeName = ssq.getAttributeName(threadQuark);
+
+ Pair<Integer, Integer> entryKey = Attributes.parseThreadAttributeName(threadAttributeName);
+ int threadId = entryKey.getFirst();
+
+ if (threadId < 0) { // ignore the 'unknown' (-1) thread
continue;
}
execNameInterval.getStateValue().getType() == ITmfStateValue.Type.STRING) {
String execName = execNameInterval.getStateValue().unboxStr();
int ppid = ppidInterval.getStateValue().unboxInt();
- ControlFlowEntry entry = entryMap.get(threadId);
+ ControlFlowEntry entry = entryMap.get(entryKey);
if (entry == null) {
entry = new ControlFlowEntry(threadQuark, trace, execName, threadId, ppid, startTime, endTime);
entryList.add(entry);
- entryMap.put(threadId, entry);
+ entryMap.put(entryKey, entry);
} else {
/*
* Update the name of the entry to the
}
}
if (isNull) {
- entryMap.remove(threadId);
+ entryMap.remove(entryKey);
}
lastExecNameStartTime = startTime;
lastExecNameEndTime = endTime;
}
}
updateTree(entryList, parentTrace, ssq);
+ }
+ });
+ queryFullStates(ssq, ssq.getStartTime(), end, resolution, monitor, new IQueryHandler() {
+ @Override
+ public void handle(@NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState) {
for (final TimeGraphEntry entry : getEntryList(ssq)) {
if (monitor.isCanceled()) {
return;
}
- buildStatusEvents(trace, parentTrace, ssq, fullStates, prevFullState, (ControlFlowEntry) entry, monitor, qStart, qEnd);
+ buildStatusEvents(trace, parentTrace, ssq, fullStates, prevFullState, (ControlFlowEntry) entry, monitor, ssq.getStartTime(), end);
}
}
});
if (eventList == null) {
return;
}
- for (ITimeEvent event : eventList) {
- entry.addEvent(event);
+ /* Start a new event list on first iteration, then append to it */
+ if (prevFullState == null) {
+ entry.setEventList(eventList);
+ } else {
+ for (ITimeEvent event : eventList) {
+ entry.addEvent(event);
+ }
}
if (parentTrace.equals(getTrace())) {
redraw();