blob: f946bb8cb66747cccdc9654649c69bb9af098a34 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014, 2017 Ericsson
*
* 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:
* Alexandre Montplaisir - Initial API and implementation
*******************************************************************************/
package org.eclipse.tracecompass.lttng2.ust.core.tests.callstack;
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.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.analysis.profiling.core.callstack.CallStackStateProvider;
import org.eclipse.tracecompass.internal.lttng2.ust.core.callstack.LttngUstCallStackProvider;
import org.eclipse.tracecompass.lttng2.ust.core.tests.shared.LttngUstTestTraceUtils;
import org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace;
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.testtraces.ctf.CtfTestTrace;
import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException;
import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider;
import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
import org.eclipse.tracecompass.tmf.ctf.core.tests.shared.CtfTmfTestTraceUtils;
import org.eclipse.tracecompass.tmf.ctf.core.trace.CtfTmfTrace;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.rules.Timeout;
/**
* Base class for the UST callstack state provider tests.
*
* @author Alexandre Montplaisir
*/
public abstract class AbstractProviderTest {
/** Time-out tests after 1 minute. */
@Rule
public TestRule globalTimeout = new Timeout(1, TimeUnit.MINUTES);
// ------------------------------------------------------------------------
// Attributes
// ------------------------------------------------------------------------
private static final @NonNull CtfTestTrace otherUstTrace = CtfTestTrace.HELLO_LOST;
private ITmfTrace fTrace = null;
private ITmfStateSystem fSS = null;
private TestLttngCallStackModule fModule;
// ------------------------------------------------------------------------
// Abstract methods
// ------------------------------------------------------------------------
/**
* @return The test trace to use for this test
*/
protected abstract @NonNull CtfTestTrace getTestTrace();
/**
* @return The ID of the process the desired thread belongs to
*/
protected abstract int getProcessId();
/**
* @return The name of the executable process in that particular trace
*/
protected abstract String getThreadName();
/**
* Get the list of timestamps to query in that trace.
*
* @param index
* Which of the test timestamps?
* @return That particular timestamp
*/
protected abstract long getTestTimestamp(int index);
// ------------------------------------------------------------------------
// Maintenance
// ------------------------------------------------------------------------
/**
* Perform pre-class initialization.
*/
@Before
public void setUp() {
CtfTestTrace testTrace = getTestTrace();
LttngUstTrace trace = LttngUstTestTraceUtils.getTrace(testTrace);
fTrace = trace;
fModule = new TestLttngCallStackModule();
try {
assertTrue(fModule.setTrace(trace));
} catch (TmfAnalysisException e) {
fail();
}
fModule.schedule();
assertTrue(fModule.waitForCompletion());
fSS = fModule.getStateSystem();
assertNotNull(fSS);
}
/**
* Perform post-class clean-up.
*/
@After
public void tearDown() {
fModule.dispose();
ITmfTrace trace = fTrace;
if (trace != null) {
LttngUstTestTraceUtils.dispose(getTestTrace());
File suppDir = new File(TmfTraceManager.getSupplementaryFileDir(trace));
deleteDirectory(suppDir);
}
}
// ------------------------------------------------------------------------
// Test methods
// ------------------------------------------------------------------------
/**
* Test the handling of generic UST traces who do not contain the required
* information.
*/
@Test
public void testOtherUstTrace() {
/* Initialize the trace and analysis module */
File suppDir;
CtfTmfTrace ustTrace = CtfTmfTestTraceUtils.getTrace(otherUstTrace);
TestLttngCallStackModule module = null;
try {
module = new TestLttngCallStackModule();
try {
assertTrue(module.setTrace(ustTrace));
} catch (TmfAnalysisException e) {
fail();
}
module.schedule();
assertTrue(module.waitForCompletion());
/* Make sure the generated state system exists, but is empty */
ITmfStateSystem ss = module.getStateSystem();
assertNotNull(ss);
assertTrue(ss.getStartTime() >= ustTrace.getStartTime().toNanos());
assertEquals(0, ss.getNbAttributes());
} finally {
if (module != null) {
module.dispose();
}
}
suppDir = new File(TmfTraceManager.getSupplementaryFileDir(ustTrace));
ustTrace.dispose();
deleteDirectory(suppDir);
assertFalse(suppDir.exists());
}
/**
* Test that the callstack state system is there and contains data.
*/
@Test
public void testConstruction() {
assertNotNull(fSS);
assertTrue(fSS.getNbAttributes() > 0);
}
/**
* Test the callstack at the beginning of the state system.
*/
@Test
public void testCallStackBegin() {
long start = fSS.getStartTime();
String[] cs = getCallStack(fSS, getProcessId(), getThreadName(), start);
assertEquals(1, cs.length);
assertEquals("40472b", cs[0]);
}
/**
* Test the callstack somewhere in the trace.
*/
@Test
public void testCallStack1() {
String[] cs = getCallStack(fSS, getProcessId(), getThreadName(), getTestTimestamp(0));
assertEquals(2, cs.length);
assertEquals("40472b", cs[0]);
assertEquals("403d60", cs[1]);
}
/**
* Test the callstack somewhere in the trace.
*/
@Test
public void testCallStack2() {
String[] cs = getCallStack(fSS, getProcessId(), getThreadName(), getTestTimestamp(1));
assertEquals(3, cs.length);
assertEquals("40472b", cs[0]);
assertEquals("403b14", cs[1]);
assertEquals("401b23", cs[2]);
}
/**
* Test the callstack somewhere in the trace.
*/
@Test
public void testCallStack3() {
String[] cs = getCallStack(fSS, getProcessId(), getThreadName(), getTestTimestamp(2));
assertEquals(4, cs.length);
assertEquals("40472b", cs[0]);
assertEquals("4045c8", cs[1]);
assertEquals("403760", cs[2]);
assertEquals("401aac", cs[3]);
}
/**
* Test the callstack at the end of the trace/state system.
*/
@Test
public void testCallStackEnd() {
long end = fSS.getCurrentEndTime();
String[] cs = getCallStack(fSS, getProcessId(), getThreadName(), end);
assertEquals(3, cs.length);
assertEquals("40472b", cs[0]);
assertEquals("4045c8", cs[1]);
assertEquals("403760", cs[2]);
}
// ------------------------------------------------------------------------
// Utility methods
// ------------------------------------------------------------------------
/** Empty and delete a directory */
private static void deleteDirectory(File dir) {
/* Assuming the dir only contains file or empty directories */
for (File file : dir.listFiles()) {
file.delete();
}
dir.delete();
}
/** Get the callstack for the given timestamp, for this particular trace */
private static String[] getCallStack(ITmfStateSystem ss, int pid, String threadName, long timestamp) {
try {
String processName = (pid == CallStackStateProvider.UNKNOWN_PID) ? CallStackStateProvider.UNKNOWN : Integer.toString(pid);
int stackAttribute = ss.getQuarkAbsolute("Processes", processName, threadName, "CallStack");
List<ITmfStateInterval> state = ss.queryFullState(timestamp);
int depth = state.get(stackAttribute).getStateValue().unboxInt();
int stackTop = ss.getQuarkRelative(stackAttribute, String.valueOf(depth));
ITmfStateValue expectedValue = state.get(stackTop).getStateValue();
ITmfStateInterval interval = StateSystemUtils.querySingleStackTop(ss, timestamp, stackAttribute);
assertNotNull(interval);
assertEquals(expectedValue, interval.getStateValue());
String[] ret = new String[depth];
for (int i = 0; i < depth; i++) {
int quark = ss.getQuarkRelative(stackAttribute, String.valueOf(i + 1));
ret[i] = Long.toHexString(state.get(quark).getStateValue().unboxLong());
}
return ret;
} catch (AttributeNotFoundException e) {
fail(e.getMessage());
} catch (StateSystemDisposedException e) {
fail(e.getMessage());
}
fail();
return null;
}
private class TestLttngCallStackModule extends TmfStateSystemAnalysisModule {
@Override
protected ITmfStateProvider createStateProvider() {
return new LttngUstCallStackProvider(checkNotNull(getTrace()));
}
}
}