analysis.os: Benchmark some typical usages of Kernel Analysis
authorGeneviève Bastien <gbastien+lttng@versatic.net>
Thu, 25 Feb 2016 03:48:44 +0000 (22:48 -0500)
committerGenevieve Bastien <gbastien+lttng@versatic.net>
Fri, 15 Apr 2016 01:05:40 +0000 (21:05 -0400)
This adds benchmark of getting the thread running on a CPU from a kernel
analysis and making full queries on that analysis.

It paves the way to adding some more of those benchmarks.

Change-Id: I853a350a7647973b87e49dabaf2ac14b09cd0136
Signed-off-by: Geneviève Bastien <gbastien+lttng@versatic.net>
Reviewed-on: https://git.eclipse.org/r/67444
Reviewed-by: Hudson CI
Reviewed-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Tested-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
lttng/org.eclipse.tracecompass.lttng2.kernel.core.tests/perf/org/eclipse/tracecompass/lttng2/kernel/core/tests/perf/analysis/kernel/KernelAnalysisBenchmark.java
lttng/org.eclipse.tracecompass.lttng2.kernel.core.tests/perf/org/eclipse/tracecompass/lttng2/kernel/core/tests/perf/analysis/kernel/KernelAnalysisUsageBenchmark.java [new file with mode: 0644]

