blob: 90bbf17e4599a01de65c5889b744bfc8fe018de0 [file] [log] [blame]
/*******************************************************************************
* 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);
}
}