Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
callstack: Add incubated LTTngUstCallStack tests
To fully pass these tests locally, [1] has to be extracted under [2]. [1] https://archive.eclipse.org/tracecompass/test-traces/qmlscene.tgz [2] ctf/org.eclipse.tracecompass.ctf.core.tests/traces/ Also, these tests require more than the default -Xmx512m of heap in the Eclipse launcher. Required is at least -Xmx1024m of maximal heap. Change-Id: I647cc228257646413957474130ea83c1835d36e1 Signed-off-by: Marco Miller <marco.miller@ericsson.com> Reviewed-on: https://git.eclipse.org/r/c/tracecompass/org.eclipse.tracecompass/+/199766 Tested-by: Trace Compass Bot <tracecompass-bot@eclipse.org> Tested-by: Bernd Hufmann <bernd.hufmann@ericsson.com> Reviewed-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
- Loading branch information
1 parent
eda2ffe
commit 21139ab
Showing
5 changed files
with
455 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
114 changes: 114 additions & 0 deletions
114
.../tracecompass/analysis/callstack/core/tests/LTTngUstCallStackAnalysisRequirementTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2016 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 | ||
*******************************************************************************/ | ||
|
||
package org.eclipse.tracecompass.analysis.callstack.core.tests; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
|
||
import java.util.Set; | ||
|
||
import org.eclipse.jdt.annotation.NonNull; | ||
import org.eclipse.tracecompass.internal.analysis.callstack.core.LttngUstCallStackAnalysisRequirement; | ||
import org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace; | ||
import org.eclipse.tracecompass.lttng2.ust.core.trace.layout.ILttngUstEventLayout; | ||
import org.eclipse.tracecompass.tmf.ctf.core.event.CtfTmfEventType; | ||
import org.junit.AfterClass; | ||
import org.junit.Test; | ||
|
||
import com.google.common.collect.ImmutableSet; | ||
|
||
/** | ||
* Test the {@link LttngUstCallStackAnalysisRequirement} class | ||
* | ||
* @author Bernd Hufmann | ||
*/ | ||
public class LTTngUstCallStackAnalysisRequirementTest { | ||
|
||
private static final @NonNull String FUNC_EXIT_FAST = "lttng_ust_cyg_profile_fast:func_exit"; | ||
private static final @NonNull String FUNC_EXIT = "lttng_ust_cyg_profile:func_exit"; | ||
private static final @NonNull String FUNC_ENTRY_FAST = "lttng_ust_cyg_profile_fast:func_entry"; | ||
private static final @NonNull String FUNC_ENTRY = "lttng_ust_cyg_profile:func_entry"; | ||
private static final @NonNull String OTHER_EVENT = "OTHER"; | ||
|
||
enum EventType { | ||
|
||
EVT_EXIT_FAST(FUNC_EXIT_FAST), | ||
EVT_EXIT(FUNC_EXIT), | ||
EVT_ENTRY_FAST(FUNC_ENTRY_FAST), | ||
EVT_ENTRY(FUNC_ENTRY), | ||
EVT_OTHER(OTHER_EVENT); | ||
|
||
private final @NonNull CtfTmfEventType fType; | ||
|
||
EventType(@NonNull String name) { | ||
fType = new CtfTmfEventType(name, null) { | ||
@Override | ||
public String getName() { | ||
return name; | ||
} | ||
}; | ||
} | ||
|
||
@NonNull CtfTmfEventType getEventType() { | ||
return fType; | ||
} | ||
} | ||
|
||
enum TestData { | ||
|
||
TRACE_WITH_VALID_EVENTS(EventType.EVT_ENTRY, EventType.EVT_EXIT, true), | ||
TRACE_WITH_VALID_EVENTS_FAST(EventType.EVT_ENTRY_FAST, EventType.EVT_EXIT_FAST, true), | ||
TRACE_WITH_MISSING_EVENTS(EventType.EVT_OTHER, EventType.EVT_EXIT_FAST, false), | ||
TRACE_MISMATCH_EVENTS(EventType.EVT_ENTRY_FAST, EventType.EVT_EXIT, false); | ||
|
||
private final @NonNull LttngUstTrace fTrace; | ||
private final boolean fIsValid; | ||
|
||
TestData(EventType first, EventType second, boolean isValid) { | ||
fTrace = new LttngUstTrace() { | ||
@Override | ||
public Set<CtfTmfEventType> getContainedEventTypes() { | ||
return ImmutableSet.of(first.getEventType(), second.getEventType()); | ||
} | ||
}; | ||
fIsValid = isValid; | ||
} | ||
|
||
@NonNull LttngUstTrace getTrace() { | ||
return fTrace; | ||
} | ||
|
||
boolean isValid() { | ||
return fIsValid; | ||
} | ||
} | ||
|
||
/** | ||
* Clean up | ||
*/ | ||
@AfterClass | ||
public static void cleanup() { | ||
for (TestData testData : TestData.values()) { | ||
testData.getTrace().dispose(); | ||
} | ||
} | ||
|
||
/** | ||
* Test Call Stack Analysis requirements | ||
*/ | ||
@Test | ||
public void testCallStackRequirements() { | ||
LttngUstCallStackAnalysisRequirement req = new LttngUstCallStackAnalysisRequirement(ILttngUstEventLayout.DEFAULT_LAYOUT); | ||
for (TestData item : TestData.values()) { | ||
assertEquals(item.name(), item.isValid(), req.test(item.getTrace())); | ||
} | ||
} | ||
} |
238 changes: 238 additions & 0 deletions
238
...g/eclipse/tracecompass/analysis/callstack/core/tests/perf/CallStackAndGraphBenchmark.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,238 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2016 É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.callstack.core.tests.perf; | ||
|
||
import static org.junit.Assert.assertNotNull; | ||
import static org.junit.Assert.assertTrue; | ||
|
||
import java.io.File; | ||
import java.security.SecureRandom; | ||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.Iterator; | ||
import java.util.List; | ||
import java.util.Objects; | ||
|
||
import org.eclipse.test.performance.Dimension; | ||
import org.eclipse.test.performance.Performance; | ||
import org.eclipse.test.performance.PerformanceMeter; | ||
import org.eclipse.tracecompass.internal.analysis.callstack.core.callgraph.CallGraph; | ||
import org.eclipse.tracecompass.internal.analysis.callstack.core.callgraph.ICallGraphProvider; | ||
import org.eclipse.tracecompass.internal.analysis.callstack.core.instrumented.IFlameChartProvider; | ||
import org.eclipse.tracecompass.internal.analysis.callstack.core.instrumented.InstrumentedCallStackAnalysis; | ||
import org.eclipse.tracecompass.internal.analysis.callstack.core.tree.AllGroupDescriptor; | ||
import org.eclipse.tracecompass.internal.analysis.callstack.core.tree.IWeightedTreeGroupDescriptor; | ||
import org.eclipse.tracecompass.internal.analysis.callstack.core.tree.WeightedTreeGroupBy; | ||
import org.eclipse.tracecompass.segmentstore.core.ISegment; | ||
import org.eclipse.tracecompass.segmentstore.core.ISegmentStore; | ||
import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule; | ||
import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException; | ||
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal; | ||
import org.eclipse.tracecompass.tmf.core.tests.shared.TmfTestHelper; | ||
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp; | ||
import org.eclipse.tracecompass.tmf.core.trace.TmfTrace; | ||
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; | ||
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; | ||
import org.junit.Test; | ||
|
||
/** | ||
* Benchmarks the flame chart analysis execution and call graph execution, | ||
* partial callgraph for time ranges and group by of call graph. | ||
* | ||
* This base class can be extended by any performance test for analysis that | ||
* implement {@link ICallGraphProvider}, whether or not it also implements | ||
* {@link IFlameChartProvider}. | ||
* | ||
* @author Geneviève Bastien | ||
*/ | ||
public abstract class CallStackAndGraphBenchmark { | ||
|
||
/** | ||
* Test ID for kernel analysis benchmarks | ||
*/ | ||
public static final String TEST_ID = "org.eclipse.tracecompass.analysis#CallStack#"; | ||
|
||
private static final String TEST_CALLSTACK_BUILD = "Building Callstack (%s)"; | ||
private static final String TEST_CALLSTACK_PARSESEGSTORE = "Callstack segment store (%s)"; | ||
private static final String TEST_CALLGRAPH_BUILD = "Building CallGraph (%s)"; | ||
private static final String TEST_CALLGRAPH_QUERY = "CallGraph Query (%s)"; | ||
private static final String TEST_CALLGRAPH_GROUPBY = "CallGraph Group By (%s)"; | ||
|
||
private static final byte[] SEED = { 0x45, 0x73, 0x74, 0x65, 0x6c, 0x6c, 0x65 }; | ||
|
||
private static final int LOOP_COUNT = 5; | ||
|
||
private final String fName; | ||
private final String fAnalysisId; | ||
|
||
/** | ||
* Constructor | ||
* | ||
* @param name | ||
* The name of this test | ||
* @param analysisId | ||
* the ID of the analysis to run this benchmark on | ||
*/ | ||
public CallStackAndGraphBenchmark(String name, String analysisId) { | ||
fName = name; | ||
fAnalysisId = analysisId; | ||
} | ||
|
||
/** | ||
* Run benchmark for the trace | ||
* | ||
* @throws TmfTraceException | ||
* Exceptions thrown getting the trace | ||
*/ | ||
@Test | ||
public void runCpuBenchmark() throws TmfTraceException { | ||
Performance perf = Performance.getDefault(); | ||
PerformanceMeter callStackBuildPm = Objects.requireNonNull(perf.createPerformanceMeter(TEST_ID + String.format(TEST_CALLSTACK_BUILD, fName))); | ||
perf.tagAsSummary(callStackBuildPm, String.format(TEST_CALLSTACK_BUILD, fName), Dimension.CPU_TIME); | ||
PerformanceMeter callStackSegStorePm = Objects.requireNonNull(perf.createPerformanceMeter(TEST_ID + String.format(TEST_CALLSTACK_PARSESEGSTORE, fName))); | ||
perf.tagAsSummary(callStackSegStorePm, String.format(TEST_CALLSTACK_PARSESEGSTORE, fName), Dimension.CPU_TIME); | ||
PerformanceMeter callgraphBuildPm = Objects.requireNonNull(perf.createPerformanceMeter(TEST_ID + String.format(TEST_CALLGRAPH_BUILD, fName))); | ||
perf.tagAsSummary(callgraphBuildPm, String.format(TEST_CALLGRAPH_BUILD, fName), Dimension.CPU_TIME); | ||
PerformanceMeter callgraphQueryPm = perf.createPerformanceMeter(TEST_ID + String.format(TEST_CALLGRAPH_QUERY, fName)); | ||
perf.tagAsSummary(callgraphQueryPm, String.format(TEST_CALLGRAPH_QUERY, fName), Dimension.CPU_TIME); | ||
PerformanceMeter callgraphGroupByPm = perf.createPerformanceMeter(TEST_ID + String.format(TEST_CALLGRAPH_GROUPBY, fName)); | ||
perf.tagAsSummary(callgraphGroupByPm, String.format(TEST_CALLGRAPH_GROUPBY, fName), Dimension.CPU_TIME); | ||
|
||
boolean isFlameChartProvider = false; | ||
for (int i = 0; i < LOOP_COUNT; i++) { | ||
TmfTrace trace = null; | ||
try { | ||
trace = getTrace(); | ||
trace.traceOpened(new TmfTraceOpenedSignal(this, trace, null)); | ||
IAnalysisModule analysisModule = TmfTraceUtils.getAnalysisModuleOfClass(trace, IAnalysisModule.class, fAnalysisId); | ||
assertTrue(analysisModule instanceof ICallGraphProvider); | ||
ICallGraphProvider callGraphModule = (ICallGraphProvider) analysisModule; | ||
|
||
if (analysisModule instanceof IFlameChartProvider) { | ||
// Do the performance test for the instrumented call stack, | ||
// then the call graph building | ||
isFlameChartProvider = true; | ||
benchmarkInstrumented((IFlameChartProvider) analysisModule, callStackBuildPm, callStackSegStorePm, callgraphBuildPm); | ||
} else { | ||
benchmarkCallGraphProvider(callGraphModule, callgraphBuildPm); | ||
} | ||
|
||
/* | ||
* Common benchmarks for both instrumented and profiled | ||
* callgraphs | ||
*/ | ||
// We just read the trace for the first time, so it should be | ||
// safe to use the end time | ||
long startTime = trace.getStartTime().toNanos(); | ||
long endTime = trace.getEndTime().toNanos(); | ||
long delta = endTime - startTime; | ||
|
||
// Get partial callgraphs | ||
SecureRandom randomGenerator = new SecureRandom(SEED); | ||
callgraphQueryPm.start(); | ||
for (int j = 0; j < 50; j++) { | ||
long time0 = Math.abs(randomGenerator.nextLong()) % delta; | ||
long time1 = Math.abs(randomGenerator.nextLong()) % delta; | ||
callGraphModule.getCallGraph(TmfTimestamp.fromNanos(startTime + Math.min(time0, time1)), TmfTimestamp.fromNanos(startTime + Math.max(time0, time1))); | ||
} | ||
callgraphQueryPm.stop(); | ||
|
||
// Benchmark the group by. Do a few iterations in different | ||
// orders | ||
List<IWeightedTreeGroupDescriptor> descriptors = new ArrayList<>(); | ||
descriptors.add(AllGroupDescriptor.getInstance()); | ||
descriptors.addAll(callGraphModule.getGroupDescriptors()); | ||
CallGraph callGraphToGroup = callGraphModule.getCallGraph(); | ||
callgraphGroupByPm.start(); | ||
for (int j = 0; j < 10; j++) { | ||
descriptors.forEach(group -> WeightedTreeGroupBy.groupWeightedTreeBy(group, callGraphToGroup, callGraphModule)); | ||
Collections.reverse(descriptors); | ||
descriptors.forEach(group -> WeightedTreeGroupBy.groupWeightedTreeBy(group, callGraphToGroup, callGraphModule)); | ||
} | ||
callgraphGroupByPm.stop(); | ||
|
||
/* | ||
* Delete the supplementary files, so that the next iteration | ||
* rebuilds the state system. | ||
*/ | ||
File suppDir = new File(TmfTraceManager.getSupplementaryFileDir(trace)); | ||
for (File file : suppDir.listFiles()) { | ||
file.delete(); | ||
} | ||
} finally { | ||
if (trace != null) { | ||
trace.dispose(); | ||
} | ||
} | ||
} | ||
if (isFlameChartProvider) { | ||
callStackBuildPm.commit(); | ||
callStackSegStorePm.commit(); | ||
} | ||
callgraphBuildPm.commit(); | ||
callgraphQueryPm.commit(); | ||
callgraphGroupByPm.commit(); | ||
} | ||
|
||
private static void benchmarkCallGraphProvider(ICallGraphProvider callGraphModule, PerformanceMeter callgraphBuildPm) { | ||
// Do the performance test for building the callgraph only | ||
callgraphBuildPm.start(); | ||
TmfTestHelper.executeAnalysis((IAnalysisModule) callGraphModule); | ||
callgraphBuildPm.stop(); | ||
CallGraph callGraph = callGraphModule.getCallGraph(); | ||
|
||
assertTrue(!callGraph.getElements().isEmpty()); | ||
} | ||
|
||
private static void benchmarkInstrumented(IFlameChartProvider analysisModule, PerformanceMeter callStackBuildPm, PerformanceMeter callStackSegStorePm, PerformanceMeter callgraphBuildPm) { | ||
// Set the instrumented analysis to not trigger the call graph | ||
// automatically, we will do it when ready | ||
if (analysisModule instanceof InstrumentedCallStackAnalysis) { | ||
((InstrumentedCallStackAnalysis) analysisModule).triggerAutomatically(false); | ||
} | ||
|
||
// Benchmark the call stack analysis | ||
callStackBuildPm.start(); | ||
TmfTestHelper.executeAnalysis(analysisModule); | ||
callStackBuildPm.stop(); | ||
|
||
// Benchmark the segment store iteration | ||
ISegmentStore<ISegment> segmentStore = analysisModule.getSegmentStore(); | ||
assertNotNull(segmentStore); | ||
callStackSegStorePm.start(); | ||
// Iterate through the whole segment store | ||
Iterator<ISegment> iterator = segmentStore.iterator(); | ||
while (iterator.hasNext()) { | ||
iterator.next(); | ||
} | ||
callStackSegStorePm.stop(); | ||
|
||
// Getting the callgraph will schedule the analysis and wait for its | ||
// completion | ||
callgraphBuildPm.start(); | ||
CallGraph callGraph = ((ICallGraphProvider) analysisModule).getCallGraph(); | ||
callgraphBuildPm.stop(); | ||
|
||
assertTrue(!callGraph.getElements().isEmpty()); | ||
} | ||
|
||
/** | ||
* Get the trace for this analysis. Every call to getTrace() should return a | ||
* fresh trace fully initialized. The caller is responsible to dispose the | ||
* trace when not required anymore | ||
* | ||
* @return A freshly initialized trace | ||
* @throws TmfTraceException | ||
* Exceptions thrown getting the trace | ||
*/ | ||
protected abstract TmfTrace getTrace() throws TmfTraceException; | ||
} |
Oops, something went wrong.