| /******************************************************************************* |
| * 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 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Geneviève Bastien - Initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.analysis.os.linux.core.tests.kernel; |
| |
| import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import java.io.File; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| 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.KernelThreadInformationProvider; |
| import org.eclipse.tracecompass.analysis.os.linux.core.model.ProcessStatus; |
| 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.statesystem.core.interval.ITmfStateInterval; |
| import org.eclipse.tracecompass.statesystem.core.interval.TmfStateInterval; |
| import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule; |
| 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.TmfTraceManager; |
| import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableSet; |
| |
| /** |
| * Test analysis-specific methods for the {@link KernelAnalysisModule} class. |
| * |
| * @author Geneviève Bastien |
| */ |
| public class KernelThreadInformationProviderTest { |
| |
| private static final @NonNull LinuxTestCase KERNEL_TEST_CASE = KernelAnalysisTestFactory.KERNEL_SCHED; |
| |
| private ITmfTrace fTrace; |
| private KernelAnalysisModule fModule; |
| |
| private static void deleteSuppFiles(@NonNull 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() { |
| ITmfTrace trace = KERNEL_TEST_CASE.getKernelTrace(); |
| deleteSuppFiles(trace); |
| ((TmfTrace) trace).traceOpened(new TmfTraceOpenedSignal(this, trace, null)); |
| IAnalysisModule module = null; |
| for (IAnalysisModule mod : TmfTraceUtils.getAnalysisModulesOfClass(trace, KernelAnalysisModule.class)) { |
| module = mod; |
| } |
| assertNotNull(module); |
| module.schedule(); |
| module.waitForCompletion(); |
| fModule = TmfTraceUtils.getAnalysisModuleOfClass(trace, KernelAnalysisModule.class, KernelAnalysisModule.ID); |
| fTrace = trace; |
| } |
| |
| /** |
| * Clean up |
| */ |
| @After |
| public void tearDown() { |
| ITmfTrace trace = fTrace; |
| if (trace != null) { |
| deleteSuppFiles(trace); |
| trace.dispose(); |
| } |
| } |
| |
| /** |
| * Test the |
| * {@link KernelThreadInformationProvider#getThreadIds(KernelAnalysisModule)} |
| * method |
| */ |
| @Test |
| public void testGetThreadQuarks() { |
| KernelAnalysisModule module = checkNotNull(fModule); |
| Collection<Integer> threadIds = KernelThreadInformationProvider.getThreadIds(module); |
| assertEquals(ImmutableSet.<Integer>of(10,11,12,20,21,30,100), threadIds); |
| } |
| |
| /** |
| * Test the |
| * {@link KernelThreadInformationProvider#getThreadOnCpu(KernelAnalysisModule, long, long)} |
| * method |
| */ |
| @Test |
| public void testGetThreadOnCpu() { |
| KernelAnalysisModule module = checkNotNull(fModule); |
| |
| /* Check with invalid timestamps */ |
| Integer tid = KernelThreadInformationProvider.getThreadOnCpu(module, 0, -1); |
| assertNull(tid); |
| |
| tid = KernelThreadInformationProvider.getThreadOnCpu(module, 0, 90); |
| assertNull(tid); |
| |
| /* Check with invalid cpus */ |
| tid = KernelThreadInformationProvider.getThreadOnCpu(module, 2, 20); |
| assertNull(tid); |
| |
| tid = KernelThreadInformationProvider.getThreadOnCpu(module, -1, 20); |
| assertNull(tid); |
| |
| /* Check valid values */ |
| tid = KernelThreadInformationProvider.getThreadOnCpu(module, 0, 4); |
| assertNull(tid); |
| |
| tid = KernelThreadInformationProvider.getThreadOnCpu(module, 0, 15); |
| assertNull(tid); |
| |
| tid = KernelThreadInformationProvider.getThreadOnCpu(module, 1, 15); |
| assertEquals(Integer.valueOf(11), tid); |
| |
| tid = KernelThreadInformationProvider.getThreadOnCpu(module, 1, 29); |
| assertEquals(Integer.valueOf(20), tid); |
| |
| tid = KernelThreadInformationProvider.getThreadOnCpu(module, 1, 30); |
| assertEquals(Integer.valueOf(21), tid); |
| |
| tid = KernelThreadInformationProvider.getThreadOnCpu(module, 0, 59); |
| assertEquals(Integer.valueOf(11), tid); |
| |
| tid = KernelThreadInformationProvider.getThreadOnCpu(module, 1, 59); |
| assertEquals(Integer.valueOf(30), tid); |
| |
| tid = KernelThreadInformationProvider.getThreadOnCpu(module, 0, 60); |
| assertEquals(Integer.valueOf(11), tid); |
| |
| tid = KernelThreadInformationProvider.getThreadOnCpu(module, 1, 60); |
| assertEquals(Integer.valueOf(21), tid); |
| |
| } |
| |
| /** |
| * Test the {@link KernelThreadInformationProvider#getThreadsOfCpus} method. |
| */ |
| @Test |
| public void testGetThreadsOfCpus() { |
| KernelAnalysisModule module = checkNotNull(fModule); |
| final long start = 45L; |
| final long end = 65L; |
| |
| Set<Integer> tids = KernelThreadInformationProvider.getThreadsOfCpus(module, Collections.singleton(0L), start, end); |
| assertNotNull(tids); |
| /* |
| * Only threads 11 should be present, due to the sched_switch at t=35. |
| */ |
| assertEquals(Collections.singleton(11), tids); |
| |
| tids = KernelThreadInformationProvider.getThreadsOfCpus(module, Collections.singleton(1L), start, end); |
| assertNotNull(tids); |
| /* Threads 21 and 30 get scheduled on CPU 1 in the range. */ |
| assertEquals(ImmutableSet.of(21, 30), tids); |
| } |
| |
| /** |
| * Test the {@link KernelThreadInformationProvider#getActiveThreadsForRange} |
| * method. |
| */ |
| @Test |
| public void testIsThreadActiveRange() { |
| KernelAnalysisModule module = checkNotNull(fModule); |
| final long start = 45L; |
| final long end = 65L; |
| |
| /* |
| * Threads 11 (running on CPU 0), 21 (wait_for_cpu) and 30 (running on |
| * CPU 1) should be active in the range. |
| */ |
| Set<Integer> tids = KernelThreadInformationProvider.getActiveThreadsForRange(module, start, end); |
| assertEquals(ImmutableSet.of(11, 21, 30), tids); |
| |
| // Check with invalid time ranges |
| tids = KernelThreadInformationProvider.getActiveThreadsForRange(module, 0, 0); |
| assertTrue(tids.isEmpty()); |
| |
| tids = KernelThreadInformationProvider.getActiveThreadsForRange(module, 123456789L, 1234567890L); |
| assertTrue(tids.isEmpty()); |
| |
| // Check with overlapping time ranges |
| tids = KernelThreadInformationProvider.getActiveThreadsForRange(module, 0, 10L); |
| assertTrue(tids.isEmpty()); |
| |
| tids = KernelThreadInformationProvider.getActiveThreadsForRange(module, 70, 123456L); |
| assertEquals(ImmutableSet.of(11, 20, 21), tids); |
| } |
| |
| /** |
| * Test the |
| * {@link KernelThreadInformationProvider#getParentPid(KernelAnalysisModule, Integer, long)} |
| * method |
| */ |
| @Test |
| public void testGetPpid() { |
| KernelAnalysisModule module = checkNotNull(fModule); |
| |
| /* Check with invalid timestamps */ |
| Integer ppid = KernelThreadInformationProvider.getParentPid(module, 11, -1); |
| assertNull(ppid); |
| |
| ppid = KernelThreadInformationProvider.getParentPid(module, 11, 90); |
| assertNull(ppid); |
| |
| /* Check with invalid tids */ |
| ppid = KernelThreadInformationProvider.getParentPid(module, -4, 20); |
| assertNull(ppid); |
| |
| ppid = KernelThreadInformationProvider.getParentPid(module, 13, 20); |
| assertNull(ppid); |
| |
| /* Check values with no parent */ |
| ppid = KernelThreadInformationProvider.getParentPid(module, 10, 20); |
| assertEquals(Integer.valueOf(0), ppid); |
| |
| ppid = KernelThreadInformationProvider.getParentPid(module, 30, 60); |
| assertEquals(Integer.valueOf(0), ppid); |
| |
| /* Check parent determined at statedump */ |
| ppid = KernelThreadInformationProvider.getParentPid(module, 11, 4); |
| assertNull(ppid); |
| |
| ppid = KernelThreadInformationProvider.getParentPid(module, 11, 5); |
| assertEquals(Integer.valueOf(10), ppid); |
| |
| ppid = KernelThreadInformationProvider.getParentPid(module, 12, 10); |
| assertEquals(Integer.valueOf(11), ppid); |
| |
| /* Check parent after process fork */ |
| ppid = KernelThreadInformationProvider.getParentPid(module, 21, 25); |
| assertEquals(Integer.valueOf(20), ppid); |
| |
| ppid = KernelThreadInformationProvider.getParentPid(module, 21, 70); |
| assertEquals(Integer.valueOf(20), ppid); |
| |
| } |
| |
| /** |
| * Test the |
| * {@link KernelThreadInformationProvider#getProcessId(KernelAnalysisModule, Integer, long)} |
| * method |
| */ |
| @Test |
| public void testGetPid() { |
| KernelAnalysisModule module = checkNotNull(fModule); |
| |
| /* Check with invalid timestamps */ |
| Integer pid = KernelThreadInformationProvider.getProcessId(module, 11, -1); |
| assertNull(pid); |
| |
| pid = KernelThreadInformationProvider.getProcessId(module, 11, 90); |
| assertNull(pid); |
| |
| /* Check with invalid tids */ |
| pid = KernelThreadInformationProvider.getProcessId(module, -4, 20); |
| assertNull(pid); |
| |
| pid = KernelThreadInformationProvider.getProcessId(module, 13, 20); |
| assertNull(pid); |
| |
| /* Check values of processes */ |
| pid = KernelThreadInformationProvider.getProcessId(module, 10, 20); |
| assertEquals(Integer.valueOf(10), pid); |
| |
| pid = KernelThreadInformationProvider.getProcessId(module, 30, 60); |
| assertEquals(Integer.valueOf(30), pid); |
| |
| /* Check pid determined at statedump */ |
| pid = KernelThreadInformationProvider.getProcessId(module, 11, 4); |
| assertNull(pid); |
| |
| pid = KernelThreadInformationProvider.getProcessId(module, 11, 5); |
| assertEquals(Integer.valueOf(10), pid); |
| |
| pid = KernelThreadInformationProvider.getProcessId(module, 12, 10); |
| assertEquals(Integer.valueOf(10), pid); |
| |
| /* Check parent after process fork */ |
| pid = KernelThreadInformationProvider.getProcessId(module, 21, 25); |
| assertEquals(Integer.valueOf(20), pid); |
| |
| pid = KernelThreadInformationProvider.getProcessId(module, 21, 70); |
| assertEquals(Integer.valueOf(20), pid); |
| |
| } |
| |
| /** |
| * Test the {@link KernelThreadInformationProvider#getExecutableName(KernelAnalysisModule, Integer)} method |
| */ |
| @Test |
| public void testGetExecutableName() { |
| KernelAnalysisModule module = checkNotNull(fModule); |
| |
| /* Check with invalid threads */ |
| String execName = KernelThreadInformationProvider.getExecutableName(module, 101, 70); |
| assertNull(execName); |
| |
| execName = KernelThreadInformationProvider.getExecutableName(module, -2, 70); |
| assertNull(execName); |
| |
| /* Check valid value */ |
| execName = KernelThreadInformationProvider.getExecutableName(module, 20, 70); |
| assertEquals("proc20", execName); |
| |
| /* Check valid value with process name change in history */ |
| execName = KernelThreadInformationProvider.getExecutableName(module, 21, 70); |
| assertEquals("tid21", execName); |
| |
| } |
| |
| private static void testIntervals(String info, List<ITmfStateInterval> intervals, ProcessStatus[] values) { |
| assertEquals(info + " interval count", values.length, intervals.size()); |
| for (int i = 0; i < values.length; i++) { |
| assertEquals(info + " interval " + i, values[i], ProcessStatus.getStatusFromStateValue(intervals.get(i).getStateValue())); |
| } |
| } |
| |
| private static void testIterator(String info, Iterator<ITmfStateInterval> intervals, ProcessStatus[] values) { |
| for (int i = 0; i < values.length; i++) { |
| assertTrue(intervals.hasNext()); |
| ITmfStateInterval interval = intervals.next(); |
| assertEquals(info + " interval " + i, values[i], ProcessStatus.getStatusFromStateValue(interval.getStateValue())); |
| } |
| assertFalse(intervals.hasNext()); |
| } |
| |
| private static void compareIntervals(List<ITmfStateInterval> expecteds, List<ITmfStateInterval> actuals) { |
| assertEquals(expecteds.size(), actuals.size()); |
| for (int i = 0; i < expecteds.size(); i++) { |
| ITmfStateInterval expected = expecteds.get(i); |
| ITmfStateInterval actual = actuals.get(i); |
| |
| /* Only compare bounds and value, attribute doesn't matter here */ |
| assertEquals(expected.getStartTime(), actual.getStartTime()); |
| assertEquals(expected.getEndTime(), actual.getEndTime()); |
| assertEquals(expected.getStateValue(), actual.getStateValue()); |
| } |
| } |
| |
| /** |
| * Test the |
| * {@link KernelThreadInformationProvider#getStatusIntervalsForThread(KernelAnalysisModule, Integer, long, long, long, IProgressMonitor)} |
| * method |
| */ |
| @Test |
| public void testGetStatusIntervalsForThread() { |
| KernelAnalysisModule module = checkNotNull(fModule); |
| |
| IProgressMonitor monitor = new NullProgressMonitor(); |
| Integer process21 = 21; |
| Integer process20 = 20; |
| |
| /* Check invalid time ranges */ |
| List<ITmfStateInterval> intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process21, -15, -5, 3, monitor); |
| assertTrue(intervals.isEmpty()); |
| |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process21, 90, 1500000000L, 50, monitor); |
| assertTrue(intervals.isEmpty()); |
| |
| /* Check invalid quarks */ |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, -1, 0, 70L, 3, monitor); |
| assertTrue(intervals.isEmpty()); |
| |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, 0, 0, 70L, 3, monitor); |
| assertTrue(intervals.isEmpty()); |
| |
| /* Check different time ranges and resolutions */ |
| ProcessStatus[] values = { ProcessStatus.NOT_ALIVE, ProcessStatus.WAIT_CPU, |
| ProcessStatus.RUN, ProcessStatus.WAIT_CPU, |
| ProcessStatus.RUN }; |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process21, 0, 70L, 3, monitor); |
| testIntervals("tid 21 [0,70,3]", intervals, values); |
| |
| ProcessStatus[] values2 = { ProcessStatus.NOT_ALIVE, ProcessStatus.RUN, |
| ProcessStatus.RUN }; |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process21, 1, 70L, 30, monitor); |
| testIntervals("tid 21 [0,70,30]", intervals, values2); |
| |
| ProcessStatus[] values3 = { ProcessStatus.WAIT_CPU, |
| ProcessStatus.RUN }; |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process21, 25, 50L, 3, monitor); |
| testIntervals("tid 21 [25,50,3]", intervals, values3); |
| |
| ImmutableList<ITmfStateInterval> expectedIntervals = ImmutableList.of( |
| new TmfStateInterval( 1, 9, 0, ProcessStatus.NOT_ALIVE.getStateValue().unboxValue()), |
| new TmfStateInterval(10, 19, 0, ProcessStatus.WAIT_UNKNOWN.getStateValue().unboxValue()), |
| new TmfStateInterval(20, 29, 0, ProcessStatus.RUN.getStateValue().unboxValue()), |
| new TmfStateInterval(30, 69, 0, ProcessStatus.WAIT_BLOCKED.getStateValue().unboxValue()) |
| ); |
| |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process20, 0, 70L, 3, monitor); |
| compareIntervals(expectedIntervals, intervals); |
| |
| expectedIntervals = ImmutableList.of( |
| new TmfStateInterval( 1, 9, 0, ProcessStatus.NOT_ALIVE.getStateValue().unboxValue()), |
| new TmfStateInterval(30, 69, 0, ProcessStatus.WAIT_BLOCKED.getStateValue().unboxValue()) |
| ); |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process20, 1, 70L, 30, monitor); |
| compareIntervals(expectedIntervals, intervals); |
| |
| ProcessStatus[] values6 = { ProcessStatus.RUN, |
| ProcessStatus.WAIT_BLOCKED }; |
| |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process20, 25, 50L, 3, monitor); |
| testIntervals("tid 20 [25,50,3]", intervals, values6); |
| |
| ProcessStatus[] values7 = { ProcessStatus.WAIT_CPU }; |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process20, 80L, 85L, 3, monitor); |
| testIntervals("tid 20 [80,85,3]", intervals, values7); |
| } |
| |
| /** |
| * Test the |
| * {@link KernelThreadInformationProvider#getStatusIntervalsForThread(KernelAnalysisModule, Integer, long, long, long)} |
| * method |
| */ |
| @Test |
| public void testGetStatusIntervalsForThreadIt() { |
| KernelAnalysisModule module = checkNotNull(fModule); |
| |
| Integer process21 = 21; |
| Integer process20 = 20; |
| |
| /* Check invalid time ranges */ |
| Iterator<ITmfStateInterval> intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process21, -15, -5, -1); |
| assertFalse(intervals.hasNext()); |
| |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process21, 90, 1500000000L, -1); |
| assertFalse(intervals.hasNext()); |
| |
| /* Check invalid quarks */ |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, -1, 0, 70L, -1); |
| assertFalse(intervals.hasNext()); |
| |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, 0, 0, 70L, 0); |
| assertFalse(intervals.hasNext()); |
| |
| /* Check different time ranges */ |
| ProcessStatus[] values = { ProcessStatus.NOT_ALIVE, ProcessStatus.WAIT_CPU, |
| ProcessStatus.RUN, ProcessStatus.WAIT_CPU, |
| ProcessStatus.RUN }; |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process21, 0, 70L, -1); |
| testIterator("tid 21 [0,70]", intervals, values); |
| |
| ProcessStatus[] values2 = { ProcessStatus.WAIT_CPU, |
| ProcessStatus.RUN }; |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process21, 25, 50L, -1); |
| testIterator("tid 21 [25,50]", intervals, values2); |
| |
| ProcessStatus[] values3 = { ProcessStatus.NOT_ALIVE, ProcessStatus.WAIT_UNKNOWN, |
| ProcessStatus.RUN, ProcessStatus.WAIT_BLOCKED }; |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process20, 0, 70L, -1); |
| testIterator("tid 20 [0,70]", intervals, values3); |
| |
| ProcessStatus[] values4 = { ProcessStatus.RUN, |
| ProcessStatus.WAIT_BLOCKED }; |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process20, 25, 50L, -1); |
| testIterator("tid 20 [25,50]", intervals, values4); |
| |
| ProcessStatus[] values5 = { ProcessStatus.WAIT_CPU }; |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process20, 80L, 85L, -1); |
| testIterator("tid 20 [80,85]", intervals, values5); |
| |
| /* Check valid time ranges with higher resolution */ |
| ProcessStatus[] values6 = { ProcessStatus.NOT_ALIVE, ProcessStatus.RUN, |
| ProcessStatus.RUN }; |
| intervals = KernelThreadInformationProvider.getStatusIntervalsForThread(module, process21, 1, 70L, 30); |
| testIterator("tid 21 [0,70,30]", intervals, values6); |
| } |
| |
| } |