From 0c85f6f28194bae576e94f45a771886fbdf70f60 Mon Sep 17 00:00:00 2001 From: Alexis Cabana-Loriaux Date: Fri, 7 Aug 2015 11:00:35 -0400 Subject: [PATCH] analysis: introduce context switch analysis Change-Id: Iccde08930c6111b93e16bab7d6d3e1b894c9c557 Signed-off-by: Alexis Cabana-Loriaux Signed-off-by: Matthew Khouzam Reviewed-on: https://git.eclipse.org/r/53413 Reviewed-by: Hudson CI Reviewed-by: Marc-Andre Laperle Tested-by: Marc-Andre Laperle --- .../META-INF/MANIFEST.MF | 5 +- .../plugin.properties | 2 + .../plugin.xml | 9 + .../KernelContextSwitchAnalysis.java | 172 ++++++++++++++++++ .../KernelContextSwitchStateProvider.java | 101 ++++++++++ 5 files changed, 287 insertions(+), 2 deletions(-) create mode 100644 analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/contextswitch/KernelContextSwitchAnalysis.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/contextswitch/KernelContextSwitchStateProvider.java diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF index 0a9a26759f..851d7838c1 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF @@ -16,8 +16,9 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.tracecompass.analysis.timing.core Import-Package: com.google.common.base, com.google.common.collect, - com.google.common.hash -Export-Package: org.eclipse.tracecompass.analysis.os.linux.core.cpuusage, + com.google.common.hash;version="15.0.0" +Export-Package: org.eclipse.tracecompass.analysis.os.linux.core.contextswitch, + org.eclipse.tracecompass.analysis.os.linux.core.cpuusage, org.eclipse.tracecompass.analysis.os.linux.core.event.aspect, org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis, org.eclipse.tracecompass.analysis.os.linux.core.latency, diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.properties b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.properties index dd1df79052..ca350c7c4a 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.properties +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.properties @@ -18,3 +18,5 @@ analysis.linuxkernel = Linux Kernel Analysis analysis.cpuusage = CPU usage analysis.latency = System Call Latency Analysis +analysis.contextswitch = Context switch analysis + diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.xml b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.xml index 82f22beb30..bb2d3c5999 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.xml +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.xml @@ -28,6 +28,15 @@ automatic="false" id="org.eclipse.tracecompass.analysis.os.linux.latency.syscall" name="%analysis.latency"> + + + + diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/contextswitch/KernelContextSwitchAnalysis.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/contextswitch/KernelContextSwitchAnalysis.java new file mode 100644 index 0000000000..52de044c08 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/contextswitch/KernelContextSwitchAnalysis.java @@ -0,0 +1,172 @@ +/******************************************************************************* + * Copyright (c) 2015 Ericsson + * + * 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: + * Alexis Cabana-Loriaux - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.analysis.os.linux.core.contextswitch; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.NonNullByDefault; +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.trace.IKernelAnalysisEventLayout; +import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace; +import org.eclipse.tracecompass.internal.analysis.os.linux.core.Activator; +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.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.analysis.IAnalysisModule; +import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider; +import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; + +/** + * This analysis module computes the number of context switches of a system from + * a kernel trace. + * + * @author Alexis Cabana-Loriaux + * @since 2.0 + */ +@NonNullByDefault +public class KernelContextSwitchAnalysis extends TmfStateSystemAnalysisModule { + + /** The ID of this analysis */ + public static final String ID = "org.eclipse.tracecompass.analysis.os.linux.contextswitch"; //$NON-NLS-1$ + + /** Integer used to identify 'total' entries in the returned maps */ + public static final Integer TOTAL = -1; + + @Override + protected ITmfStateProvider createStateProvider() { + ITmfTrace trace = checkNotNull(getTrace()); + IKernelAnalysisEventLayout layout; + + if (trace instanceof IKernelTrace) { + layout = ((IKernelTrace) trace).getKernelEventLayout(); + } else { + /* Fall-back to the base LttngEventLayout */ + layout = IKernelAnalysisEventLayout.DEFAULT_LAYOUT; + } + + return new KernelContextSwitchStateProvider(trace, layout); + } + + @Override + protected StateSystemBackendType getBackendType() { + return StateSystemBackendType.FULL; + } + + @Override + protected Iterable getDependentAnalyses() { + Set modules = new HashSet<>(); + + ITmfTrace trace = getTrace(); + if (trace == null) { + throw new IllegalStateException(); + } + /* + * This analysis depends on the LTTng kernel analysis, so it's added to + * dependent modules. + */ + Iterable kernelModules = TmfTraceUtils.getAnalysisModulesOfClass(trace, KernelAnalysisModule.class); + for (KernelAnalysisModule kernelModule : kernelModules) { + /* Only add the first one we find, if there is one */ + modules.add(kernelModule); + break; + } + return modules; + } + + /** + * Get a map of the number of context switch per CPU during a time range. + * + * @param startParam + * Start time of requested range + * @param endParam + * End time of requested range + * @return A map of CPU# -> nb of context switch in the [start, end] + * interval. CPU# == -1 represents the total number of context + * switch + * @throws TimeRangeException + * if one or more of the parameters is outside the range the + * state history + */ + public @NonNullByDefault({}) @NonNull Map getContextSwitchesRange(final long startParam, final long endParam) { + final @Nullable ITmfStateSystem stateSystem = getStateSystem(); + ITmfTrace trace = getTrace(); + if (trace == null || stateSystem == null) { + return Collections. emptyMap(); + } + long start = Math.max(startParam, stateSystem.getStartTime()); + long end = Math.min(endParam, stateSystem.getCurrentEndTime()); + ITmfStateSystem contextSwitchStateSystem = TmfStateSystemAnalysisModule.getStateSystem(trace, KernelContextSwitchAnalysis.ID); + if (contextSwitchStateSystem == null) { + return Collections. emptyMap(); + } + + /* + * Make sure the start/end times are within the state history, so we + * don't get TimeRange exceptions. + */ + long startTime = contextSwitchStateSystem.getStartTime(); + long endTime = contextSwitchStateSystem.getCurrentEndTime(); + if (endTime < startTime) { + return Collections. emptyMap(); + } + + Map map = new HashMap<>(); + try { + /* Get the list of quarks for each CPU */ + int cpusNode = contextSwitchStateSystem.getQuarkAbsolute(Attributes.CPUS); + List cpuQuarks = contextSwitchStateSystem.getSubAttributes(cpusNode, false); + /* Query full states at start and end times */ + List kernelEndState = contextSwitchStateSystem.queryFullState(end); + List kernelStartState = contextSwitchStateSystem.queryFullState(start); + Long totalNbCxtSwt = 0l; + for (Integer cpuQuark : cpuQuarks) { + int cpuNb = Integer.parseInt(contextSwitchStateSystem.getAttributeName(cpuQuark.intValue())); + Long nbCxtSwtForCore = kernelEndState.get(cpuQuark).getStateValue().unboxLong() - kernelStartState.get(cpuQuark).getStateValue().unboxLong(); + map.put(cpuNb, nbCxtSwtForCore); + totalNbCxtSwt += nbCxtSwtForCore; + } + + /* Put the total number of context switches in the interval */ + map.put(TOTAL, totalNbCxtSwt); + } catch (TimeRangeException | AttributeNotFoundException e) { + /* + * Assume there is no events or the attribute does not exist yet, + * nothing will be put in the map. + */ + } catch (StateValueTypeException | StateSystemDisposedException e) { + /* + * These other exception types would show a logic problem, so they + * should not happen. + */ + Activator.getDefault().logError("Error getting CPU context switches in a time range", e); //$NON-NLS-1$ + } + + return map; + } + +} diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/contextswitch/KernelContextSwitchStateProvider.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/contextswitch/KernelContextSwitchStateProvider.java new file mode 100644 index 0000000000..c106fcf1a6 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/contextswitch/KernelContextSwitchStateProvider.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2015 Ericsson + * + * 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: + * Alexis Cabana-Loriaux - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.analysis.os.linux.core.contextswitch; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.Attributes; +import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout; +import org.eclipse.tracecompass.common.core.NonNullUtils; +import org.eclipse.tracecompass.internal.analysis.os.linux.core.Activator; +import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder; +import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; +import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException; +import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; +import org.eclipse.tracecompass.tmf.core.event.aspect.TmfCpuAspect; +import org.eclipse.tracecompass.tmf.core.statesystem.AbstractTmfStateProvider; +import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; + +/** + * Class used to build a state system of the context switches of a trace + * + * @author Alexis Cabana-Loriaux + * @since 2.0 + */ +@NonNullByDefault +public class KernelContextSwitchStateProvider extends AbstractTmfStateProvider { + + private static final String ID = "org.eclipse.tracecompass.analysis.os.linux.contextswitch.stateprovider"; //$NON-NLS-1$ + private static final int STARTING_QUARK = -1; + private int fCpuAttributeQuark = STARTING_QUARK; + private @Nullable ITmfStateSystemBuilder fStateSystemBuilder; + private IKernelAnalysisEventLayout fLayout; + + /** + * Default constructor + * + * @param trace + * the trace + * @param layout + * the associated layout + */ + public KernelContextSwitchStateProvider(ITmfTrace trace, IKernelAnalysisEventLayout layout) { + super(trace, ID); + fLayout = layout; + } + + @Override + public int getVersion() { + return 1; + } + + @Override + public ITmfStateProvider getNewInstance() { + return new KernelContextSwitchStateProvider(getTrace(), fLayout); + } + + /* + * Classify sched_switch events for every CPU + */ + @Override + protected void eventHandle(ITmfEvent event) { + ITmfStateSystemBuilder stateSystemBuilder = fStateSystemBuilder; + if (stateSystemBuilder == null) { + stateSystemBuilder = (ITmfStateSystemBuilder) getAssignedStateSystem(); + fStateSystemBuilder = stateSystemBuilder; + } + if (stateSystemBuilder == null) { + return; + } + if (fCpuAttributeQuark == STARTING_QUARK) { + fCpuAttributeQuark = stateSystemBuilder.getQuarkAbsoluteAndAdd(Attributes.CPUS); + } + if (event.getName().equals(fLayout.eventSchedSwitch())) { + Object cpuObj = TmfTraceUtils.resolveEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event); + if (cpuObj == null) { + /* We couldn't find any CPU information, ignore this event */ + return; + } + int cpuQuark = stateSystemBuilder.getQuarkRelativeAndAdd(fCpuAttributeQuark, cpuObj.toString()); + try { + stateSystemBuilder.incrementAttribute(event.getTimestamp().getValue(), cpuQuark); + } catch (StateValueTypeException | AttributeNotFoundException e) { + Activator.getDefault().logError(NonNullUtils.nullToEmptyString(e.getMessage()), e); + } + } + + } + +} -- 2.34.1