Skip to content

Commit

Permalink
lttng-ust: Add cpu analysis to be able to query the callsite statesystem
Browse files Browse the repository at this point in the history
This analysis is needed because the callsite state system cannot be
queried by a data provider if the user only has a ust trace.

[Added] UstCpuAnalysisModule and UstCpuStateProvider

Change-Id: I0f161ce4847c59b8dc7239482d6e0c3fc247cf27
Signed-off-by: Arnaud Fiorini <fiorini.arnaud@gmail.com>
Reviewed-on: https://git.eclipse.org/r/c/tracecompass/org.eclipse.tracecompass/+/188705
Tested-by: Trace Compass Bot <tracecompass-bot@eclipse.org>
Tested-by: Marco Miller <marco.miller@ericsson.com>
Reviewed-by: Marco Miller <marco.miller@ericsson.com>
  • Loading branch information
arfio authored and marco-miller committed Nov 11, 2022
1 parent 154bd2e commit aaed95b
Show file tree
Hide file tree
Showing 6 changed files with 321 additions and 1 deletion.
@@ -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<TmfAbstractAnalysisRequirement> 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);
}
}
Expand Up @@ -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",
Expand All @@ -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,
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions lttng/org.eclipse.tracecompass.lttng2.ust.core/plugin.xml
Expand Up @@ -55,6 +55,16 @@
class="org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace">
</tracetype>
</module>
<module
analysis_module="org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.cpu.UstCpuAnalysisModule"
automatic="true"
icon="icons/threads.png"
id="org.eclipse.linuxtools.lttng2.ust.analysis.cpu"
name="CPU Analysis">
<tracetype
class="org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace">
</tracetype>
</module>
</extension>
<extension
point="org.eclipse.tracecompass.tmf.core.dataprovider">
Expand Down
@@ -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<TmfAbstractAnalysisRequirement> getAnalysisRequirements() {
return ImmutableSet.of(VTID_ASPECT_REQUIREMENT);
}
}
@@ -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:
*
* <pre>
* |- Threads
* | |- <TID> -> CPU number for this TID depending on LTTng UST events
* </pre>
*
* @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);
}
}
}

0 comments on commit aaed95b

Please sign in to comment.