From: Jean-Christian Kouame Date: Mon, 13 Jun 2016 17:24:43 +0000 (-0400) Subject: analysis: Keep thread selection and follow CPU when switching traces X-Git-Url: http://git.efficios.com/?a=commitdiff_plain;h=178d3c0e0baf30494e121d10d095ea4f070ea6d3;p=deliverable%2Ftracecompass.git analysis: Keep thread selection and follow CPU when switching traces Keep thread selection and follow CPU when switching traces in CPU Usage View. The data is saved in a map in the trace context, so if the view is closed, it will remember the thread selection and the followed CPU for each trace when reopening. Change-Id: I8c56d852a133d0615f58cdb3e8e6b965a7c2f73d Signed-off-by: Jean-Christian Kouame Reviewed-on: https://git.eclipse.org/r/75600 Reviewed-by: Marc-Andre Laperle Tested-by: Marc-Andre Laperle --- diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/cpuusage/CpuUsageComposite.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/cpuusage/CpuUsageComposite.java index aa3fed88f1..429d26364f 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/cpuusage/CpuUsageComposite.java +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/cpuusage/CpuUsageComposite.java @@ -43,6 +43,8 @@ import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal; import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal; import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceContext; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; import org.eclipse.tracecompass.tmf.ui.viewers.tree.AbstractTmfTreeViewer; import org.eclipse.tracecompass.tmf.ui.viewers.tree.ITmfTreeColumnDataProvider; @@ -372,15 +374,39 @@ public class CpuUsageComposite extends AbstractTmfTreeViewer { @Override @TmfSignalHandler public void traceSelected(TmfTraceSelectedSignal signal) { - setSelectedThread(null); + initSelection(); + initCPU(); super.traceSelected(signal); } @Override @TmfSignalHandler public void traceOpened(TmfTraceOpenedSignal signal) { - setSelectedThread(null); + initSelection(); + initCPU(); super.traceOpened(signal); } + private void initSelection() { + TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext(); + String thread = (String) ctx.getData(CpuUsageView.CPU_USAGE_SELECTED_THREAD); + setSelectedThread(thread); + } + + private void initCPU() { + clearCpu(); + TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext(); + Object data = ctx.getData(CpuUsageView.CPU_USAGE_FOLLOW_CPU); + if (data instanceof Set) { + Set set = (Set) data; + for (Object coreObject : set) { + if (coreObject instanceof Integer) { + Integer core = (Integer) coreObject; + if (core >= 0) { + addCpu(core); + } + } + } + } + } } diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/cpuusage/CpuUsageView.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/cpuusage/CpuUsageView.java index 1ce79b1211..d1ac399c17 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/cpuusage/CpuUsageView.java +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/cpuusage/CpuUsageView.java @@ -12,6 +12,12 @@ package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.cpuusage; +import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; + +import java.util.Set; +import java.util.TreeSet; + +import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; @@ -21,14 +27,19 @@ import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.widgets.Composite; import org.eclipse.tracecompass.analysis.os.linux.core.signals.TmfCpuSelectedSignal; +import org.eclipse.tracecompass.internal.analysis.os.linux.ui.Activator; import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler; import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceContext; import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; import org.eclipse.tracecompass.tmf.ui.viewers.TmfViewer; import org.eclipse.tracecompass.tmf.ui.viewers.xycharts.TmfXYChartViewer; import org.eclipse.tracecompass.tmf.ui.views.TmfChartView; +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; + /** * CPU usage view. It contains 2 viewers: one tree viewer showing all the * threads who were on the CPU in the time range, and one XY chart viewer @@ -42,6 +53,12 @@ public class CpuUsageView extends TmfChartView { /** ID string */ public static final String ID = "org.eclipse.tracecompass.analysis.os.linux.views.cpuusage"; //$NON-NLS-1$ + /** ID of the selected thread in the map of data in {@link TmfTraceContext} */ + public static final @NonNull String CPU_USAGE_SELECTED_THREAD = ID + ".CPU_USAGE_SELECTED_TRHEAD"; //$NON-NLS-1$ + + /** ID of the followed CPU in the map data in {@link TmfTraceContext} */ + public static final @NonNull String CPU_USAGE_FOLLOW_CPU = ID + ".FOLLOW_CPU"; //$NON-NLS-1$ + private @Nullable CpuUsageComposite fTreeViewer = null; private @Nullable CpuUsageXYViewer fXYViewer = null; @@ -96,6 +113,7 @@ public class CpuUsageView extends TmfChartView { if (fXYViewer != null) { fXYViewer.setSelectedThread(Long.valueOf(entry.getTid())); } + saveData(CPU_USAGE_SELECTED_THREAD, entry.getTid()); } } } @@ -112,6 +130,19 @@ public class CpuUsageView extends TmfChartView { return fTreeViewer; } + /** + * Save a data in the data map of {@link TmfTraceContext} + */ + private static void saveData(@NonNull String key, Object data) { + TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext(); + ctx.setData(key, checkNotNull(data)); + } + + private static Object getData(@NonNull String key) { + TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext(); + return ctx.getData(key); + } + @Override public void setFocus() { if (fXYViewer != null) { @@ -131,13 +162,29 @@ public class CpuUsageView extends TmfChartView { final @Nullable CpuUsageXYViewer xyViewer = fXYViewer; final @Nullable CpuUsageComposite treeViewer = fTreeViewer; if (xyViewer != null && treeViewer != null) { - int core = signal.getCore(); - if (core >= 0) { - xyViewer.addCpu(core); - treeViewer.addCpu(core); + Object data = getData(CPU_USAGE_FOLLOW_CPU); + if (data == null) { + data = new TreeSet(); + } + if (data instanceof Set) { + Set set = (Set) data; + int core = signal.getCore(); + if (core >= 0) { + xyViewer.addCpu(core); + treeViewer.addCpu(core); + if (Iterables.all(set, Predicates.instanceOf(Integer.class))) { + @SuppressWarnings("unchecked") + Set intSet = (Set) set; + intSet.add(core); + } + } else { + xyViewer.clearCpu(); + treeViewer.clearCpu(); + ((Set) data).clear(); + } + saveData(CPU_USAGE_FOLLOW_CPU, data); } else { - xyViewer.clearCpu(); - treeViewer.clearCpu(); + Activator.getDefault().logError("The followed cores should have been store in a Set"); //$NON-NLS-1$ } } } diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/cpuusage/CpuUsageXYViewer.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/cpuusage/CpuUsageXYViewer.java index 4ec23effab..e7b9b8fe73 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/cpuusage/CpuUsageXYViewer.java +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/cpuusage/CpuUsageXYViewer.java @@ -33,6 +33,8 @@ import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler; import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal; import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceContext; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; import org.eclipse.tracecompass.tmf.ui.viewers.xycharts.linecharts.TmfCommonXLineChartViewer; @@ -293,15 +295,39 @@ public class CpuUsageXYViewer extends TmfCommonXLineChartViewer { @Override @TmfSignalHandler public void traceSelected(TmfTraceSelectedSignal signal) { - setSelectedThread(NOT_SELECTED); + initSelection(); + initCPU(); super.traceSelected(signal); } @Override @TmfSignalHandler public void traceOpened(TmfTraceOpenedSignal signal) { - setSelectedThread(NOT_SELECTED); + initSelection(); + initCPU(); super.traceOpened(signal); } + private void initSelection() { + TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext(); + String data = (String) ctx.getData(CpuUsageView.CPU_USAGE_SELECTED_THREAD); + long thread = data != null ? Long.valueOf(data) : NOT_SELECTED; + setSelectedThread(thread); + } + + private void initCPU() { + clearCpu(); + TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext(); + Object data = ctx.getData(CpuUsageView.CPU_USAGE_FOLLOW_CPU); + if (data instanceof Set) { + Set set = (Set) data; + for (Object coreObject : set) { + Integer core = (Integer) coreObject; + if (core != null && core >= 0) { + addCpu(core); + } + } + } + } + } diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/resources/ResourcesView.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/resources/ResourcesView.java index b33a600637..7a24ddc67b 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/resources/ResourcesView.java +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/resources/ResourcesView.java @@ -41,6 +41,8 @@ import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval; import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler; import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceContext; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; import org.eclipse.tracecompass.tmf.ui.views.timegraph.AbstractStateSystemTimeGraphView; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry; @@ -58,12 +60,13 @@ public class ResourcesView extends AbstractStateSystemTimeGraphView { /** View ID. */ public static final String ID = "org.eclipse.tracecompass.analysis.os.linux.views.resources"; //$NON-NLS-1$ + /** ID of the followed CPU in the map data in {@link TmfTraceContext} */ + public static final @NonNull String RESOURCES_FOLLOW_CPU = ID + ".FOLLOW_CPU"; //$NON-NLS-1$ + private static final String[] FILTER_COLUMN_NAMES = new String[] { Messages.ResourcesView_stateTypeName }; - private int fCurrentCpu = -1; - // Timeout between updates in the build thread in ms private static final long BUILD_UPDATE_TIMEOUT = 500; @@ -108,7 +111,10 @@ public class ResourcesView extends AbstractStateSystemTimeGraphView { if (sSel.getFirstElement() instanceof ResourcesEntry) { ResourcesEntry resourcesEntry = (ResourcesEntry) sSel.getFirstElement(); if (resourcesEntry.getType().equals(ResourcesEntry.Type.CPU)) { - if (fCurrentCpu >= 0) { + TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext(); + Integer data = (Integer) ctx.getData(RESOURCES_FOLLOW_CPU); + int cpu = data != null ? data.intValue() : -1; + if (cpu >= 0) { menuManager.add(new UnfollowCpuAction(ResourcesView.this, resourcesEntry.getId(), resourcesEntry.getTrace())); } else { menuManager.add(new FollowCpuAction(ResourcesView.this, resourcesEntry.getId(), resourcesEntry.getTrace())); @@ -440,11 +446,9 @@ public class ResourcesView extends AbstractStateSystemTimeGraphView { */ @TmfSignalHandler public void listenToCpu(TmfCpuSelectedSignal signal) { - if (signal.getCore() >= 0) { - fCurrentCpu = signal.getCore(); - } else { - fCurrentCpu = -1; - } + int data = signal.getCore() >= 0 ? signal.getCore() : -1; + TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext(); + ctx.setData(RESOURCES_FOLLOW_CPU, data); } } diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/TmfTraceContext.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/TmfTraceContext.java index a9ae523874..f87a88501b 100644 --- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/TmfTraceContext.java +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/TmfTraceContext.java @@ -14,13 +14,19 @@ package org.eclipse.tracecompass.tmf.core.trace; +import java.util.HashMap; +import java.util.Map; + import org.eclipse.core.resources.IFile; +import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.tracecompass.tmf.core.filter.ITmfFilter; import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange; import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp; +import com.google.common.collect.ImmutableMap; + /** * Context of a trace, which is the representation of the "view" the user * currently has on this trace (window time range, selected time or time range). @@ -42,6 +48,7 @@ public class TmfTraceContext implements ITraceContextSignalHandler { private final TmfTimeRange fWindowRange; private final @Nullable IFile fEditorFile; private final @Nullable ITmfFilter fFilter; + private final Map<@NonNull String, @NonNull Object> fData = new HashMap<>(); /** * Build a new trace context. @@ -61,6 +68,7 @@ public class TmfTraceContext implements ITraceContextSignalHandler { fWindowRange = windowRange; fEditorFile = editorFile; fFilter = filter; + fData.clear(); } /** @@ -99,6 +107,52 @@ public class TmfTraceContext implements ITraceContextSignalHandler { return fFilter; } + /** + * Store a data for the trace + * + * @param key + * The id of the data + * @param value + * The value of the data + * @since 2.1 + */ + public synchronized void setData(String key, Object value) { + fData.put(key, value); + } + + /** + * Copy data into the data map + * + * @param data + * The map of data to copy + * @since 2.1 + */ + public synchronized void setData(Map data) { + fData.putAll(data); + } + + /** + * Get the data for the specific key + * + * @param key + * The id of the data + * @return The data or null if the key do not exist + * @since 2.1 + */ + public synchronized @Nullable Object getData(String key) { + return fData.get(key); + } + + /** + * Get a copy of the data map + * + * @return The data map copy + * @since 2.1 + */ + public synchronized Map getData() { + return ImmutableMap.copyOf(fData); + } + @Override public String toString() { return getClass().getSimpleName() + "[fSelection=" + fSelection + //$NON-NLS-1$ diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/TmfTraceManager.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/TmfTraceManager.java index e819d31b11..eb28f3e157 100644 --- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/TmfTraceManager.java +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/TmfTraceManager.java @@ -37,11 +37,11 @@ import org.eclipse.jdt.annotation.Nullable; import org.eclipse.tracecompass.internal.tmf.core.Activator; import org.eclipse.tracecompass.tmf.core.TmfCommonConstants; import org.eclipse.tracecompass.tmf.core.signal.TmfEventFilterAppliedSignal; -import org.eclipse.tracecompass.tmf.core.signal.TmfTraceModelSignal; import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal; import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler; import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager; import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal; +import org.eclipse.tracecompass.tmf.core.signal.TmfTraceModelSignal; import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal; import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal; import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal; @@ -334,10 +334,12 @@ public final class TmfTraceManager { if (context == null) { throw new RuntimeException(); } - fTraces.put(newTrace, newTrace.createTraceContext(context.getSelectionRange(), + final TmfTraceContext newContext = newTrace.createTraceContext(context.getSelectionRange(), context.getWindowRange(), context.getEditorFile(), - signal.getEventFilter())); + signal.getEventFilter()); + newContext.setData(context.getData()); + fTraces.put(newTrace, newContext); } /** @@ -387,6 +389,7 @@ public final class TmfTraceManager { prevCtx.getWindowRange(), prevCtx.getEditorFile(), prevCtx.getFilter()); + newCtx.setData(prevCtx.getData()); entry.setValue(newCtx); } } @@ -420,6 +423,7 @@ public final class TmfTraceManager { /* Keep the values from the old context, except for the window range */ TmfTraceContext newCtx = trace.createTraceContext(prevCtx.getSelectionRange(), newWindowTr, prevCtx.getEditorFile(), prevCtx.getFilter()); + newCtx.setData(prevCtx.getData()); entry.setValue(newCtx); } }