-
Notifications
You must be signed in to change notification settings - Fork 10
/
CallStackAndGraphBenchmark.java
234 lines (207 loc) · 11.1 KB
/
CallStackAndGraphBenchmark.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
/*******************************************************************************
* 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.incubator.callstack.core.tests.perf.analysis;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.security.SecureRandom;
import org.eclipse.test.performance.Dimension;
import org.eclipse.test.performance.Performance;
import org.eclipse.test.performance.PerformanceMeter;
import org.eclipse.tracecompass.incubator.analysis.core.weighted.tree.AllGroupDescriptor;
import org.eclipse.tracecompass.incubator.analysis.core.weighted.tree.IWeightedTreeGroupDescriptor;
import org.eclipse.tracecompass.incubator.analysis.core.weighted.tree.WeightedTreeGroupBy;
import org.eclipse.tracecompass.incubator.callstack.core.callgraph.CallGraph;
import org.eclipse.tracecompass.incubator.callstack.core.callgraph.ICallGraphProvider;
import org.eclipse.tracecompass.incubator.callstack.core.instrumented.IFlameChartProvider;
import org.eclipse.tracecompass.incubator.callstack.core.instrumented.statesystem.InstrumentedCallStackAnalysis;
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 test ID for kernel analysis benchmarks
*/
public static final String TEST_ID = "org.eclipse.tracecompass.incubator#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().size() > 0);
}
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().size() > 0);
}
/**
* 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;
}