/*******************************************************************************
* Copyright (c) 2014, 2017 É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
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Geneviève Bastien - Initial API and implementation
*******************************************************************************/
package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.cpuusage;
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;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
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
* plotting the total time spent on CPU and the time of the threads selected in
* the tree viewer.
*
* @author Geneviève Bastien
*/
public class CpuUsageView extends TmfChartView {
/** ID string */
public static final @NonNull 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;
/**
* Constructor
*/
public CpuUsageView() {
super(Messages.CpuUsageView_Title);
}
@Override
public void createPartControl(Composite parent) {
super.createPartControl(parent);
/* Initialize the viewers with the currently selected trace */
ITmfTrace trace = TmfTraceManager.getInstance().getActiveTrace();
if (trace != null) {
TmfTraceSelectedSignal signal = new TmfTraceSelectedSignal(this, trace);
if (fTreeViewer != null) {
fTreeViewer.traceSelected(signal);
}
if (fXYViewer != null) {
fXYViewer.traceSelected(signal);
}
}
}
@Override
protected TmfXYChartViewer createChartViewer(Composite parent) {
CpuUsageXYViewer viewer = new CpuUsageXYViewer(parent);
viewer.setSendTimeAlignSignals(true);
fXYViewer = viewer;
return viewer;
}
@Override
public TmfViewer createLeftChildViewer(Composite parent) {
final CpuUsageComposite viewer = new CpuUsageComposite(parent);
/* Add selection listener to tree viewer */
viewer.addSelectionChangeListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = event.getSelection();
if (selection instanceof IStructuredSelection) {
Object structSelection = ((IStructuredSelection) selection).getFirstElement();
if (structSelection instanceof CpuUsageEntry) {
CpuUsageEntry entry = (CpuUsageEntry) structSelection;
if (fTreeViewer != null) {
fTreeViewer.setSelectedThread(entry.getTid());
}
if (fXYViewer != null) {
fXYViewer.setSelectedThread(Long.valueOf(entry.getTid()));
}
saveData(CPU_USAGE_SELECTED_THREAD, entry.getTid());
}
}
}
});
viewer.getControl().addControlListener(new ControlAdapter() {
@Override
public void controlResized(ControlEvent e) {
super.controlResized(e);
}
});
fTreeViewer = viewer;
return fTreeViewer;
}
/**
* Save a data in the data map of {@link TmfTraceContext}
*/
private void saveData(@NonNull String key, @NonNull Object data) {
ITmfTrace trace = getViewerTrace();
if (trace == null) {
return;
}
TmfTraceManager.getInstance().updateTraceContext(trace,
builder -> builder.setData(key, data));
}
private Object getData(@NonNull String key) {
ITmfTrace trace = getViewerTrace();
if (trace == null) {
return null;
}
TmfTraceContext ctx = TmfTraceManager.getInstance().getTraceContext(trace);
return ctx.getData(key);
}
private ITmfTrace getViewerTrace() {
CpuUsageComposite treeViewer = fTreeViewer;
return (treeViewer != null) ? treeViewer.getTrace() : null;
}
@Override
public void setFocus() {
if (fXYViewer != null) {
fXYViewer.getControl().setFocus();
}
}
/**
* Signal handler for when a cpu is selected
*
* @param signal
* the cpu being selected
* @since 2.0
*/
@TmfSignalHandler
public void cpuSelect(TmfCpuSelectedSignal signal) {
final @Nullable CpuUsageXYViewer xyViewer = fXYViewer;
final @Nullable CpuUsageComposite treeViewer = fTreeViewer;
if (xyViewer != null && treeViewer != null) {
Object data = getData(CPU_USAGE_FOLLOW_CPU);
if (data == null) {
data = new TreeSet<Integer>();
}
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<Integer> intSet = (Set<Integer>) set;
intSet.add(core);
}
} else {
xyViewer.clearCpu();
treeViewer.clearCpu();
((Set<?>) data).clear();
}
saveData(CPU_USAGE_FOLLOW_CPU, data);
} else {
Activator.getDefault().logError("The followed cores should have been store in a Set"); //$NON-NLS-1$
}
}
}
}