--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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
+ *
+ * Contributors:
+ * Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.lttng2.kernel.core.tests;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Plugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Activator for the lttng2.kernel.core.tests plugin
+ *
+ * @author Geneviève Bastien
+ */
+public class Activator extends Plugin {
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The plug-in ID
+ */
+ public static final String PLUGIN_ID = "org.eclipse.tracecompass.lttng2.kernel.core.tests"; //$NON-NLS-1$
+
+ /**
+ * The shared instance
+ */
+ private static Activator PLUGIN;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+ // ------------------------------------------------------------------------
+ // Accessors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return PLUGIN;
+ }
+
+ // ------------------------------------------------------------------------
+ // Operators
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ PLUGIN = this;
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ PLUGIN = null;
+ super.stop(context);
+ }
+
+ /**
+ * Return a path to a file relative to this plugin's base directory
+ *
+ * @param relativePath
+ * The path relative to the plugin's root directory
+ * @return The path corresponding to the relative path in parameter
+ */
+ public static IPath getAbsoluteFilePath(String relativePath) {
+ Activator plugin = Activator.getDefault();
+ if (plugin == null) {
+ /*
+ * Shouldn't happen but at least throw something to get the test to
+ * fail early
+ */
+ throw new IllegalStateException();
+ }
+ URL location = FileLocator.find(plugin.getBundle(), new Path(relativePath), null);
+ try {
+ return new Path(FileLocator.toFileURL(location).getPath());
+ } catch (IOException e) {
+ throw new IllegalStateException();
+ }
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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
+ *
+ * Contributors:
+ * Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.lttng2.kernel.core.tests.analysis.cpuusage;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.Attributes;
+import org.eclipse.tracecompass.lttng2.kernel.core.analysis.cpuusage.LttngKernelCpuUsageAnalysis;
+import org.eclipse.tracecompass.lttng2.kernel.core.analysis.kernel.LttngKernelAnalysis;
+import org.eclipse.tracecompass.lttng2.kernel.core.tests.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.tmf.core.analysis.IAnalysisModule;
+import org.eclipse.tracecompass.tmf.core.event.TmfEvent;
+import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
+import org.eclipse.tracecompass.tmf.core.tests.shared.TmfTestHelper;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
+import org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.TmfXmlTraceStub;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test suite for the {@link LttngKernelCpuUsageAnalysis} class
+ *
+ * @author Geneviève Bastien
+ */
+public class CpuUsageStateProviderTest {
+
+ private static final String CPU_USAGE_FILE = "testfiles/cpu_analysis.xml";
+ /**
+ * The ID of the cpu usage analysis module for development traces
+ */
+ public static final String CPU_USAGE_ANALYSIS_ID = "lttng2.kernel.core.tests.cpuusage";
+
+ private ITmfTrace fTrace;
+ private LttngKernelCpuUsageAnalysis fModule;
+
+ private static void deleteSuppFiles(ITmfTrace trace) {
+ /* Remove supplementary files */
+ File suppDir = new File(TmfTraceManager.getSupplementaryFileDir(trace));
+ for (File file : suppDir.listFiles()) {
+ file.delete();
+ }
+ }
+
+ /**
+ * Setup the trace for the tests
+ */
+ @Before
+ public void setUp() {
+ fTrace = new TmfXmlTraceStub();
+ IPath filePath = Activator.getAbsoluteFilePath(CPU_USAGE_FILE);
+ IStatus status = fTrace.validate(null, filePath.toOSString());
+ if (!status.isOK()) {
+ fail(status.getException().getMessage());
+ }
+ try {
+ fTrace.initTrace(null, filePath.toOSString(), TmfEvent.class);
+ } catch (TmfTraceException e) {
+ fail(e.getMessage());
+ }
+ deleteSuppFiles(fTrace);
+ ((TmfTrace) fTrace).traceOpened(new TmfTraceOpenedSignal(this, fTrace, null));
+ /*
+ * FIXME: Make sure this analysis is finished before running the CPU
+ * analysis. This block can be removed once analysis dependency and
+ * request precedence is implemented
+ */
+ IAnalysisModule module = null;
+ for (IAnalysisModule mod : TmfTraceUtils.getAnalysisModulesOfClass(fTrace, LttngKernelAnalysis.class)) {
+ module = mod;
+ }
+ assertNotNull(module);
+ module.schedule();
+ module.waitForCompletion();
+ /* End of the FIXME block */
+ fModule = TmfTraceUtils.getAnalysisModuleOfClass(fTrace, LttngKernelCpuUsageAnalysis.class, CPU_USAGE_ANALYSIS_ID);
+ assertNotNull(fModule);
+ }
+
+ /**
+ * Clean up
+ */
+ @After
+ public void tearDown() {
+ deleteSuppFiles(fTrace);
+ fTrace.dispose();
+ }
+
+ /**
+ * Test that the analysis executes without problems
+ */
+ @Test
+ public void testAnalysisExecution() {
+ /* Make sure the analysis hasn't run yet */
+ assertNull(fModule.getStateSystem());
+
+ /* Execute the analysis */
+ assertTrue(TmfTestHelper.executeAnalysis(fModule));
+ assertNotNull(fModule.getStateSystem());
+ }
+
+ /**
+ * Test that the state system is returned with the expected results
+ */
+ @Test
+ public void testReturnedStateSystem() {
+ fModule.schedule();
+ fModule.waitForCompletion();
+ ITmfStateSystem ss = fModule.getStateSystem();
+ assertNotNull(ss);
+ assertEquals(1L, ss.getStartTime());
+ assertEquals(25L, ss.getCurrentEndTime());
+
+ try {
+ int cpusQuark = ss.getQuarkAbsolute(Attributes.CPUS);
+
+ /*
+ * There should be 2 CPU entries: 0 and 1 and 3 process entries
+ * under each
+ */
+ List<Integer> cpuQuarks = ss.getSubAttributes(cpusQuark, false);
+ assertEquals(2, cpuQuarks.size());
+ for (Integer cpuQuark : cpuQuarks) {
+ assertEquals(3, ss.getSubAttributes(cpuQuark, false).size());
+ }
+
+ /* Proc 2 on CPU 0 should run from 1 to 20 seconds */
+ int proc2Quark = ss.getQuarkAbsolute(Attributes.CPUS, "0", "2");
+ ITmfStateInterval interval = ss.querySingleState(2L, proc2Quark);
+ assertEquals(1L, interval.getStartTime());
+ assertEquals(19L, interval.getEndTime());
+
+ /*
+ * Query at the end and make sure all processes on all CPU have the
+ * expected values
+ */
+ Map<String, Long> expected = new HashMap<>();
+ expected.put("CPUs/0/1", 0L);
+ expected.put("CPUs/0/2", 19L);
+ expected.put("CPUs/0/3", 5L);
+ expected.put("CPUs/1/1", 5L);
+ expected.put("CPUs/1/3", 6L);
+ expected.put("CPUs/1/4", 8L);
+ List<ITmfStateInterval> intervals = ss.queryFullState(25L);
+ Map<String, Long> intervalMap = new HashMap<>();
+ for (ITmfStateInterval oneInterval : intervals) {
+ if (!oneInterval.getStateValue().isNull()) {
+ intervalMap.put(ss.getFullAttributePath(oneInterval.getAttribute()), oneInterval.getStateValue().unboxLong());
+ }
+ }
+ assertEquals(expected, intervalMap);
+
+ } catch (AttributeNotFoundException | StateSystemDisposedException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * Test the
+ * {@link LttngKernelCpuUsageAnalysis#getCpuUsageInRange(long, long)}
+ * method.
+ */
+ @Test
+ public void testUsageInRange() {
+ fModule.schedule();
+ fModule.waitForCompletion();
+
+ /* This range should query the total range */
+ Map<String, Long> expected = new HashMap<>();
+ expected.put("0/1", 0L);
+ expected.put("0/2", 19L);
+ expected.put("0/3", 5L);
+ expected.put("1/1", 5L);
+ expected.put("1/3", 6L);
+ expected.put("1/4", 13L);
+ expected.put("total", 48L);
+ expected.put("total/1", 5L);
+ expected.put("total/2", 19L);
+ expected.put("total/3", 11L);
+ expected.put("total/4", 13L);
+ expected.put("0", 24L);
+ expected.put("1", 24L);
+ Map<String, Long> resultMap = fModule.getCpuUsageInRange(0L, 30L);
+ assertEquals(expected, resultMap);
+
+ /* Verify a range when a process runs at the start */
+ expected.clear();
+ expected.put("0/1", 0L);
+ expected.put("0/2", 0L);
+ expected.put("0/3", 3L);
+ expected.put("1/1", 0L);
+ expected.put("1/3", 0L);
+ expected.put("1/4", 3L);
+ expected.put("total", 6L);
+ expected.put("total/1", 0L);
+ expected.put("total/2", 0L);
+ expected.put("total/3", 3L);
+ expected.put("total/4", 3L);
+ expected.put("0", 3L);
+ expected.put("1", 3L);
+ resultMap = fModule.getCpuUsageInRange(22L, 25L);
+ assertEquals(expected, resultMap);
+
+ /* Verify a range when a process runs at the end */
+ expected.clear();
+ expected.put("0/1", 0L);
+ expected.put("0/2", 3L);
+ expected.put("0/3", 0L);
+ expected.put("1/1", 0L);
+ expected.put("1/3", 1L);
+ expected.put("1/4", 2L);
+ expected.put("total", 6L);
+ expected.put("total/1", 0L);
+ expected.put("total/2", 3L);
+ expected.put("total/3", 1L);
+ expected.put("total/4", 2L);
+ expected.put("0", 3L);
+ expected.put("1", 3L);
+ resultMap = fModule.getCpuUsageInRange(1L, 4L);
+ assertEquals(expected, resultMap);
+
+ /* Verify a range when a process runs at start and at the end */
+ expected.clear();
+ expected.put("0/1", 0L);
+ expected.put("0/2", 9L);
+ expected.put("0/3", 0L);
+ expected.put("1/1", 0L);
+ expected.put("1/3", 5L);
+ expected.put("1/4", 4L);
+ expected.put("total", 18L);
+ expected.put("total/1", 0L);
+ expected.put("total/2", 9L);
+ expected.put("total/3", 5L);
+ expected.put("total/4", 4L);
+ expected.put("0", 9L);
+ expected.put("1", 9L);
+ resultMap = fModule.getCpuUsageInRange(4L, 13L);
+ assertEquals(expected, resultMap);
+
+ }
+}
--- /dev/null
+<trace>
+<event timestamp="0" name="set_aspects">
+<field name="cpu" value="1" type="int" />
+</event>
+<event timestamp="1" name="sched_switch">
+<field name="cpu" value="0" type="int" />
+<field name="prev_comm" value="proc1" type="string" />
+<field name="prev_tid" value="1" type="long" />
+<field name="prev_prio" value="20" type="int" />
+<field name="prev_state" value="0" type="long" />
+<field name="next_comm" value="proc2" type="string" />
+<field name="next_tid" value="2" type="long" />
+<field name="next_prio" value="20" type="int" />
+</event>
+<event timestamp="2" name="sched_switch">
+<field name="cpu" value="1" type="int" />
+<field name="prev_comm" value="proc3" type="string" />
+<field name="prev_tid" value="3" type="long" />
+<field name="prev_prio" value="20" type="int" />
+<field name="prev_state" value="0" type="long" />
+<field name="next_comm" value="proc4" type="string" />
+<field name="next_tid" value="4" type="long" />
+<field name="next_prio" value="20" type="int" />
+</event>
+<event timestamp="5" name="sched_switch">
+<field name="cpu" value="1" type="int" />
+<field name="prev_comm" value="proc4" type="string" />
+<field name="prev_tid" value="4" type="long" />
+<field name="prev_prio" value="20" type="int" />
+<field name="prev_state" value="0" type="long" />
+<field name="next_comm" value="proc3" type="string" />
+<field name="next_tid" value="3" type="long" />
+<field name="next_prio" value="20" type="int" />
+</event>
+<event timestamp="10" name="sched_switch">
+<field name="cpu" value="1" type="int" />
+<field name="prev_comm" value="proc3" type="string" />
+<field name="prev_tid" value="3" type="long" />
+<field name="prev_prio" value="20" type="int" />
+<field name="prev_state" value="0" type="long" />
+<field name="next_comm" value="proc4" type="string" />
+<field name="next_tid" value="4" type="long" />
+<field name="next_prio" value="20" type="int" />
+</event>
+<event timestamp="15" name="sched_switch">
+<field name="cpu" value="1" type="int" />
+<field name="prev_comm" value="proc4" type="string" />
+<field name="prev_tid" value="4" type="long" />
+<field name="prev_prio" value="20" type="int" />
+<field name="prev_state" value="0" type="long" />
+<field name="next_comm" value="proc1" type="string" />
+<field name="next_tid" value="1" type="long" />
+<field name="next_prio" value="20" type="int" />
+</event>
+<event timestamp="20" name="sched_switch">
+<field name="cpu" value="1" type="int" />
+<field name="prev_comm" value="proc1" type="string" />
+<field name="prev_tid" value="1" type="long" />
+<field name="prev_prio" value="20" type="int" />
+<field name="prev_state" value="0" type="long" />
+<field name="next_comm" value="proc4" type="string" />
+<field name="next_tid" value="4" type="long" />
+<field name="next_prio" value="20" type="int" />
+</event>
+<event timestamp="20" name="sched_switch">
+<field name="cpu" value="0" type="int" />
+<field name="prev_comm" value="proc2" type="string" />
+<field name="prev_tid" value="2" type="long" />
+<field name="prev_prio" value="20" type="int" />
+<field name="prev_state" value="0" type="long" />
+<field name="next_comm" value="proc3" type="string" />
+<field name="next_tid" value="3" type="long" />
+<field name="next_prio" value="20" type="int" />
+</event>
+<event timestamp="25" name="sched_switch">
+<field name="cpu" value="0" type="int" />
+<field name="prev_comm" value="proc3" type="string" />
+<field name="prev_tid" value="3" type="long" />
+<field name="prev_prio" value="20" type="int" />
+<field name="prev_state" value="0" type="long" />
+<field name="next_comm" value="proc2" type="string" />
+<field name="next_tid" value="2" type="long" />
+<field name="next_prio" value="20" type="int" />
+</event>
+</trace>
\ No newline at end of file