/******************************************************************************* * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir * * 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 *******************************************************************************/ package org.eclipse.tracecompass.lttng2.kernel.core.tests.synchronization; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; 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.lttng2.lttng.kernel.core.tests.shared.LttngKernelTestTraceUtils; import org.eclipse.tracecompass.testtraces.ctf.CtfTestTrace; import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager; import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal; import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal; import org.eclipse.tracecompass.tmf.core.trace.ITmfContext; import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment; import org.eclipse.tracecompass.tmf.ctf.core.event.CtfTmfEvent; import org.eclipse.tracecompass.tmf.ctf.core.tests.shared.CtfTmfTestTraceUtils; 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; /** * Test that synchronization between LTTng UST and kernel traces is done * correctly. * * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=484620 * * @author Alexandre Montplaisir */ public class UstKernelSyncTest { /** Time-out tests after 60 seconds */ @Rule public TestRule globalTimeout= new Timeout(60, TimeUnit.SECONDS); private static final @NonNull CtfTestTrace KERNEL_TRACE = CtfTestTrace.CONTEXT_SWITCHES_KERNEL; private static final @NonNull CtfTestTrace UST_TRACE = CtfTestTrace.CONTEXT_SWITCHES_UST; private TmfExperiment fExperiment; private ITmfTrace fUstTrace; private KernelAnalysisModule fKernelModule; /** * Test setup */ @Before public void setup() { ITmfTrace ustTrace = CtfTmfTestTraceUtils.getTrace(UST_TRACE); ITmfTrace kernelTrace = LttngKernelTestTraceUtils.getTrace(KERNEL_TRACE); TmfExperiment experiment = new TmfExperiment(CtfTmfEvent.class, "test-exp", new ITmfTrace[] { ustTrace, kernelTrace }, TmfExperiment.DEFAULT_INDEX_PAGE_SIZE, null); /* Simulate experiment being opened */ TmfSignalManager.dispatchSignal(new TmfTraceOpenedSignal(this, experiment, null)); TmfSignalManager.dispatchSignal(new TmfTraceSelectedSignal(this, experiment)); KernelAnalysisModule module = TmfTraceUtils.getAnalysisModuleOfClass(experiment, KernelAnalysisModule.class, KernelAnalysisModule.ID); assertNotNull(module); module.waitForCompletion(); fExperiment = experiment; fUstTrace = ustTrace; fKernelModule = module; } /** * Test teardown */ @After public void tearDown() { if (fExperiment != null) { fExperiment.dispose(); } CtfTmfTestTraceUtils.dispose(UST_TRACE); LttngKernelTestTraceUtils.dispose(KERNEL_TRACE); } /** * Test that the TID given by the kernel analysis matches the one from the * UST event's context for a given UST event that was known to fail. * * Reproduces the specific example that was pointed out in bug 484620. */ @Test public void testOneEvent() { TmfExperiment experiment = fExperiment; ITmfTrace ustTrace = fUstTrace; KernelAnalysisModule module = fKernelModule; assertNotNull(experiment); assertNotNull(ustTrace); assertNotNull(module); Predicate<@NonNull ITmfEvent> eventFinder = event -> { Long addr = event.getContent().getFieldValue(Long.class, "addr"); Long cs = event.getContent().getFieldValue(Long.class, "call_site"); Long ctxVtid = event.getContent().getFieldValue(Long.class, "context._vtid"); if (addr == null || cs == null || ctxVtid == null) { return false; } return Objects.equals(event.getType().getName(), "lttng_ust_cyg_profile:func_entry") && Objects.equals(Long.toHexString(addr), "804af97") && Objects.equals(Long.toHexString(cs), "804ab03") && Objects.equals(ctxVtid.longValue(), 594L); }; /* The event we're looking for is the second event matching the predicate */ CtfTmfEvent ustEvent = (CtfTmfEvent) TmfTraceUtils.getNextEventMatching(experiment, 0, eventFinder, null); assertNotNull(ustEvent); long rank = experiment.seekEvent(ustEvent.getTimestamp()).getRank() + 1; ustEvent = (CtfTmfEvent) TmfTraceUtils.getNextEventMatching(experiment, rank, eventFinder, null); assertNotNull(ustEvent); assertEquals(ustTrace, ustEvent.getTrace()); Integer tidFromKernel = KernelThreadInformationProvider.getThreadOnCpu(module, ustEvent.getCPU(), ustEvent.getTimestamp().toNanos()); assertNotNull(tidFromKernel); assertEquals(594, tidFromKernel.intValue()); } /** * Test going through the whole UST trace, making sure the VTID context of * each event corresponds to the TID given by the kernel analysis at the * same timestamp. */ @Test public void testWholeUstTrace() { TmfExperiment experiment = fExperiment; ITmfTrace ustTrace = fUstTrace; KernelAnalysisModule module = fKernelModule; assertNotNull(experiment); assertNotNull(ustTrace); assertNotNull(module); ITmfContext context = ustTrace.seekEvent(0L); CtfTmfEvent ustEvent = (CtfTmfEvent) ustTrace.getNext(context); int count = 0; while (ustEvent != null) { Long ustVtid = ustEvent.getContent().getFieldValue(Long.class, "context._vtid"); /* All events in the trace should have that context */ assertNotNull(ustVtid); long ts = ustEvent.getTimestamp().toNanos(); long cpu = ustEvent.getCPU(); Integer kernelTid = KernelThreadInformationProvider.getThreadOnCpu(module, cpu, ts); assertNotNull(kernelTid); assertEquals("Wrong TID for trace event " + ustEvent.toString(), ustVtid.longValue(), kernelTid.longValue()); ustEvent = (CtfTmfEvent) ustTrace.getNext(context); count++; } /* Make sure we've read all expected events */ assertEquals(UST_TRACE.getNbEvents(), count); } }