/******************************************************************************* * Copyright (c) 2014, 2015 É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.vm; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import java.util.Collection; import java.util.List; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule; import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.VcpuStateValues; import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.VmAttributes; import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.module.VirtualMachineCpuAnalysis; import org.eclipse.tracecompass.lttng2.lttng.kernel.core.tests.shared.vm.VmTestExperiment; import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; import org.eclipse.tracecompass.statesystem.core.StateSystemUtils; 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.TmfStateValue; import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; import org.eclipse.tracecompass.tmf.core.trace.TmfTrace; import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment; import org.junit.Test; import com.google.common.collect.Multimap; /** * Test suite for the {@link VirtualMachineCpuAnalysis} class * * @author Geneviève Bastien */ public class VirtualMachineAnalysisTest { private static void verifyStateIntervals(String testId, List<ITmfStateInterval> intervals, int[] expectedStarts, ITmfStateValue[] expectedValues) { int expectedCount = expectedStarts.length - 1; assertEquals(testId + ": Interval count", expectedCount, intervals.size()); for (int i = 0; i < expectedCount; i++) { ITmfStateInterval interval = intervals.get(i); assertEquals(testId + ": Start time of interval " + i, expectedStarts[i], interval.getStartTime()); long actualEnd = (i == expectedCount - 1) ? (expectedStarts[i + 1]) : (expectedStarts[i + 1]) - 1; assertEquals(testId + ": End time of interval " + i, actualEnd, interval.getEndTime()); assertEquals(testId + ": Expected value of interval " + i, expectedValues[i], interval.getStateValue()); } } private static void verifyIntervalsWithMask(String testId, Collection<ITmfStateInterval> intervals, int[] expectedStarts, int[] expectedEnds, ITmfStateValue[] expectedValues, int mask) { int expectedCount = expectedStarts.length - 1; assertEquals(testId + ": Interval count", expectedCount, intervals.size()); int i = 0; for (ITmfStateInterval interval : intervals) { assertEquals(testId + ": Start time of interval " + i, expectedStarts[i], interval.getStartTime()); assertEquals(testId + ": End time of interval " + i, expectedEnds[i], interval.getEndTime()); assertEquals(testId + ": Expected value of interval " + i, expectedValues[i].unboxInt() & mask, interval.getStateValue().unboxInt() & mask); i++; } } /** * Test the analysis execution with stub traces of a virtual machine with * one virtual machine and one CPU */ @Test public void testStubTracesOneQemuKvm() { assumeTrue(VmTestExperiment.ONE_QEMUKVM.exists()); TmfExperiment experiment = VmTestExperiment.ONE_QEMUKVM.getExperiment(true); /* Open the traces */ for (ITmfTrace trace : experiment.getTraces()) { ((TmfTrace) trace).traceOpened(new TmfTraceOpenedSignal(this, trace, null)); } /* * TODO For now, make sure the LttngKernelAnalysis have been run for * each trace before running the analysis. When event request precedence * is implemented, we can remove this */ for (ITmfTrace trace : experiment.getTraces()) { for (KernelAnalysisModule module : TmfTraceUtils.getAnalysisModulesOfClass(trace, KernelAnalysisModule.class)) { module.schedule(); module.waitForCompletion(); } } /* End of TODO block */ experiment.traceOpened(new TmfTraceOpenedSignal(this, experiment, null)); VirtualMachineCpuAnalysis module = null; for (VirtualMachineCpuAnalysis mod : TmfTraceUtils.getAnalysisModulesOfClass(experiment, VirtualMachineCpuAnalysis.class)) { module = mod; break; } assertNotNull(module); module.schedule(); if (!module.waitForCompletion()) { fail("Module did not complete properly"); } try { /* Check the state system */ ITmfStateSystem ss = module.getStateSystem(); assertNotNull(ss); int vmQuark; vmQuark = ss.getQuarkAbsolute(VmAttributes.VIRTUAL_MACHINES); List<Integer> guestQuarks = ss.getSubAttributes(vmQuark, false); assertEquals("Number of guests", 1, guestQuarks.size()); List<Integer> vcpuQuarks = ss.getSubAttributes(guestQuarks.get(0), false); assertEquals("Number of virtual CPUs", 1, vcpuQuarks.size()); Integer statusQuark = ss.getQuarkRelative(vcpuQuarks.get(0), VmAttributes.STATUS); /* Check the intervals for the virtual CPU */ List<ITmfStateInterval> intervals = StateSystemUtils.queryHistoryRange(ss, statusQuark, ss.getStartTime(), ss.getCurrentEndTime()); /* Expected interval values for the virtual CPU */ int[] expectedStarts = { 1, 60, 75, 95, 100, 150, 155, 195, 210, 245, 260, 295, 300, 350, 355, 375 }; ITmfStateValue[] expectedValues = { TmfStateValue.nullValue(), TmfStateValue.newValueInt(VcpuStateValues.VCPU_UNKNOWN), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING | VcpuStateValues.VCPU_VMM), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING | VcpuStateValues.VCPU_VMM | VcpuStateValues.VCPU_PREEMPT), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING | VcpuStateValues.VCPU_VMM), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING | VcpuStateValues.VCPU_VMM), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING | VcpuStateValues.VCPU_VMM), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING | VcpuStateValues.VCPU_VMM), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING | VcpuStateValues.VCPU_VMM | VcpuStateValues.VCPU_PREEMPT), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING | VcpuStateValues.VCPU_VMM), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING) }; verifyStateIntervals("Virtual CPU", intervals, expectedStarts, expectedValues); /* Check the status of the guest's threads */ int[] expectedStartsT130 = { 10, 35, 75, 175, 195, 225, 275, 295, 300, 350, 375 }; int[] expectedEndsT130 = { 34, 74, 174, 224, 209, 274, 374, 299, 349, 354, 375 }; ITmfStateValue[] expectedValuesT30 = { TmfStateValue.newValueInt(VcpuStateValues.VCPU_IDLE), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING), TmfStateValue.newValueInt(VcpuStateValues.VCPU_IDLE), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING), TmfStateValue.newValueInt(VcpuStateValues.VCPU_PREEMPT), TmfStateValue.newValueInt(VcpuStateValues.VCPU_IDLE), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING), TmfStateValue.newValueInt(VcpuStateValues.VCPU_PREEMPT), TmfStateValue.newValueInt(VcpuStateValues.VCPU_PREEMPT), TmfStateValue.newValueInt(VcpuStateValues.VCPU_PREEMPT), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING) }; int[] expectedStartsT131 = { 10, 35, 75, 95, 100, 150, 175, 225, 245, 275, 375 }; int[] expectedEndsT131 = { 34, 74, 174, 99, 149, 154, 224, 274, 259, 374, 375 }; ITmfStateValue[] expectedValuesT31 = { TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING), TmfStateValue.newValueInt(VcpuStateValues.VCPU_IDLE), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING), TmfStateValue.newValueInt(VcpuStateValues.VCPU_PREEMPT), TmfStateValue.newValueInt(VcpuStateValues.VCPU_PREEMPT), TmfStateValue.newValueInt(VcpuStateValues.VCPU_PREEMPT), TmfStateValue.newValueInt(VcpuStateValues.VCPU_IDLE), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING), TmfStateValue.newValueInt(VcpuStateValues.VCPU_PREEMPT), TmfStateValue.newValueInt(VcpuStateValues.VCPU_IDLE), TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING) }; Multimap<Integer, ITmfStateInterval> threadIntervals = module.getUpdatedThreadIntervals(guestQuarks.get(0), ss.getStartTime(), ss.getCurrentEndTime(), 1, new NullProgressMonitor()); verifyIntervalsWithMask("Thread 130", threadIntervals.get(130), expectedStartsT130, expectedEndsT130, expectedValuesT30, VcpuStateValues.VCPU_PREEMPT); verifyIntervalsWithMask("Thread 131", threadIntervals.get(131), expectedStartsT131, expectedEndsT131, expectedValuesT31, VcpuStateValues.VCPU_PREEMPT); } catch (AttributeNotFoundException | StateSystemDisposedException e) { fail(e.getMessage()); } finally { experiment.dispose(); } } }