diff --git a/analysis/org.eclipse.tracecompass.analysis.profiling.core.tests/src/org/eclipse/tracecompass/analysis/profiling/core/tests/callgraph/sampled/SampledCallGraphTest.java b/analysis/org.eclipse.tracecompass.analysis.profiling.core.tests/src/org/eclipse/tracecompass/analysis/profiling/core/tests/callgraph/sampled/SampledCallGraphTest.java new file mode 100644 index 0000000000..cbf2678d5b --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.profiling.core.tests/src/org/eclipse/tracecompass/analysis/profiling/core/tests/callgraph/sampled/SampledCallGraphTest.java @@ -0,0 +1,153 @@ +/******************************************************************************* + * Copyright (c) 2017 É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.analysis.profiling.core.tests.callgraph.sampled; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.analysis.profiling.core.base.ICallStackElement; +import org.eclipse.tracecompass.analysis.profiling.core.callgraph.AggregatedCallSite; +import org.eclipse.tracecompass.analysis.profiling.core.callgraph.CallGraph; +import org.eclipse.tracecompass.analysis.profiling.core.callstack2.CallStackElement; +import org.eclipse.tracecompass.analysis.profiling.core.sampled.callgraph.ProfilingCallGraphAnalysisModule; +import org.eclipse.tracecompass.analysis.profiling.core.tests.CallStackTestBase2; +import org.eclipse.tracecompass.analysis.profiling.core.tree.IWeightedTreeGroupDescriptor; +import org.eclipse.tracecompass.internal.analysis.profiling.core.tree.AllGroupDescriptor; +import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; +import org.eclipse.tracecompass.tmf.core.util.Pair; +import org.junit.Test; + +/** + * Test profiling data where the input are stack traces from events + * + * @author Geneviève Bastien + */ +public class SampledCallGraphTest { + + private static final long @NonNull [] CALLSITE_1 = { 1, 2, 3, 4 }; + private static final long @NonNull [] CALLSITE_2 = { 1, 2, 3 }; + private static final long @NonNull [] CALLSITE_3 = { 1, 2, 3, 4 }; + private static final long @NonNull [] CALLSITE_4 = { 1, 3, 4 }; + private static final long @NonNull [] CALLSITE_5 = { 1, 2, 5 }; + private static final long @NonNull [] CALLSITE_6 = { 1, 2, 5, 4 }; + private static final long @NonNull [] CALLSITE_7 = { 10, 11, 12 }; + private static final long @NonNull [] CALLSITE_8 = { 10, 11 }; + private static final long @NonNull [] CALLSITE_9 = { 1, 2, 3, 4 }; + private static final long @NonNull [] CALLSITE_10 = { 1, 2, 4, 5 }; + + /** + * A default implementation of the profiling call graph analysis for test + * purposes + */ + private static class TestProfilingAnalysis extends ProfilingCallGraphAnalysisModule { + + private final @NonNull ICallStackElement fOneElement; + + public TestProfilingAnalysis() { + ICallStackElement element = new CallStackElement("test", AllGroupDescriptor.getInstance()); + addRootElement(element); + fOneElement = element; + } + + public @NonNull ICallStackElement getElement() { + return fOneElement; + } + + @Override + public Collection getGroupDescriptors() { + return Collections.singleton(AllGroupDescriptor.getInstance()); + } + + @Override + public Map> getCallStack(@NonNull ITmfEvent event) { + return Collections.emptyMap(); + } + + @Override + protected @Nullable Pair<@NonNull ICallStackElement, @NonNull AggregatedCallSite> getProfiledStackTrace(@NonNull ITmfEvent event) { + return null; + } + + } + + /** + * Test a full sampling for one group + */ + @Test + public void testStackTraces() { + TestProfilingAnalysis pg = new TestProfilingAnalysis(); + try { + ICallStackElement element = pg.getElement(); + + CallGraph cg = pg.getCallGraph(); + cg.addAggregatedCallSite(element, pg.getCallSite(element, CALLSITE_1, 1)); + cg.addAggregatedCallSite(element, pg.getCallSite(element, CALLSITE_2, 2)); + cg.addAggregatedCallSite(element, pg.getCallSite(element, CALLSITE_3, 3)); + cg.addAggregatedCallSite(element, pg.getCallSite(element, CALLSITE_4, 4)); + cg.addAggregatedCallSite(element, pg.getCallSite(element, CALLSITE_5, 5)); + cg.addAggregatedCallSite(element, pg.getCallSite(element, CALLSITE_6, 6)); + cg.addAggregatedCallSite(element, pg.getCallSite(element, CALLSITE_7, 7)); + cg.addAggregatedCallSite(element, pg.getCallSite(element, CALLSITE_8, 8)); + cg.addAggregatedCallSite(element, pg.getCallSite(element, CALLSITE_9, 9)); + cg.addAggregatedCallSite(element, pg.getCallSite(element, CALLSITE_10, 10)); + + Collection aggregatedData = cg.getCallingContextTree(element); + + assertNotNull(aggregatedData); + assertEquals(2, aggregatedData.size()); + + for (AggregatedCallSite callsite : aggregatedData) { + switch (CallStackTestBase2.getCallSiteSymbol(callsite).resolve(Collections.emptySet())) { + case "0x1": { + assertEquals(8, callsite.getWeight()); + assertEquals(2, callsite.getCallees().size()); + for (AggregatedCallSite childCallsite : callsite.getCallees()) { + switch (CallStackTestBase2.getCallSiteSymbol(childCallsite).resolve(Collections.emptySet())) { + case "0x2": + assertEquals(7, childCallsite.getWeight()); + assertEquals(3, childCallsite.getCallees().size()); + break; + case "0x3": + assertEquals(1, childCallsite.getWeight()); + assertEquals(1, childCallsite.getCallees().size()); + break; + default: + throw new IllegalStateException("Unknown callsite: " + CallStackTestBase2.getCallSiteSymbol(childCallsite)); + } + } + } + break; + case "0xa": { + assertEquals(2, callsite.getWeight()); + assertEquals(1, callsite.getCallees().size()); + AggregatedCallSite childCallsite = callsite.getCallees().iterator().next(); + assertEquals(2, childCallsite.getWeight()); + assertEquals(1, callsite.getCallees().size()); + } + break; + default: + throw new IllegalStateException("Unknown callsite: " + CallStackTestBase2.getCallSiteSymbol(callsite)); + } + } + } finally { + pg.dispose(); + } + + } + +} diff --git a/analysis/org.eclipse.tracecompass.analysis.profiling.core/META-INF/MANIFEST.MF b/analysis/org.eclipse.tracecompass.analysis.profiling.core/META-INF/MANIFEST.MF index 6b2a1ad763..1291088585 100644 --- a/analysis/org.eclipse.tracecompass.analysis.profiling.core/META-INF/MANIFEST.MF +++ b/analysis/org.eclipse.tracecompass.analysis.profiling.core/META-INF/MANIFEST.MF @@ -36,6 +36,7 @@ Export-Package: org.eclipse.tracecompass.analysis.profiling.core.base;uses:="org org.eclipse.tracecompass.analysis.profiling.core.callstack2, org.eclipse.tracecompass.analysis.profiling.core.instrumented, org.eclipse.tracecompass.analysis.profiling.core.model, + org.eclipse.tracecompass.analysis.profiling.core.sampled.callgraph, org.eclipse.tracecompass.analysis.profiling.core.tree, org.eclipse.tracecompass.internal.analysis.profiling.core;x-friends:="org.eclipse.tracecompass.analysis.profiling.core.tests,org.eclipse.tracecompass.analysis.profiling.ui", org.eclipse.tracecompass.internal.analysis.profiling.core.callgraph;x-friends:="org.eclipse.tracecompass.analysis.profiling.core.tests,org.eclipse.tracecompass.analysis.profiling.ui", diff --git a/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/analysis/profiling/core/callstack/IEventCallStackProvider.java b/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/analysis/profiling/core/callstack/IEventCallStackProvider.java new file mode 100644 index 0000000000..7d31d81b97 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/analysis/profiling/core/callstack/IEventCallStackProvider.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2017 É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.analysis.profiling.core.callstack; + +import java.util.Collection; +import java.util.Map; + +import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; + +/** + * An interface that analyses can implement if they can provide a stack of + * called function for a single event. + * + * @author Geneviève Bastien + * @since 2.5 + */ +public interface IEventCallStackProvider { + + /** + * Get the callstack from an event + * + * @param event + * The event for which to get the stack + * @return The callstack for the event, grouped by some domain, where the + * first element of each collection is the root. + */ + Map> getCallStack(ITmfEvent event); + +} diff --git a/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/internal/analysis/profiling/core/instrumented/CallStackGroupDescriptor.java b/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/analysis/profiling/core/instrumented/CallStackGroupDescriptor.java similarity index 95% rename from analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/internal/analysis/profiling/core/instrumented/CallStackGroupDescriptor.java rename to analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/analysis/profiling/core/instrumented/CallStackGroupDescriptor.java index 17f4b472de..bd56699af0 100644 --- a/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/internal/analysis/profiling/core/instrumented/CallStackGroupDescriptor.java +++ b/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/analysis/profiling/core/instrumented/CallStackGroupDescriptor.java @@ -9,7 +9,7 @@ * SPDX-License-Identifier: EPL-2.0 *******************************************************************************/ -package org.eclipse.tracecompass.internal.analysis.profiling.core.instrumented; +package org.eclipse.tracecompass.analysis.profiling.core.instrumented; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.tracecompass.analysis.profiling.core.base.ICallStackGroupDescriptor; @@ -18,6 +18,7 @@ * A basic group descriptor implementation. * * @author Geneviève Bastien + * @since 2.5 */ public class CallStackGroupDescriptor implements ICallStackGroupDescriptor { diff --git a/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/analysis/profiling/core/sampled/callgraph/AggregatedStackTraces.java b/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/analysis/profiling/core/sampled/callgraph/AggregatedStackTraces.java new file mode 100644 index 0000000000..6b6db1f91d --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/analysis/profiling/core/sampled/callgraph/AggregatedStackTraces.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2017 É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.analysis.profiling.core.sampled.callgraph; + +import org.eclipse.tracecompass.analysis.profiling.core.base.ICallStackSymbol; +import org.eclipse.tracecompass.analysis.profiling.core.callgraph.AggregatedCallSite; + +/** + * A data structure aggregating data from the callstack for sampled call stack + * data. It counts the number of times each frame pointer was present in a given + * stack + * + * @author Geneviève Bastien + * @since 2.5 + */ +public class AggregatedStackTraces extends AggregatedCallSite { + + /** + * Constructor + * + * @param symbol + * The symbol for this frame pointer + */ + public AggregatedStackTraces(ICallStackSymbol symbol) { + super(symbol, 1); + } + + private AggregatedStackTraces(AggregatedStackTraces toCopy) { + super(toCopy); + } + + @Override + public AggregatedStackTraces copyOf() { + return new AggregatedStackTraces(this); + } + +} diff --git a/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/analysis/profiling/core/sampled/callgraph/ProfilingCallGraphAnalysisModule.java b/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/analysis/profiling/core/sampled/callgraph/ProfilingCallGraphAnalysisModule.java new file mode 100644 index 0000000000..3664a2db40 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/analysis/profiling/core/sampled/callgraph/ProfilingCallGraphAnalysisModule.java @@ -0,0 +1,264 @@ +/******************************************************************************* + * Copyright (c) 2017 É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.analysis.profiling.core.sampled.callgraph; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.analysis.profiling.core.base.ICallStackElement; +import org.eclipse.tracecompass.analysis.profiling.core.base.ICallStackSymbol; +import org.eclipse.tracecompass.analysis.profiling.core.callgraph.AggregatedCallSite; +import org.eclipse.tracecompass.analysis.profiling.core.callgraph.CallGraph; +import org.eclipse.tracecompass.analysis.profiling.core.callgraph.ICallGraphProvider2; +import org.eclipse.tracecompass.analysis.profiling.core.callstack.IEventCallStackProvider; +import org.eclipse.tracecompass.analysis.profiling.core.callstack2.CallStackSymbolFactory; +import org.eclipse.tracecompass.internal.analysis.profiling.core.Activator; +import org.eclipse.tracecompass.internal.analysis.profiling.core.callgraph2.Messages; +import org.eclipse.tracecompass.tmf.core.analysis.TmfAbstractAnalysisModule; +import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; +import org.eclipse.tracecompass.tmf.core.event.TmfEvent; +import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException; +import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest; +import org.eclipse.tracecompass.tmf.core.request.TmfEventRequest; +import org.eclipse.tracecompass.tmf.core.symbols.ISymbolProvider; +import org.eclipse.tracecompass.tmf.core.symbols.SymbolProviderManager; +import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp; +import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment; +import org.eclipse.tracecompass.tmf.core.util.Pair; + +/** + * The callgraph analysis module + * + * @author Geneviève Bastien + * @since 2.5 + */ +public abstract class ProfilingCallGraphAnalysisModule extends TmfAbstractAnalysisModule implements ICallGraphProvider2, IEventCallStackProvider { + + private static final MetricType WEIGHT_METRIC = new MetricType(Objects.requireNonNull(Messages.CallGraphStats_NbCalls), DataType.NUMBER, null); + + private @Nullable ITmfEventRequest fRequest; + private final Set fRootElements = new HashSet<>(); + + private @Nullable CallGraph fFullRangeCallGraph; + private @Nullable Collection fSymbolProviders = null; + + /** + * Get the root elements from this call graph hierarchy + * + * @return The root elements + */ + protected Collection getRootElements() { + return fRootElements; + } + + /** + * Add a root element to call graph + * + * @param element + * The root element to add + */ + public void addRootElement(ICallStackElement element) { + fRootElements.add(element); + } + + @Override + public CallGraph getCallGraph(ITmfTimestamp start, ITmfTimestamp end) { + CallGraph cg = executeForRange(new TmfTimeRange(start, end)); + if (cg == null) { + return CallGraph.EMPTY_GRAPH; + } + return cg; + } + + @Override + public CallGraph getCallGraph() { + CallGraph cg = fFullRangeCallGraph; + if (cg == null) { + return CallGraph.EMPTY_GRAPH; + } + return cg; + } + + @Override + public MetricType getWeightType() { + return WEIGHT_METRIC; + } + + @Override + public String getTitle() { + return "Call Graph"; //$NON-NLS-1$ + } + + @Override + public String toDisplayString(AggregatedCallSite callsite) { + Collection symbolProviders = fSymbolProviders; + if (symbolProviders == null) { + ITmfTrace trace = getTrace(); + if (trace == null) { + return String.valueOf(callsite.getObject()); + } + symbolProviders = SymbolProviderManager.getInstance().getSymbolProviders(trace); + fSymbolProviders = symbolProviders; + } + return callsite.getObject().resolve(symbolProviders); + } + + @Override + public AggregatedCallSite createCallSite(Object symbol) { + return new AggregatedStackTraces((ICallStackSymbol) symbol); + } + + /** + * Get a callsite from a stack trace. The array should be non-zero length and + * the symbol at position 0 is the top of the stack, ie the last symbol called. + * + * @param dstGroup + * The element to which to add this stack trace + * @param stackTrace + * The stack trace to add to the group + * @param ts + * The timestamp at which this stack trace is added + * @return The callsite + * @throws ArrayIndexOutOfBoundsException + * Exception thrown if the stackTrace is empty + */ + public AggregatedCallSite getCallSite(ICallStackElement dstGroup, long[] stackTrace, long ts) { + if (stackTrace.length == 0) { + throw new ArrayIndexOutOfBoundsException("Get callsite, the received array should not be null"); //$NON-NLS-1$ + } + // Create the callsite for this stack trace + AggregatedCallSite prevCallsite = createCallSite(CallStackSymbolFactory.createSymbol(stackTrace[stackTrace.length - 1], dstGroup, ts)); + for (int i = stackTrace.length - 2; i >= 0; i--) { + AggregatedCallSite callsite = createCallSite(CallStackSymbolFactory.createSymbol(stackTrace[i], dstGroup, ts)); + callsite.addChild(prevCallsite); + prevCallsite = callsite; + } + return prevCallsite; + } + + /** + * Method to implement to get the call stack from an event. It returns a + * stack trace in the form or a Pair of {@link ICallStackElement} and + * {@link AggregatedCallSite}. + * + * @param event + * The trace event to process + * @return A pair of callstack element and aggregated callsite from this + * event + */ + protected abstract @Nullable Pair getProfiledStackTrace(ITmfEvent event); + + @Override + protected boolean executeAnalysis(IProgressMonitor monitor) throws TmfAnalysisException { + CallGraph callgraph = executeForRange(TmfTimeRange.ETERNITY); + if (callgraph == null) { + return false; + } + fFullRangeCallGraph = callgraph; + return true; + } + + private @Nullable CallGraph executeForRange(TmfTimeRange range) { + ITmfTrace trace = getTrace(); + if (trace == null) { + throw new NullPointerException("Trace has not been set, yet the analysis is being run!"); //$NON-NLS-1$ + } + /* Cancel any previous request */ + ITmfEventRequest request = fRequest; + if ((request != null) && (!request.isCompleted())) { + request.cancel(); + } + + try { + CallGraph callGraph = new CallGraph(); + request = new ProfilingEventRequest(trace, callGraph, range); + fRequest = request; + trace.sendRequest(request); + + request.waitForCompletion(); + if (!request.isCompleted()) { + return null; + } + return callGraph; + } catch (InterruptedException e) { + Activator.getInstance().logError("Request interrupted", e); //$NON-NLS-1$ + } + return null; + } + + @Override + protected void canceling() { + ITmfEventRequest req = fRequest; + if ((req != null) && (!req.isCompleted())) { + req.cancel(); + } + } + + private class ProfilingEventRequest extends TmfEventRequest { + + private final ITmfTrace fTrace; + private final CallGraph fCallGraph; + + /** + * Constructor + * + * @param trace + * The trace + * @param callgraph + * The callgraph to fill + * @param range + * The time range of this request + */ + public ProfilingEventRequest(ITmfTrace trace, CallGraph callgraph, TmfTimeRange range) { + super(TmfEvent.class, + range, + 0, + ITmfEventRequest.ALL_DATA, + ITmfEventRequest.ExecutionType.BACKGROUND); + fTrace = trace; + fCallGraph = callgraph; + } + + @Override + public void handleData(final ITmfEvent event) { + super.handleData(event); + if (event.getTrace() == fTrace) { + processEvent(event); + } else if (fTrace instanceof TmfExperiment) { + /* + * If the request is for an experiment, check if the event is + * from one of the child trace + */ + for (ITmfTrace childTrace : ((TmfExperiment) fTrace).getTraces()) { + if (childTrace == event.getTrace()) { + processEvent(event); + } + } + } + } + + private void processEvent(ITmfEvent event) { + Pair perfCallSite = getProfiledStackTrace(event); + if (perfCallSite == null) { + return; + } + fCallGraph.addAggregatedCallSite(perfCallSite.getFirst(), perfCallSite.getSecond()); + } + } + +} diff --git a/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/analysis/profiling/core/sampled/callgraph/package-info.java b/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/analysis/profiling/core/sampled/callgraph/package-info.java new file mode 100644 index 0000000000..3b9b1ed87a --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/analysis/profiling/core/sampled/callgraph/package-info.java @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright (c) 2024 É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 + *******************************************************************************/ + +@org.eclipse.jdt.annotation.NonNullByDefault +package org.eclipse.tracecompass.analysis.profiling.core.sampled.callgraph; \ No newline at end of file diff --git a/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/internal/analysis/profiling/core/instrumented/InstrumentedGroupDescriptor.java b/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/internal/analysis/profiling/core/instrumented/InstrumentedGroupDescriptor.java index fc7093ca23..b7a185b0cf 100644 --- a/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/internal/analysis/profiling/core/instrumented/InstrumentedGroupDescriptor.java +++ b/analysis/org.eclipse.tracecompass.analysis.profiling.core/src/org/eclipse/tracecompass/internal/analysis/profiling/core/instrumented/InstrumentedGroupDescriptor.java @@ -14,6 +14,7 @@ import org.apache.commons.lang3.StringUtils; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.analysis.profiling.core.instrumented.CallStackGroupDescriptor; import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; /**