diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.core.tests/src/org/eclipse/tracecompass/lttng2/ust/core/tests/analysis/cpu/UstCpuAnalysisModuleTest.java b/lttng/org.eclipse.tracecompass.lttng2.ust.core.tests/src/org/eclipse/tracecompass/lttng2/ust/core/tests/analysis/cpu/UstCpuAnalysisModuleTest.java new file mode 100644 index 0000000000..56ef1b73a1 --- /dev/null +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.core.tests/src/org/eclipse/tracecompass/lttng2/ust/core/tests/analysis/cpu/UstCpuAnalysisModuleTest.java @@ -0,0 +1,164 @@ +/******************************************************************************* + * Copyright (c) 2022 É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 + *******************************************************************************/ + +package org.eclipse.tracecompass.lttng2.ust.core.tests.analysis.cpu; + +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.util.List; +import java.util.stream.StreamSupport; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.cpu.UstCpuAnalysisModule; +import org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.cpu.UstCpuStateProvider; +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.exceptions.AttributeNotFoundException; +import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException; +import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval; +import org.eclipse.tracecompass.testtraces.ctf.CtfTestTrace; +import org.eclipse.tracecompass.tmf.core.analysis.requirements.TmfAbstractAnalysisRequirement; +import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests for the {@link UstCpuAnalysisModule} + * + * @author Arnaud Fiorini + */ +public class UstCpuAnalysisModuleTest { + + private static final @NonNull CtfTestTrace TRACE_WITHOUT_VTID = CtfTestTrace.DEBUG_INFO4; + private static final @NonNull CtfTestTrace TRACE_WITH_VTID = CtfTestTrace.CYG_PROFILE; + + private UstCpuAnalysisModule fModule; + + /** + * Test setup + */ + @Before + public void setup() { + fModule = new UstCpuAnalysisModule(); + } + + /** + * Test cleanup + */ + @After + public void tearDown() { + fModule.dispose(); + fModule = null; + } + + /** + * Test for {@link UstCpuAnalysisModule#getAnalysisRequirements()} + */ + @Test + public void testGetAnalysisRequirements() { + Iterable requirements = fModule.getAnalysisRequirements(); + assertNotNull(requirements); + assertEquals(1, StreamSupport.stream(requirements.spliterator(), false).count()); + } + + /** + * Test that the analysis can execute on a valid trace. + */ + @Test + public void testCanExecute() { + LttngUstTrace trace = LttngUstTestTraceUtils.getTrace(TRACE_WITH_VTID); + assertTrue(fModule.canExecute(trace)); + LttngUstTestTraceUtils.dispose(TRACE_WITH_VTID); + } + + /** + * Test that the analysis correctly refuses to execute on a trace that does + * not provide vtid. + */ + @Test + public void testCannotExcecute() { + LttngUstTrace invalidTrace = LttngUstTestTraceUtils.getTrace(TRACE_WITHOUT_VTID); + assertFalse(fModule.canExecute(invalidTrace)); + LttngUstTestTraceUtils.dispose(TRACE_WITHOUT_VTID); + } + + private void executeModule(@NonNull ITmfTrace trace) { + try { + fModule.setTrace(trace); + } catch (TmfAnalysisException e) { + fail(); + } + fModule.schedule(); + fModule.waitForCompletion(); + } + + /** + * Test that basic execution of the module works well. + */ + @Test + public void testExecution() { + LttngUstTrace trace = LttngUstTestTraceUtils.getTrace(TRACE_WITH_VTID); + executeModule(trace); + ITmfStateSystem ss = fModule.getStateSystem(); + assertNotNull(ss); + LttngUstTestTraceUtils.dispose(TRACE_WITH_VTID); + } + + /** + * Test that the state system generated is correct. + */ + @Test + public void testGetCpuForThread() { + LttngUstTrace trace = LttngUstTestTraceUtils.getTrace(TRACE_WITH_VTID); + executeModule(trace); + ITmfStateSystem ss = fModule.getStateSystem(); + assertNotNull(ss); + + // Test threads quark exists + int parentThreadsQuark = -1; + try { + parentThreadsQuark = ss.getQuarkAbsolute(UstCpuStateProvider.THREADS); + } catch (AttributeNotFoundException e) { + fail(); + } + + // Test that there is the correct number of threads + List<@NonNull Integer> threadsQuarks = ss.getSubAttributes(parentThreadsQuark, false); + assertEquals(1, threadsQuarks.size()); + + // Test that at multiple specific time the cpu value is correct + Integer threadQuark = threadsQuarks.iterator().next(); + try { + // End of the trace + ITmfStateInterval cpuState = ss.querySingleState(ss.getCurrentEndTime(), threadQuark); + assertNotNull(cpuState.getValue()); + assertEquals(3, cpuState.getValue()); + // Beginning of the trace + cpuState = ss.querySingleState(ss.getStartTime(), threadQuark); + assertNotNull(cpuState.getValue()); + assertEquals(0, cpuState.getValue()); + // Middle of the trace + cpuState = ss.querySingleState(ss.getStartTime() + (ss.getCurrentEndTime() - ss.getStartTime()) / 2, threadQuark); + assertNotNull(cpuState.getValue()); + assertEquals(3, cpuState.getValue()); + } catch (StateSystemDisposedException e) { + fail(); + } + LttngUstTestTraceUtils.dispose(TRACE_WITH_VTID); + } +} diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.core/META-INF/MANIFEST.MF b/lttng/org.eclipse.tracecompass.lttng2.ust.core/META-INF/MANIFEST.MF index 5a93490a22..2a24fb0077 100644 --- a/lttng/org.eclipse.tracecompass.lttng2.ust.core/META-INF/MANIFEST.MF +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.core/META-INF/MANIFEST.MF @@ -9,6 +9,7 @@ Bundle-Activator: org.eclipse.tracecompass.internal.lttng2.ust.core.Activator Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Export-Package: org.eclipse.tracecompass.internal.lttng2.ust.core;x-friends:="org.eclipse.tracecompass.lttng2.ust.core.tests,org.eclipse.tracecompass.lttng2.ust.ui", + org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.cpu;x-friends:="org.eclipse.tracecompass.lttng2.ust.core.tests", org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.debuginfo;x-friends:="org.eclipse.tracecompass.lttng2.ust.core.tests,org.eclipse.tracecompass.lttng2.ust.ui", org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.memory;x-friends:="org.eclipse.tracecompass.lttng2.ust.ui,org.eclipse.tracecompass.lttng2.ust.core.tests", org.eclipse.tracecompass.internal.lttng2.ust.core.callstack;x-friends:="org.eclipse.tracecompass.lttng2.ust.ui,org.eclipse.tracecompass.lttng2.ust.core.tests,org.eclipse.tracecompass.lttng2.ust.ui.swtbot.tests", @@ -31,7 +32,8 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.tracecompass.analysis.timing.core, org.eclipse.tracecompass.segmentstore.core, org.eclipse.tracecompass.datastore.core, - org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional + org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional, + org.apache.commons.lang Import-Package: com.google.common.annotations;version="15.0.0", com.google.common.base, com.google.common.cache, diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.core/icons/threads.png b/lttng/org.eclipse.tracecompass.lttng2.ust.core/icons/threads.png new file mode 100644 index 0000000000..59f3ffd3b3 Binary files /dev/null and b/lttng/org.eclipse.tracecompass.lttng2.ust.core/icons/threads.png differ diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.core/plugin.xml b/lttng/org.eclipse.tracecompass.lttng2.ust.core/plugin.xml index d2ef4a098d..72f3232b4f 100644 --- a/lttng/org.eclipse.tracecompass.lttng2.ust.core/plugin.xml +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.core/plugin.xml @@ -55,6 +55,16 @@ class="org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace"> + + + + diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/internal/lttng2/ust/core/analysis/cpu/UstCpuAnalysisModule.java b/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/internal/lttng2/ust/core/analysis/cpu/UstCpuAnalysisModule.java new file mode 100644 index 0000000000..3dcd3db574 --- /dev/null +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/internal/lttng2/ust/core/analysis/cpu/UstCpuAnalysisModule.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2022 É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 + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.cpu; + +import java.util.Collections; +import java.util.Objects; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.tracecompass.internal.lttng2.ust.core.trace.ContextVtidAspect; +import org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace; +import org.eclipse.tracecompass.tmf.core.analysis.requirements.TmfAbstractAnalysisRequirement; +import org.eclipse.tracecompass.tmf.core.analysis.requirements.TmfAbstractAnalysisRequirement.PriorityLevel; +import org.eclipse.tracecompass.tmf.core.event.aspect.ITmfEventAspect; +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.TmfTraceUtils; + +import com.google.common.collect.ImmutableSet; + +/** + * This analysis builds a state system from the cpu + * + * @author Arnaud Fiorini + */ +public class UstCpuAnalysisModule extends TmfStateSystemAnalysisModule { + + /** + * Analysis ID, it should match that in the plugin.xml file + */ + public static final @NonNull String ID = "org.eclipse.linuxtools.lttng2.ust.analysis.cpu"; //$NON-NLS-1$ + + private static final @NonNull TmfAbstractAnalysisRequirement VTID_ASPECT_REQUIREMENT = new TmfAbstractAnalysisRequirement( + Collections.emptySet(), PriorityLevel.MANDATORY) { + @Override + public boolean test(ITmfTrace trace) { + if (trace instanceof LttngUstTrace) { + Iterable<@NonNull ITmfEventAspect> eventAspects = TmfTraceUtils.getEventAspects(trace, ContextVtidAspect.class); + return eventAspects.iterator().hasNext(); + } + return false; + } + }; + + @Override + public ITmfStateProvider createStateProvider() { + return new UstCpuStateProvider(Objects.requireNonNull(getTrace())); + } + + @Override + public Iterable getAnalysisRequirements() { + return ImmutableSet.of(VTID_ASPECT_REQUIREMENT); + } +} diff --git a/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/internal/lttng2/ust/core/analysis/cpu/UstCpuStateProvider.java b/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/internal/lttng2/ust/core/analysis/cpu/UstCpuStateProvider.java new file mode 100644 index 0000000000..a8be71d2bb --- /dev/null +++ b/lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/internal/lttng2/ust/core/analysis/cpu/UstCpuStateProvider.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2022 É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 + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.cpu; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.tracecompass.internal.lttng2.ust.core.trace.ContextVtidAspect; +import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder; +import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; +import org.eclipse.tracecompass.tmf.core.statesystem.AbstractTmfStateProvider; +import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; +import org.eclipse.tracecompass.tmf.ctf.core.event.CtfTmfEvent; + +/** + * Creates a state system with a quark for each thread describing which CPU is + * in use. + * + * This state system is useful to get the CPU number in analysis of LTTng UST + * traces. More specifically, to get callsite information or other analyses. + * + * Attribute tree: + * + *
+ * |- Threads
+ * |  |-  -> CPU number for this TID depending on LTTng UST events
+ * 
+ * + * @author Arnaud Fiorini + */ +public class UstCpuStateProvider extends AbstractTmfStateProvider { + + /** + * State system ID + */ + public static final @NonNull String ID = "org.eclipse.linuxtools.lttng2.ust.analysis.cpu.stateprovider"; //$NON-NLS-1$ + + /** State system attribute name for the Threads to CPU mappings */ + public static final String THREADS = "Threads"; //$NON-NLS-1$ + + /** + * @param trace + * the trace to build the state system + */ + public UstCpuStateProvider(@NonNull ITmfTrace trace) { + super(trace, ID); + } + + @Override + public int getVersion() { + return 0; + } + + @Override + public @NonNull ITmfStateProvider getNewInstance() { + return new UstCpuStateProvider(getTrace()); + } + + @Override + protected void eventHandle(@NonNull ITmfEvent event) { + ITmfStateSystemBuilder ssb = checkNotNull(getStateSystemBuilder()); + CtfTmfEvent ctfEvent = (CtfTmfEvent) event; + int cpuId = ctfEvent.getCPU(); + Object vtid = TmfTraceUtils.resolveEventAspectOfClassForEvent(getTrace(), ContextVtidAspect.class, event); + if (vtid != null) { + int threadQuark = ssb.getQuarkAbsoluteAndAdd(THREADS, vtid.toString()); + ssb.modifyAttribute(event.getTimestamp().getValue(), cpuId, threadQuark); + } + } +}