blob: c4984db6e00d7b91e47c4709402179c62d0bd7b4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2016 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 views
*******************************************************************************/
package org.eclipse.tracecompass.analysis.os.linux.ui.views.resources;
import java.util.ArrayList;
import java.util.Collections;
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.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
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.ui.views.resources.ResourcesEntry.Type;
import org.eclipse.tracecompass.internal.analysis.os.linux.ui.Messages;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
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;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.NullTimeEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
/**
* Main implementation for the LTTng 2.0 kernel Resource view
*
* @author Patrick Tasse
*/
public class ResourcesView extends AbstractStateSystemTimeGraphView {
/** View ID. */
public static final String ID = "org.eclipse.tracecompass.analysis.os.linux.views.resources"; //$NON-NLS-1$
private static final String[] FILTER_COLUMN_NAMES = new String[] {
Messages.ResourcesView_stateTypeName
};
// Timeout between updates in the build thread in ms
private static final long BUILD_UPDATE_TIMEOUT = 500;
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
/**
* Default constructor
*/
public ResourcesView() {
super(ID, new ResourcesPresentationProvider());
setFilterColumns(FILTER_COLUMN_NAMES);
setFilterLabelProvider(new ResourcesFilterLabelProvider());
setEntryComparator(new ResourcesEntryComparator());
}
private static class ResourcesEntryComparator implements Comparator<ITimeGraphEntry> {
@Override
public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
ResourcesEntry entry1 = (ResourcesEntry) o1;
ResourcesEntry entry2 = (ResourcesEntry) o2;
if (entry1.getType() == Type.NULL && entry2.getType() == Type.NULL) {
/* sort trace entries alphabetically */
return entry1.getName().compareTo(entry2.getName());
}
/* sort resource entries by their defined order */
return entry1.compareTo(entry2);
}
}
private static class ResourcesFilterLabelProvider extends TreeLabelProvider {
@Override
public String getColumnText(Object element, int columnIndex) {
ResourcesEntry entry = (ResourcesEntry) element;
if (columnIndex == 0) {
return entry.getName();
}
return ""; //$NON-NLS-1$
}
}
// ------------------------------------------------------------------------
// Internal
// ------------------------------------------------------------------------
@Override
protected String getNextText() {
return Messages.ResourcesView_nextResourceActionNameText;
}
@Override
protected String getNextTooltip() {
return Messages.ResourcesView_nextResourceActionToolTipText;
}
@Override
protected String getPrevText() {
return Messages.ResourcesView_previousResourceActionNameText;
}
@Override
protected String getPrevTooltip() {
return Messages.ResourcesView_previousResourceActionToolTipText;
}
@Override
protected void buildEventList(ITmfTrace trace, ITmfTrace parentTrace, final IProgressMonitor monitor) {
final ITmfStateSystem ssq = TmfStateSystemAnalysisModule.getStateSystem(trace, KernelAnalysisModule.ID);
if (ssq == null) {
return;
}
Map<Integer, ResourcesEntry> entryMap = new HashMap<>();
TimeGraphEntry traceEntry = null;
long startTime = ssq.getStartTime();
long start = startTime;
setStartTime(Math.min(getStartTime(), startTime));
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;
}
long endTime = end + 1;
setEndTime(Math.max(getEndTime(), endTime));
if (traceEntry == null) {
traceEntry = new ResourcesEntry(trace, trace.getName(), startTime, endTime, 0);
List<TimeGraphEntry> entryList = Collections.singletonList(traceEntry);
addToEntryList(parentTrace, ssq, entryList);
} else {
traceEntry.updateEndTime(endTime);
}
List<Integer> cpuQuarks = ssq.getQuarks(Attributes.CPUS, "*"); //$NON-NLS-1$
for (Integer cpuQuark : cpuQuarks) {
int cpu = Integer.parseInt(ssq.getAttributeName(cpuQuark));
ResourcesEntry entry = entryMap.get(cpuQuark);
if (entry == null) {
entry = new ResourcesEntry(cpuQuark, trace, startTime, endTime, Type.CPU, cpu);
entryMap.put(cpuQuark, entry);
traceEntry.addChild(entry);
} else {
entry.updateEndTime(endTime);
}
}
List<Integer> irqQuarks = ssq.getQuarks(Attributes.RESOURCES, Attributes.IRQS, "*"); //$NON-NLS-1$
for (Integer irqQuark : irqQuarks) {
int irq = Integer.parseInt(ssq.getAttributeName(irqQuark));
ResourcesEntry entry = entryMap.get(irqQuark);
if (entry == null) {
entry = new ResourcesEntry(irqQuark, trace, startTime, endTime, Type.IRQ, irq);
entryMap.put(irqQuark, entry);
traceEntry.addChild(entry);
} else {
entry.updateEndTime(endTime);
}
}
List<Integer> softIrqQuarks = ssq.getQuarks(Attributes.RESOURCES, Attributes.SOFT_IRQS, "*"); //$NON-NLS-1$
for (Integer softIrqQuark : softIrqQuarks) {
int softIrq = Integer.parseInt(ssq.getAttributeName(softIrqQuark));
ResourcesEntry entry = entryMap.get(softIrqQuark);
if (entry == null) {
entry = new ResourcesEntry(softIrqQuark, trace, startTime, endTime, Type.SOFT_IRQ, softIrq);
entryMap.put(softIrqQuark, entry);
traceEntry.addChild(entry);
} else {
entry.updateEndTime(endTime);
}
}
if (parentTrace.equals(getTrace())) {
refresh();
}
final List<? extends ITimeGraphEntry> traceEntryChildren = traceEntry.getChildren();
final long resolution = Math.max(1, (endTime - ssq.getStartTime()) / getDisplayWidth());
final long qStart = start;
final long qEnd = end;
queryFullStates(ssq, qStart, qEnd, resolution, monitor, new IQueryHandler() {
@Override
public void handle(List<List<ITmfStateInterval>> fullStates, List<ITmfStateInterval> prevFullState) {
for (ITimeGraphEntry child : traceEntryChildren) {
if (monitor.isCanceled()) {
return;
}
if (child instanceof TimeGraphEntry) {
TimeGraphEntry entry = (TimeGraphEntry) child;
List<ITimeEvent> eventList = getEventList(entry, ssq, fullStates, prevFullState, monitor);
if (eventList != null) {
for (ITimeEvent event : eventList) {
entry.addEvent(event);
}
}
}
}
}
});
start = end;
}
}
@Override
protected @Nullable List<ITimeEvent> getEventList(@NonNull TimeGraphEntry entry, ITmfStateSystem ssq,
@NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState, @NonNull IProgressMonitor monitor) {
ResourcesEntry resourcesEntry = (ResourcesEntry) entry;
List<ITimeEvent> eventList = null;
int quark = resourcesEntry.getQuark();
if (resourcesEntry.getType().equals(Type.CPU)) {
int statusQuark;
try {
statusQuark = ssq.getQuarkRelative(quark, Attributes.STATUS);
} catch (AttributeNotFoundException e) {
/*
* The sub-attribute "status" is not available. May happen
* if the trace does not have sched_switch events enabled.
*/
return null;
}
eventList = new ArrayList<>(fullStates.size());
ITmfStateInterval lastInterval = prevFullState == null || statusQuark >= prevFullState.size() ? null : prevFullState.get(statusQuark);
long lastStartTime = lastInterval == null ? -1 : lastInterval.getStartTime();
long lastEndTime = lastInterval == null ? -1 : lastInterval.getEndTime() + 1;
for (List<ITmfStateInterval> fullState : fullStates) {
if (monitor.isCanceled()) {
return null;
}
if (statusQuark >= fullState.size()) {
/* No information on this cpu (yet?), skip it for now */
continue;
}
ITmfStateInterval statusInterval = fullState.get(statusQuark);
int status = statusInterval.getStateValue().unboxInt();
long time = statusInterval.getStartTime();
long duration = statusInterval.getEndTime() - time + 1;
if (time == lastStartTime) {
continue;
}
if (!statusInterval.getStateValue().isNull()) {
if (lastEndTime != time && lastEndTime != -1) {
eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime));
}
eventList.add(new TimeEvent(entry, time, duration, status));
} else {
eventList.add(new NullTimeEvent(entry, time, duration));
}
lastStartTime = time;
lastEndTime = time + duration;
}
} else if (resourcesEntry.getType().equals(Type.IRQ) || resourcesEntry.getType().equals(Type.SOFT_IRQ)) {
eventList = new ArrayList<>(fullStates.size());
ITmfStateInterval lastInterval = prevFullState == null ? null : prevFullState.get(quark);
long lastStartTime = lastInterval == null ? -1 : lastInterval.getStartTime();
long lastEndTime = lastInterval == null ? -1 : lastInterval.getEndTime() + 1;
boolean lastIsNull = lastInterval == null ? false : lastInterval.getStateValue().isNull();
for (List<ITmfStateInterval> fullState : fullStates) {
if (monitor.isCanceled()) {
return null;
}
ITmfStateInterval irqInterval = fullState.get(quark);
long time = irqInterval.getStartTime();
long duration = irqInterval.getEndTime() - time + 1;
if (time == lastStartTime) {
continue;
}
if (!irqInterval.getStateValue().isNull()) {
int cpu = irqInterval.getStateValue().unboxInt();
eventList.add(new TimeEvent(entry, time, duration, cpu));
lastIsNull = false;
} else {
if (lastEndTime != time && lastIsNull) {
/* This is a special case where we want to show IRQ_ACTIVE state but we don't know the CPU (it is between two null samples) */
eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime, -1));
}
eventList.add(new NullTimeEvent(entry, time, duration));
lastIsNull = true;
}
lastStartTime = time;
lastEndTime = time + duration;
}
}
return eventList;
}
}