index 11c3d22be85a9464a19b63d70637b97eda565aea..3b45e94cda728efb16f5e970ef3f97e69c654061 100644 (file)
@@ -45,7 +45,10 @@ import org.junit.runners.Parameterized.Parameters;
 @RunWith(Parameterized.class)
 public class KernelAnalysisBenchmark {
 
-    private static final String TEST_ID = "org.eclipse.linuxtools#LTTng kernel analysis#";
+    /**
+     * Test test ID for kernel analysis benchmarks
+     */
+    public static final String TEST_ID = "org.eclipse.linuxtools#LTTng kernel analysis#";
     private static final int LOOP_COUNT = 25;
 
     private final TestModule fTestModule;
@@ -108,6 +111,22 @@ public class KernelAnalysisBenchmark {
         runTest(CtfTestTrace.TRACE2, "Trace2", fTestModule);
     }
 
+    /**
+     * Run the benchmark with "many thread"
+     */
+    @Test
+    public void testManyThreads() {
+        runTest(CtfTestTrace.MANY_THREADS, "Many Threads", fTestModule);
+    }
+
+    /**
+     * Run the benchmark with "django httpd"
+     */
+    @Test
+    public void testDjangoHttpd() {
+        runTest(CtfTestTrace.DJANGO_HTTPD, "Django httpd", fTestModule);
+    }
+
     private static void runTest(@NonNull CtfTestTrace testTrace, String testName, TestModule testModule) {
         Performance perf = Performance.getDefault();
         PerformanceMeter pm = perf.createPerformanceMeter(TEST_ID + testName + testModule.getTestNameString());
diff --git a/lttng/org.eclipse.tracecompass.lttng2.kernel.core.tests/perf/org/eclipse/tracecompass/lttng2/kernel/core/tests/perf/analysis/kernel/KernelAnalysisUsageBenchmark.java b/lttng/org.eclipse.tracecompass.lttng2.kernel.core.tests/perf/org/eclipse/tracecompass/lttng2/kernel/core/tests/perf/analysis/kernel/KernelAnalysisUsageBenchmark.java
new file mode 100644 (file)
index 0000000..0d3aec6
--- /dev/null
@@ -0,0 +1,227 @@
+/*******************************************************************************
+ * Copyright (c) 2016 É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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.lttng2.kernel.core.tests.perf.analysis.kernel;
+
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.util.List;
+import java.util.Random;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.test.performance.Dimension;
+import org.eclipse.test.performance.Performance;
+import org.eclipse.test.performance.PerformanceMeter;
+import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule;
+import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelThreadInformationProvider;
+import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes;
+import org.eclipse.tracecompass.lttng2.kernel.core.trace.LttngKernelTrace;
+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.testtraces.ctf.CtfTestTrace;
+import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException;
+import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
+import org.eclipse.tracecompass.tmf.core.tests.shared.TmfTestHelper;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.ctf.core.event.CtfTmfEvent;
+import org.eclipse.tracecompass.tmf.ctf.core.tests.shared.CtfTmfTestTraceUtils;
+import org.junit.Test;
+
+/**
+ * Benchmarks some typical usages of the kernel analysis
+ *
+ * @author Geneviève Bastien
+ */
+public class KernelAnalysisUsageBenchmark {
+
+    private static final String TEST_GET_RUNNING_THREAD = "Kernel: Threads On CPU";
+    private static final String TEST_FULL_QUERIES = "Kernel: Full Queries";
+    private static final int LOOP_COUNT = 25;
+    private static final long SEED = 65423897234L;
+    private static final int NUM_CPU_QUERIES = 20000;
+    private static final int NUM_FULL_QUERIES = 20000;
+
+    /**
+     * Run the benchmark with "trace2"
+     */
+    @Test
+    public void testTrace2() {
+        runTest(CtfTestTrace.TRACE2, "Trace2");
+    }
+
+    /**
+     * Run the benchmark with "many threads"
+     */
+    @Test
+    public void testManyThreads() {
+        runTest(CtfTestTrace.MANY_THREADS, "ManyThreads");
+    }
+
+    /**
+     * Run the benchmark with "django httpd"
+     */
+    @Test
+    public void testDjangoHttpd() {
+        runTest(CtfTestTrace.DJANGO_HTTPD, "Django httpd");
+    }
+
+    private static KernelAnalysisModule getModule(@NonNull CtfTestTrace testTrace, @NonNull LttngKernelTrace trace) {
+        KernelAnalysisModule module = null;
+        String path = CtfTmfTestTraceUtils.getTrace(testTrace).getPath();
+
+        try {
+            /* Initialize the analysis module */
+            module = new KernelAnalysisModule();
+            module.setId("test");
+            trace.initTrace(null, path, CtfTmfEvent.class);
+            module.setTrace(trace);
+            TmfTestHelper.executeAnalysis(module);
+        } catch (TmfAnalysisException | TmfTraceException e) {
+            fail(e.getMessage());
+        }
+        return module;
+    }
+
+    private static void deleteSupplementaryFiles(ITmfTrace trace) {
+        /*
+         * Delete the supplementary files at the end of the benchmarks
+         */
+        File suppDir = new File(TmfTraceManager.getSupplementaryFileDir(trace));
+        for (File file : suppDir.listFiles()) {
+            file.delete();
+        }
+    }
+
+    private static void runTest(@NonNull CtfTestTrace testTrace, String testName) {
+
+        /* First, complete the analysis */
+        LttngKernelTrace trace = new LttngKernelTrace();
+        deleteSupplementaryFiles(trace);
+        KernelAnalysisModule module = getModule(testTrace, trace);
+
+        /* Benchmark some query use cases */
+        benchmarkGetThreadOnCpu(testName, module);
+        benchmarkFullQueries(testName, module);
+
+        /*
+         * Delete the supplementary files at the end of the benchmarks
+         */
+        deleteSupplementaryFiles(trace);
+
+        module.dispose();
+        trace.dispose();
+
+        CtfTmfTestTraceUtils.dispose(testTrace);
+    }
+
+    /**
+     * Benchmarks getting a thread running on a random CPU from the kernel
+     * analysis at fixed intervals. This use case mimics an analysis that reads
+     * events and needs to get the currently running thread for those events.
+     */
+    private static void benchmarkGetThreadOnCpu(String testName, KernelAnalysisModule module) {
+
+        Performance perf = Performance.getDefault();
+        PerformanceMeter pmRunningThread = perf.createPerformanceMeter(KernelAnalysisBenchmark.TEST_ID + testName + ": " + TEST_GET_RUNNING_THREAD);
+        perf.tagAsSummary(pmRunningThread, TEST_GET_RUNNING_THREAD + '(' + testName + ')', Dimension.CPU_TIME);
+
+        @Nullable
+        ITmfStateSystem ss = module.getStateSystem();
+        if (ss == null) {
+            fail("The state system is null");
+            return;
+        }
+
+        /* Get the number of CPUs */
+        int cpuCount = -1;
+        try {
+            int cpusQuark = ss.getQuarkAbsolute(Attributes.CPUS);
+            @NonNull
+            List<@NonNull Integer> cpus = ss.getSubAttributes(cpusQuark, false);
+            cpuCount = cpus.size();
+        } catch (AttributeNotFoundException e) {
+            fail(e.getMessage());
+        }
+        if (cpuCount < 1) {
+            fail("Impossible to get the number of CPUs");
+        }
+
+        /* Get the step and start time of the queries */
+        long startTime = ss.getStartTime();
+        long endTime = ss.getCurrentEndTime();
+        long step = Math.floorDiv(endTime - startTime, NUM_CPU_QUERIES);
+
+        if (step < 1) {
+            fail("Trace is too short to run the get thread on CPU benchmark");
+        }
+
+        /* Verify the query work by fetching a value at the end of the trace */
+        Integer threadOnCpu = KernelThreadInformationProvider.getThreadOnCpu(module, 0, endTime);
+        if (threadOnCpu == null) {
+            fail("null thread on CPU at the end of the trace. Something is not right with the state system");
+        }
+
+        for (int i = 0; i < LOOP_COUNT; i++) {
+            /* Get the thread running on a random CPU at fixed intervals */
+            Random randomGenerator = new Random(SEED);
+            pmRunningThread.start();
+            for (long nextTime = startTime; nextTime < endTime; nextTime += step) {
+                int cpu = Math.abs(randomGenerator.nextInt()) % cpuCount;
+                KernelThreadInformationProvider.getThreadOnCpu(module, cpu, nextTime);
+            }
+            pmRunningThread.stop();
+        }
+        pmRunningThread.commit();
+    }
+
+    /**
+     * Benchmarks getting full queries at different times. This use cases is
+     * often used to populate the views.
+     */
+    private static void benchmarkFullQueries(String testName, KernelAnalysisModule module) {
+
+        Performance perf = Performance.getDefault();
+        PerformanceMeter pmRunningThread = perf.createPerformanceMeter(KernelAnalysisBenchmark.TEST_ID + testName + ": " + TEST_FULL_QUERIES);
+        perf.tagAsSummary(pmRunningThread, TEST_FULL_QUERIES + '(' + testName + ')', Dimension.CPU_TIME);
+
+        @Nullable
+        ITmfStateSystem ss = module.getStateSystem();
+        if (ss == null) {
+            fail("The state system is null");
+            return;
+        }
+
+        /* Get the step and start time of the queries */
+        long startTime = ss.getStartTime();
+        long endTime = ss.getCurrentEndTime();
+        long step = Math.floorDiv(endTime - startTime, NUM_FULL_QUERIES);
+
+        if (step < 1) {
+            fail("Trace is too short to run the get full queries benchmark");
+        }
+
+        for (int i = 0; i < LOOP_COUNT; i++) {
+            /* Make a full query at fixed intervals */
+            pmRunningThread.start();
+            for (long nextTime = startTime; nextTime < endTime; nextTime += step) {
+                try {
+                    ss.queryFullState(nextTime);
+                } catch (StateSystemDisposedException e) {
+                    fail(e.getMessage());
+                }
+            }
+            pmRunningThread.stop();
+        }
+        pmRunningThread.commit();
+    }
+}
This page took 0.02682 seconds and 5 git commands to generate.