linux.core: Introduce TID analysis
authorMatthew Khouzam <matthew.khouzam@ericsson.com>
Wed, 6 Apr 2016 00:20:11 +0000 (20:20 -0400)
committerMatthew Khouzam <matthew.khouzam@ericsson.com>
Thu, 7 Apr 2016 18:25:35 +0000 (14:25 -0400)
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 <matthew.khouzam@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/68878
Reviewed-by: Genevieve Bastien <gbastien+lttng@versatic.net>
Tested-by: Genevieve Bastien <gbastien+lttng@versatic.net>
Reviewed-by: Marc-Andre Laperle <marc-andre.laperle@ericsson.com>
Reviewed-by: Hudson CI
analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/kernel/KernelTidAspectTest.java
analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/stubs/org/eclipse/tracecompass/analysis/os/linux/core/tests/stubs/trace/TmfXmlKernelTraceStub.java
analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF
analysis/org.eclipse.tracecompass.analysis.os.linux.core/icons/threads.png [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.properties
analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.xml
analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/kernel/KernelTidAspect.java
analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/tid/ActiveTidStateProvider.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/tid/TidAnalysisModule.java [new file with mode: 0644]

index 41b95e04d6cf86c0d93f091679f76142aa14657f..beb4b93a158bad5ef9f8c3d88061c988876c9400 100644 (file)
@@ -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<Integer> 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<Integer> tids = new ArrayList<>();
+
+        for (int i = 0; i < expected.size(); i++) {
+            tids.add(resolveNextEvent(context));
+        }
+        assertEquals(expected, tids);
     }
 
 }
index 837993127526acbc85da22492d7c30c7723c479a..b5a53886f0c8d43d32a438d6bf18d2669897e9d9 100644 (file)
@@ -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;
index 1ee4a17503e2b8ac93f2fce9c04d0a4d0a4341db..7a09596bc5e684b2129a5803d5b8df9271f54657 100644 (file)
@@ -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 (file)
index 0000000..59f3ffd
Binary files /dev/null and b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/icons/threads.png differ
index da9e549812f3253ad64ab39dd7387ba7cc09dc66..1404147ce76a8882171daee98d22b77c37447442 100644 (file)
@@ -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
index 29c0d4b83476f78ed7412cc5606ea2a778dfbffc..300647bcae3e001697153be541814430de822b8b 100644 (file)
             automatic="false"
             id="org.eclipse.tracecompass.analysis.os.linux.latency.syscall"
             name="%analysis.latency">
-            <tracetype
+         <tracetype
                applies="true"
                class="org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace">
          </tracetype>
-            </module>
+      </module>
       <module
             analysis_module="org.eclipse.tracecompass.analysis.os.linux.core.contextswitch.KernelContextSwitchAnalysis"
             id="org.eclipse.tracecompass.analysis.os.linux.contextswitch"
             analysis_module="org.eclipse.tracecompass.analysis.os.linux.core.kernelmemoryusage.KernelMemoryAnalysisModule"
             id="org.eclipse.tracecompass.analysis.os.linux.core.kernelmemory"
             name="%analysis.kernelmemory">
-            <tracetype
+         <tracetype
+               applies="true"
+               class="org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace">
+         </tracetype>
+      </module>
+      <module
+            analysis_module="org.eclipse.tracecompass.analysis.os.linux.core.tid.TidAnalysisModule"
+            automatic="true"
+            icon="icons/threads.png"
+            id="org.eclipse.tracecompass.analysis.os.linux.kernel.tid"
+            name="%analysis.tid">
+         <tracetype
                applies="true"
                class="org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace">
          </tracetype>
index 6696abb585352b510940f1af688147133cb16b76..e2a2a6d9cd9630724ff01e72e4bde525f277a68e 100644 (file)
@@ -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 (file)
index 0000000..b15bcf9
--- /dev/null
@@ -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<Integer, Integer> 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 (file)
index 0000000..58c1fdc
--- /dev/null
@@ -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 <br>
+     * 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;
+    }
+}
This page took 0.03272 seconds and 5 git commands to generate.