From: Matthew Khouzam Date: Wed, 6 Apr 2016 00:20:11 +0000 (-0400) Subject: linux.core: Introduce TID analysis X-Git-Url: http://git.efficios.com/?a=commitdiff_plain;h=d8e841d96dda449fc56172b0443e87916b458057;p=deliverable%2Ftracecompass.git linux.core: Introduce TID analysis This analysis calculates a subset of what the kernel state system has: which tid is running on which cpu. This will allow these aspects to be available much faster during state construction and in the reading after. The new state system is typically 1% of the size of the kernel state system. Therefore the seeks, even though they are log(n) will accelerate. As getTid is something MANY analyses do often this patch should improve performance accross the board. In one corner case example, (System call analysis), where each state required a TID, performance passed from 3000 to 140000 events per seconds. On average, searches on the TID column should reduce in time by 5-10% depending on the trace configuration (how many contexts etc...). Change-Id: Icf7921c49232481129b9c021170556c9d06d5ca4 Signed-off-by: Matthew Khouzam Reviewed-on: https://git.eclipse.org/r/68878 Reviewed-by: Genevieve Bastien Tested-by: Genevieve Bastien Reviewed-by: Marc-Andre Laperle Reviewed-by: Hudson CI --- diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/kernel/KernelTidAspectTest.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/kernel/KernelTidAspectTest.java index 41b95e04d6..beb4b93a15 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/kernel/KernelTidAspectTest.java +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/kernel/KernelTidAspectTest.java @@ -11,15 +11,16 @@ package org.eclipse.tracecompass.analysis.os.linux.core.tests.kernel; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import java.io.File; +import java.util.ArrayList; +import java.util.List; import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule; import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelTidAspect; import org.eclipse.tracecompass.analysis.os.linux.core.tests.stubs.LinuxTestCase; import org.eclipse.tracecompass.analysis.os.linux.core.tests.stubs.kernel.KernelAnalysisTestFactory; +import org.eclipse.tracecompass.analysis.os.linux.core.tid.TidAnalysisModule; import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule; import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal; @@ -65,7 +66,7 @@ public class KernelTidAspectTest { /* Make sure the Kernel analysis has run */ ((TmfTrace) trace).traceOpened(new TmfTraceOpenedSignal(this, trace, null)); IAnalysisModule module = null; - for (IAnalysisModule mod : TmfTraceUtils.getAnalysisModulesOfClass(trace, KernelAnalysisModule.class)) { + for (IAnalysisModule mod : TmfTraceUtils.getAnalysisModulesOfClass(trace, TidAnalysisModule.class)) { module = mod; } assertNotNull(module); @@ -82,18 +83,11 @@ public class KernelTidAspectTest { fTrace.dispose(); } - private void resolveNextEvent(ITmfContext context, Integer tid) { + private Integer resolveNextEvent(ITmfContext context) { ITmfTrace trace = fTrace; ITmfEvent event = trace.getNext(context); assertNotNull(event); - - Object tidObj = TmfTraceUtils.resolveEventAspectOfClassForEvent(trace, KernelTidAspect.class, event); - if (tid == null) { - assertNull(tidObj); - } else { - assertNotNull(tidObj); - assertEquals(tid, tidObj); - } + return (Integer) TmfTraceUtils.resolveEventAspectOfClassForEvent(trace, KernelTidAspect.class, event); } /** @@ -103,19 +97,26 @@ public class KernelTidAspectTest { public void testResolveTidAspect() { ITmfContext context = fTrace.seekEvent(0L); - resolveNextEvent(context, null); - resolveNextEvent(context, null); - resolveNextEvent(context, null); - resolveNextEvent(context, 11); - resolveNextEvent(context, null); - resolveNextEvent(context, null); - resolveNextEvent(context, 20); - resolveNextEvent(context, 20); - resolveNextEvent(context, 21); - resolveNextEvent(context, 11); - resolveNextEvent(context, 30); - resolveNextEvent(context, 21); - resolveNextEvent(context, 20); + List expected = new ArrayList<>(); + expected.add(null); + expected.add(null); + expected.add(null); + expected.add(11); + expected.add(null); + expected.add(null); + expected.add(20); + expected.add(20); + expected.add(21); + expected.add(11); + expected.add(30); + expected.add(21); + expected.add(20); + List tids = new ArrayList<>(); + + for (int i = 0; i < expected.size(); i++) { + tids.add(resolveNextEvent(context)); + } + assertEquals(expected, tids); } } diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/stubs/org/eclipse/tracecompass/analysis/os/linux/core/tests/stubs/trace/TmfXmlKernelTraceStub.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/stubs/org/eclipse/tracecompass/analysis/os/linux/core/tests/stubs/trace/TmfXmlKernelTraceStub.java index 8379931275..b5a53886f0 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/stubs/org/eclipse/tracecompass/analysis/os/linux/core/tests/stubs/trace/TmfXmlKernelTraceStub.java +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/stubs/org/eclipse/tracecompass/analysis/os/linux/core/tests/stubs/trace/TmfXmlKernelTraceStub.java @@ -10,8 +10,8 @@ package org.eclipse.tracecompass.analysis.os.linux.core.tests.stubs.trace; import org.eclipse.jdt.annotation.Nullable; -import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelTidAspect; import org.eclipse.tracecompass.analysis.os.linux.core.event.aspect.ThreadPriorityAspect; +import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelTidAspect; import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout; import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace; import org.eclipse.tracecompass.tmf.core.event.aspect.ITmfEventAspect; 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 1ee4a17503..7a09596bc5 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 @@ -28,6 +28,7 @@ Export-Package: org.eclipse.tracecompass.analysis.os.linux.core.contextswitch, org.eclipse.tracecompass.analysis.os.linux.core.latency, org.eclipse.tracecompass.analysis.os.linux.core.model, org.eclipse.tracecompass.analysis.os.linux.core.signals, + org.eclipse.tracecompass.analysis.os.linux.core.tid, org.eclipse.tracecompass.analysis.os.linux.core.trace, org.eclipse.tracecompass.internal.analysis.os.linux.core;x-internal:=true, org.eclipse.tracecompass.internal.analysis.os.linux.core.inputoutput;x-friends:="org.eclipse.tracecompass.analysis.os.linux.core.tests", diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/icons/threads.png b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/icons/threads.png new file mode 100644 index 0000000000..59f3ffd3b3 Binary files /dev/null and b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/icons/threads.png differ 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 da9e549812..1404147ce7 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.properties +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.properties @@ -21,3 +21,4 @@ analysis.latency = System Call Latency analysis.contextswitch = Context switch analysis.kernelmemory = Kernel memory usage analysis.io = Input/Output +analysis.tid = Active Thread 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 29c0d4b834..300647bcae 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.xml +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.xml @@ -28,11 +28,11 @@ 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/kernel/KernelTidAspect.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/kernel/KernelTidAspect.java index 6696abb585..e2a2a6d9cd 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/kernel/KernelTidAspect.java +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/kernel/KernelTidAspect.java @@ -14,6 +14,7 @@ package org.eclipse.tracecompass.analysis.os.linux.core.kernel; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.tracecompass.analysis.os.linux.core.event.aspect.LinuxTidAspect; +import org.eclipse.tracecompass.analysis.os.linux.core.tid.TidAnalysisModule; import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; import org.eclipse.tracecompass.tmf.core.event.aspect.TmfCpuAspect; import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; @@ -43,17 +44,12 @@ public final class KernelTidAspect extends LinuxTidAspect { } /* Find the analysis module for the trace */ - KernelAnalysisModule analysis = TmfTraceUtils.getAnalysisModuleOfClass(event.getTrace(), - KernelAnalysisModule.class, KernelAnalysisModule.ID); + TidAnalysisModule analysis = TmfTraceUtils.getAnalysisModuleOfClass(event.getTrace(), + TidAnalysisModule.class, TidAnalysisModule.ID); if (analysis == null) { return null; } - Integer tid = KernelThreadInformationProvider.getThreadOnCpu( - analysis, cpu, event.getTimestamp().getValue()); - if (tid != null) { - return tid; - } - return null; + return analysis.getThreadOnCpuAtTime(cpu, event.getTimestamp().toNanos()); } } diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/tid/ActiveTidStateProvider.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/tid/ActiveTidStateProvider.java new file mode 100644 index 0000000000..b15bcf9339 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/tid/ActiveTidStateProvider.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2016 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 + *******************************************************************************/ + +package org.eclipse.tracecompass.analysis.os.linux.core.tid; + +import java.util.Map; +import java.util.TreeMap; + +import org.eclipse.jdt.annotation.NonNull; +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.statesystem.core.statevalue.TmfStateValue; +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; + +/** + * Active TID state provider, this only does one thing: figure out the active + * TID on any given CPU. This state provider is designed to do one thing and do + * it fast. + * + * Note: this state provider exists as a way to accelerate the TID aspect, but + * also to start splitting up the kernel analysis into smaller sections. + * + * Note 2: this is deliberately only package visible. + * + * @author Matthew Khouzam + */ +class ActiveTidStateProvider extends AbstractTmfStateProvider { + + private static final @NonNull String PROVIDER_ID = "activeTidAnalysis.provider"; //$NON-NLS-1$ + private static final int VERSION = 0; + + private final Map fCpuNumToQuark = new TreeMap<>(); + private final @NonNull String fSchedSwitch; + private final @NonNull String fNextTid; + private final @NonNull IKernelAnalysisEventLayout fLayout; + + public ActiveTidStateProvider(@NonNull ITmfTrace trace, @NonNull IKernelAnalysisEventLayout layout) { + super(trace, PROVIDER_ID); + fSchedSwitch = layout.eventSchedSwitch(); + fNextTid = layout.fieldNextTid(); + fLayout = layout; + } + + @Override + public int getVersion() { + return VERSION; + } + + @Override + public @NonNull ITmfStateProvider getNewInstance() { + return new ActiveTidStateProvider(getTrace(), fLayout); + } + + @Override + protected void eventHandle(@NonNull ITmfEvent event) { + Integer cpu = TmfTraceUtils.resolveIntEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event); + if (cpu == null) { + return; + } + if (!event.getName().equals(fSchedSwitch)) { + return; + } + ITmfStateSystemBuilder ssb = getStateSystemBuilder(); + if (ssb == null) { + return; + } + try { + Integer cpuQuark = fCpuNumToQuark.get(cpu); + if (cpuQuark == null) { + String cpuAttributeName = NonNullUtils.nullToEmptyString(cpu); + cpuQuark = ssb.getQuarkAbsoluteAndAdd(cpuAttributeName); + fCpuNumToQuark.put(cpu, cpuQuark); + } + int nextTid = ((Long) event.getContent().getField(fNextTid).getValue()).intValue(); + final TmfStateValue value = TmfStateValue.newValueInt(nextTid); + ssb.modifyAttribute(event.getTimestamp().toNanos(), value, cpuQuark); + } catch (StateValueTypeException | AttributeNotFoundException e) { + Activator.getDefault().logError(NonNullUtils.nullToEmptyString(e.getMessage()), e); + } + } +} \ No newline at end of file diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/tid/TidAnalysisModule.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/tid/TidAnalysisModule.java new file mode 100644 index 0000000000..58c1fdcc8a --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/tid/TidAnalysisModule.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2016 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 + *******************************************************************************/ + +package org.eclipse.tracecompass.analysis.os.linux.core.tid; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; + +import java.util.Collections; +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.analysis.os.linux.core.kernel.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.common.core.NonNullUtils; +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.interval.ITmfStateInterval; +import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; +import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue.Type; +import org.eclipse.tracecompass.tmf.core.analysis.TmfAnalysisRequirement; +import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider; +import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; + +/** + * Active tid analysis module, this only does one thing: figure out the active + * tid on any given cpu. This analysis should be approx 10x faster than the full + * {@link KernelAnalysisModule}. + * + * Note: this module exists as a way to accelerate the TID aspect, but also to + * start splitting up the kernel analysis into smaller sections. + * + * @author Matthew Khouzam + * @since 2.0 + */ +public class TidAnalysisModule extends TmfStateSystemAnalysisModule { + + /** The ID of this analysis module */ + public static final @NonNull String ID = "org.eclipse.tracecompass.analysis.os.linux.kernel.tid"; //$NON-NLS-1$ + + /** The requirements as an immutable set */ + private static final @NonNull Set<@NonNull TmfAnalysisRequirement> REQUIREMENTS = Collections.EMPTY_SET; + + @Override + public @NonNull Iterable<@NonNull TmfAnalysisRequirement> getAnalysisRequirements() { + return REQUIREMENTS; + } + + @Override + protected @NonNull ITmfStateProvider createStateProvider() { + ITmfTrace trace = checkNotNull(getTrace()); + IKernelAnalysisEventLayout layout = (trace instanceof IKernelTrace) ? ((IKernelTrace) trace).getKernelEventLayout() : IKernelAnalysisEventLayout.DEFAULT_LAYOUT; + return new ActiveTidStateProvider(trace, layout); + } + + /** + * Gets the current thread ID on a given CPU for a given time + * + * @param cpu + * the CPU + * @param time + * the time in nanoseconds + * @return the current TID at the time on the CPU or {@code null} if not + * known + */ + public @Nullable Integer getThreadOnCpuAtTime(int cpu, long time) { + ITmfStateSystem stateSystem = getStateSystem(); + if (stateSystem == null) { + return null; + } + + Integer tid = null; + try { + int cpuQuark = stateSystem.getQuarkAbsolute(Integer.toString(cpu)); + ITmfStateValue value = stateSystem.querySingleState(time, cpuQuark).getStateValue(); + if (value.getType().equals(Type.INTEGER)) { + tid = value.unboxInt(); + } + } catch (AttributeNotFoundException | StateSystemDisposedException e) { + Activator.getDefault().logError(NonNullUtils.nullToEmptyString(e.getMessage()), e); + } + return tid; + } + + /** + * Gets the CPU a thread is running on for a given time
+ * Note: this is not designed to be fast, only convenient + * + * @param tid + * the tid + * @param time + * the time in nanoseconds + * @return the current CPU at the time for a TID or {@code null} if not + * available + */ + public @Nullable Integer getCpuForTidAtTime(int tid, long time) { + ITmfStateSystem stateSystem = getStateSystem(); + if (stateSystem == null) { + return null; + } + + try { + for (ITmfStateInterval interval : stateSystem.queryFullState(time)) { + if (tid == interval.getStateValue().unboxInt()) { + return Integer.parseInt(stateSystem.getAttributeName(interval.getAttribute())); + } + } + } catch (StateSystemDisposedException e) { + Activator.getDefault().logError(NonNullUtils.nullToEmptyString(e.getMessage()), e); + } + return null; + } +}