/*******************************************************************************
- * Copyright (c) 2012, 2015 Ericsson, École Polytechnique de Montréal
+ * 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
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+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.core.kernel.Attributes;
+import org.eclipse.tracecompass.analysis.os.linux.core.kernel.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.StateSystemUtils;
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
-import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
-import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
-import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
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.AbstractTimeGraphView;
+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;
*
* @author Patrick Tasse
*/
-public class ResourcesView extends AbstractTimeGraphView {
+public class ResourcesView extends AbstractStateSystemTimeGraphView {
/** View ID. */
public static final String ID = "org.eclipse.tracecompass.analysis.os.linux.views.resources"; //$NON-NLS-1$
public ResourcesView() {
super(ID, new ResourcesPresentationProvider());
setFilterColumns(FILTER_COLUMN_NAMES);
+ setFilterLabelProvider(new ResourcesFilterLabelProvider());
+ setEntryComparator(new ResourcesEntryComparator());
+ setAutoExpandLevel(1);
+ }
+
+ 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$
+ }
+
}
// ------------------------------------------------------------------------
}
@Override
- protected void buildEventList(ITmfTrace trace, ITmfTrace parentTrace, IProgressMonitor monitor) {
- ITmfStateSystem ssq = TmfStateSystemAnalysisModule.getStateSystem(trace, KernelAnalysisModule.ID);
+ protected void buildEventList(ITmfTrace trace, ITmfTrace parentTrace, final IProgressMonitor monitor) {
+ final ITmfStateSystem ssq = TmfStateSystemAnalysisModule.getStateSystem(trace, KernelAnalysisModule.ID);
if (ssq == null) {
return;
}
- Comparator<ITimeGraphEntry> comparator = new Comparator<ITimeGraphEntry>() {
- @Override
- public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
- return ((ResourcesEntry) o1).compareTo(o2);
- }
- };
Map<Integer, ResourcesEntry> entryMap = new HashMap<>();
TimeGraphEntry traceEntry = null;
return;
}
long end = ssq.getCurrentEndTime();
- if (start == end && !complete) { // when complete execute one last time regardless of end time
+ if (start == end && !complete) {
+ // when complete execute one last time regardless of end time
continue;
}
long endTime = end + 1;
if (traceEntry == null) {
traceEntry = new ResourcesEntry(trace, trace.getName(), startTime, endTime, 0);
- traceEntry.sortChildren(comparator);
List<TimeGraphEntry> entryList = Collections.singletonList(traceEntry);
- addToEntryList(parentTrace, entryList);
+ 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);
- }
- }
-
+ createCpuEntriesWithQuark(trace, ssq, entryMap, traceEntry, startTime, endTime, cpuQuarks);
if (parentTrace.equals(getTrace())) {
refresh();
}
- long resolution = Math.max(1, (endTime - ssq.getStartTime()) / getDisplayWidth());
- for (ITimeGraphEntry child : traceEntry.getChildren()) {
- if (monitor.isCanceled()) {
- return;
+ 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 (!populateEventsRecursively(fullStates, prevFullState, child).isOK()) {
+ return;
+ }
+ }
}
- if (child instanceof TimeGraphEntry) {
- TimeGraphEntry entry = (TimeGraphEntry) child;
- List<ITimeEvent> eventList = getEventList(entry, start, endTime, resolution, monitor);
- if (eventList != null) {
- for (ITimeEvent event : eventList) {
- entry.addEvent(event);
+
+ private IStatus populateEventsRecursively(@NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState, ITimeGraphEntry entry) {
+ if (monitor.isCanceled()) {
+ return Status.CANCEL_STATUS;
+ }
+ if (entry instanceof TimeGraphEntry) {
+ TimeGraphEntry timeGraphEntry = (TimeGraphEntry) entry;
+ List<ITimeEvent> eventList = getEventList(timeGraphEntry, ssq, fullStates, prevFullState, monitor);
+ if (eventList != null) {
+ for (ITimeEvent event : eventList) {
+ timeGraphEntry.addEvent(event);
+ }
}
}
- redraw();
+ for (ITimeGraphEntry child : entry.getChildren()) {
+ IStatus status = populateEventsRecursively(fullStates, prevFullState, child);
+ if (!status.isOK()) {
+ return status;
+ }
+ }
+ return Status.OK_STATUS;
}
- }
+ });
start = end;
}
+
+ }
+
+ private static void createCpuEntriesWithQuark(@NonNull ITmfTrace trace, final ITmfStateSystem ssq, Map<Integer, ResourcesEntry> entryMap, TimeGraphEntry traceEntry, long startTime, long endTime, List<Integer> cpuQuarks) {
+ for (Integer cpuQuark : cpuQuarks) {
+ final @NonNull String cpuName = ssq.getAttributeName(cpuQuark);
+ int cpu = Integer.parseInt(cpuName);
+ ResourcesEntry cpuEntry = entryMap.get(cpuQuark);
+ if (cpuEntry == null) {
+ cpuEntry = new ResourcesEntry(cpuQuark, trace, startTime, endTime, Type.CPU, cpu);
+ entryMap.put(cpuQuark, cpuEntry);
+ traceEntry.addChild(cpuEntry);
+ } else {
+ cpuEntry.updateEndTime(endTime);
+ }
+ List<Integer> irqQuarks = ssq.getQuarks(Attributes.CPUS, cpuName, Attributes.IRQS, "*"); //$NON-NLS-1$
+ createCpuInterruptEntryWithQuark(trace, ssq, entryMap, startTime, endTime, traceEntry, cpuEntry, irqQuarks, Type.IRQ);
+ List<Integer> softIrqQuarks = ssq.getQuarks(Attributes.CPUS, cpuName, Attributes.SOFT_IRQS, "*"); //$NON-NLS-1$
+ createCpuInterruptEntryWithQuark(trace, ssq, entryMap, startTime, endTime, traceEntry, cpuEntry, softIrqQuarks, Type.SOFT_IRQ);
+ }
+ }
+
+ /**
+ * Create and add execution contexts to a cpu entry. Also creates an
+ * aggregate entry in the root trace entry. The execution context is
+ * basically what the cpu is doing in its execution stack. It can be in an
+ * IRQ, Soft IRQ. MCEs, NMIs, Userland and Kernel execution is not yet
+ * supported.
+ *
+ * @param trace
+ * the trace
+ * @param ssq
+ * the state system
+ * @param entryMap
+ * the entry map
+ * @param startTime
+ * the start time in nanoseconds
+ * @param endTime
+ * the end time in nanoseconds
+ * @param traceEntry
+ * the trace timegraph entry
+ * @param cpuEntry
+ * the cpu timegraph entry (the entry under the trace entry
+ * @param childrenQuarks
+ * the quarks to add to cpu entry
+ * @param type
+ * the type of entry being added
+ */
+ private static void createCpuInterruptEntryWithQuark(@NonNull ITmfTrace trace,
+ final ITmfStateSystem ssq, Map<Integer, ResourcesEntry> entryMap,
+ long startTime, long endTime,
+ TimeGraphEntry traceEntry, ResourcesEntry cpuEntry,
+ List<Integer> childrenQuarks, Type type) {
+ for (Integer quark : childrenQuarks) {
+ final @NonNull String resourceName = ssq.getAttributeName(quark);
+ int resourceId = Integer.parseInt(resourceName);
+ ResourcesEntry interruptEntry = entryMap.get(quark);
+ if (interruptEntry == null) {
+ interruptEntry = new ResourcesEntry(quark, trace, startTime, endTime, type, resourceId);
+ entryMap.put(quark, interruptEntry);
+ cpuEntry.addChild(interruptEntry);
+ boolean found = false;
+ for (ITimeGraphEntry rootElem : traceEntry.getChildren()) {
+ if (rootElem instanceof AggregateResourcesEntry) {
+ AggregateResourcesEntry aggregateInterruptEntry = (AggregateResourcesEntry) rootElem;
+ if (aggregateInterruptEntry.getId() == resourceId && aggregateInterruptEntry.getType().equals(type)) {
+ found = true;
+ aggregateInterruptEntry.addContributor(interruptEntry);
+ final AggregateResourcesEntry irqCpuEntry = new AggregateResourcesEntry(trace, cpuEntry.getName(), startTime, endTime, type, cpuEntry.getId());
+ irqCpuEntry.addContributor(interruptEntry);
+ aggregateInterruptEntry.addChild(irqCpuEntry);
+ break;
+ }
+ }
+ }
+ if (!found) {
+ AggregateResourcesEntry aggregateInterruptEntry = new AggregateResourcesEntry(trace, startTime, endTime, type, resourceId);
+ aggregateInterruptEntry.addContributor(interruptEntry);
+ final AggregateResourcesEntry irqCpuEntry = new AggregateResourcesEntry(trace, cpuEntry.getName(), startTime, endTime, type, cpuEntry.getId());
+ irqCpuEntry.addContributor(interruptEntry);
+ aggregateInterruptEntry.addChild(irqCpuEntry);
+ traceEntry.addChild(aggregateInterruptEntry);
+ }
+ } else {
+ interruptEntry.updateEndTime(endTime);
+ }
+ }
}
@Override
- protected @Nullable List<ITimeEvent> getEventList(TimeGraphEntry entry,
- long startTime, long endTime, long resolution,
- IProgressMonitor monitor) {
+ 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;
- ITmfStateSystem ssq = TmfStateSystemAnalysisModule.getStateSystem(resourcesEntry.getTrace(), KernelAnalysisModule.ID);
- if (ssq == null) {
- return null;
+ int quark = resourcesEntry.getQuark();
+
+ if (resourcesEntry.getType().equals(Type.CPU)) {
+ return createCpuEventsList(entry, ssq, fullStates, prevFullState, monitor, quark);
+ } else if ((resourcesEntry.getType().equals(Type.IRQ) || resourcesEntry.getType().equals(Type.SOFT_IRQ)) && (quark >= 0)) {
+ return createIrqEventsList(entry, fullStates, prevFullState, monitor, quark);
}
- final long realStart = Math.max(startTime, ssq.getStartTime());
- final long realEnd = Math.min(endTime, ssq.getCurrentEndTime() + 1);
- if (realEnd <= realStart) {
+
+ return null;
+ }
+
+ private static List<ITimeEvent> createCpuEventsList(TimeGraphEntry entry, ITmfStateSystem ssq, List<List<ITmfStateInterval>> fullStates, List<ITmfStateInterval> prevFullState, IProgressMonitor monitor, int quark) {
+ List<ITimeEvent> eventList;
+ 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;
}
- List<ITimeEvent> eventList = null;
- int quark = resourcesEntry.getQuark();
+ 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;
+ }
+ return eventList;
+ }
- try {
- if (resourcesEntry.getType().equals(Type.CPU)) {
- int statusQuark;
- try {
- statusQuark = ssq.getQuarkRelative(quark, Attributes.STATUS);
- } catch (AttributeNotFoundException e) {
+ private static List<ITimeEvent> createIrqEventsList(TimeGraphEntry entry, List<List<ITmfStateInterval>> fullStates, List<ITmfStateInterval> prevFullState, IProgressMonitor monitor, int quark) {
+ List<ITimeEvent> eventList;
+ eventList = new ArrayList<>(fullStates.size());
+ ITmfStateInterval lastInterval = prevFullState == null || quark >= prevFullState.size() ? 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;
+ }
+ if (quark >= fullState.size()) {
+ /* No information on this IRQ (yet?), skip it for now */
+ continue;
+ }
+ 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) {
/*
- * The sub-attribute "status" is not available. May happen
- * if the trace does not have sched_switch events enabled.
+ * 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)
*/
- return null;
- }
- List<ITmfStateInterval> statusIntervals = StateSystemUtils.queryHistoryRange(ssq, statusQuark, realStart, realEnd - 1, resolution, monitor);
- eventList = new ArrayList<>(statusIntervals.size());
- long lastEndTime = -1;
- for (ITmfStateInterval statusInterval : statusIntervals) {
- if (monitor.isCanceled()) {
- return null;
- }
- int status = statusInterval.getStateValue().unboxInt();
- long time = statusInterval.getStartTime();
- long duration = statusInterval.getEndTime() - time + 1;
- 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 if (lastEndTime == -1 || time + duration >= endTime) {
- // add null event if it intersects the start or end time
- eventList.add(new NullTimeEvent(entry, time, duration));
- }
- lastEndTime = time + duration;
- }
- } else if (resourcesEntry.getType().equals(Type.IRQ)) {
- List<ITmfStateInterval> irqIntervals = StateSystemUtils.queryHistoryRange(ssq, quark, realStart, realEnd - 1, resolution, monitor);
- eventList = new ArrayList<>(irqIntervals.size());
- long lastEndTime = -1;
- boolean lastIsNull = true;
- for (ITmfStateInterval irqInterval : irqIntervals) {
- if (monitor.isCanceled()) {
- return null;
- }
- long time = irqInterval.getStartTime();
- long duration = irqInterval.getEndTime() - time + 1;
- if (!irqInterval.getStateValue().isNull()) {
- int cpu = irqInterval.getStateValue().unboxInt();
- eventList.add(new TimeEvent(entry, time, duration, cpu));
- lastIsNull = false;
- } else {
- if (lastEndTime == -1) {
- // add null event if it intersects the start time
- eventList.add(new NullTimeEvent(entry, time, duration));
- } 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));
- }
- if (time + duration >= endTime) {
- // add null event if it intersects the end time
- eventList.add(new NullTimeEvent(entry, time, duration));
- }
- }
- lastIsNull = true;
- }
- lastEndTime = time + duration;
- }
- } else if (resourcesEntry.getType().equals(Type.SOFT_IRQ)) {
- List<ITmfStateInterval> softIrqIntervals = StateSystemUtils.queryHistoryRange(ssq, quark, realStart, realEnd - 1, resolution, monitor);
- eventList = new ArrayList<>(softIrqIntervals.size());
- long lastEndTime = -1;
- boolean lastIsNull = true;
- for (ITmfStateInterval softIrqInterval : softIrqIntervals) {
- if (monitor.isCanceled()) {
- return null;
- }
- long time = softIrqInterval.getStartTime();
- long duration = softIrqInterval.getEndTime() - time + 1;
- if (!softIrqInterval.getStateValue().isNull()) {
- int cpu = softIrqInterval.getStateValue().unboxInt();
- eventList.add(new TimeEvent(entry, time, duration, cpu));
- } else {
- if (lastEndTime == -1) {
- // add null event if it intersects the start time
- eventList.add(new NullTimeEvent(entry, time, duration));
- } 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));
- }
- if (time + duration >= endTime) {
- // add null event if it intersects the end time
- eventList.add(new NullTimeEvent(entry, time, duration));
- }
- }
- lastIsNull = true;
- }
- lastEndTime = time + duration;
+ eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime, -1));
}
+ eventList.add(new NullTimeEvent(entry, time, duration));
+ lastIsNull = true;
}
-
- } catch (AttributeNotFoundException | TimeRangeException | StateValueTypeException e) {
- e.printStackTrace();
- } catch (StateSystemDisposedException e) {
- /* Ignored */
+ lastStartTime = time;
+ lastEndTime = time + duration;
}
return eventList;
}