Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/micro/org/openjdk/bench/java/lang/StackWalkBench.java
41161 views
1
/*
2
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
package org.openjdk.bench.java.lang;
24
25
import java.lang.StackWalker.StackFrame;
26
import java.util.concurrent.TimeUnit;
27
import org.openjdk.jmh.annotations.Benchmark;
28
import org.openjdk.jmh.annotations.BenchmarkMode;
29
import org.openjdk.jmh.annotations.Mode;
30
import org.openjdk.jmh.annotations.OutputTimeUnit;
31
import org.openjdk.jmh.annotations.Param;
32
import org.openjdk.jmh.annotations.Scope;
33
import org.openjdk.jmh.annotations.State;
34
import org.openjdk.jmh.infra.Blackhole;
35
36
/**
37
* Benchmarks for java.lang.StackWalker
38
*/
39
@State(value=Scope.Benchmark)
40
@BenchmarkMode(Mode.AverageTime)
41
@OutputTimeUnit(TimeUnit.NANOSECONDS)
42
public class StackWalkBench {
43
private static final StackWalker WALKER_DEFAULT = StackWalker.getInstance();
44
45
private static final StackWalker WALKER_CLASS =
46
StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
47
48
// TestStack will add this number of calls to the call stack
49
@Param({"4", "100", "1000"})
50
// For more thorough testing, consider:
51
// @Param({"4", "10", "100", "256", "1000"})
52
public int depth;
53
54
// Only used by swFilterCallerClass, to specify (roughly) how far back the
55
// call stack the target class will be found. Not needed by other
56
// benchmarks, so not a @Param by default.
57
// @Param({"4"})
58
public int mark = 4;
59
60
/** Build a call stack of a given size, then run trigger code in it.
61
* (Does not account for existing frames higher up in the JMH machinery).
62
*/
63
public static class TestStack {
64
final long fence;
65
long current;
66
final Runnable trigger;
67
68
public TestStack(long max, Runnable trigger) {
69
this.fence = max;
70
this.current = 0;
71
this.trigger = trigger;
72
}
73
74
public void start() {
75
one();
76
}
77
78
public void one() {
79
if (check()) {
80
two();
81
}
82
}
83
84
void two() {
85
if (check()) {
86
three();
87
}
88
}
89
90
private void three() {
91
if (check()) {
92
one();
93
}
94
}
95
96
boolean check() {
97
if (++current == fence) {
98
trigger.run();
99
return false;
100
} else {
101
return true;
102
}
103
}
104
}
105
106
/* Class to look for when testing filtering */
107
static class TestMarker {
108
public void call(MarkedTestStack test) {
109
test.marked();
110
}
111
}
112
113
/** Call stack to test filtering.
114
* TestMarker will make a call on the stack.
115
*/
116
static class MarkedTestStack extends TestStack {
117
long mark;
118
119
/**
120
* @param mark How far back the stack should the TestMarker be found?
121
*/
122
public MarkedTestStack(long max, long mark, Runnable trigger) {
123
super(max, trigger);
124
if (mark > max) {
125
throw new IllegalArgumentException("mark must be <= max");
126
}
127
this.mark = max - mark; // Count backwards from the completed call stack
128
}
129
@Override
130
public void start() {
131
if (mark == 0) {
132
mark();
133
} else {
134
super.one();
135
}
136
}
137
@Override
138
boolean check() {
139
if (++current == mark) {
140
mark();
141
return false;
142
} else if (current == fence) {
143
trigger.run();
144
return false;
145
} else {
146
return true;
147
}
148
}
149
void mark() {
150
new TestMarker().call(this);
151
}
152
public void marked() {
153
if (current < fence) {
154
if (check()) {
155
one();
156
}
157
} else {
158
trigger.run();
159
}
160
}
161
}
162
163
/**
164
* StackWalker.forEach() with default options
165
*/
166
@Benchmark
167
public void forEach_DefaultOpts(Blackhole bh) {
168
final Blackhole localBH = bh;
169
final boolean[] done = {false};
170
new TestStack(depth, new Runnable() {
171
public void run() {
172
WALKER_DEFAULT.forEach(localBH::consume);
173
done[0] = true;
174
}
175
}).start();
176
if (!done[0]) {
177
throw new RuntimeException();
178
}
179
}
180
181
/**
182
* Use Stackwalker.walk() to fetch class names
183
*/
184
@Benchmark
185
public void walk_ClassNames(Blackhole bh) {
186
final Blackhole localBH = bh;
187
final boolean[] done = {false};
188
new TestStack(depth, new Runnable() {
189
public void run() {
190
WALKER_DEFAULT.walk(s -> {
191
s.map(StackFrame::getClassName).forEach(localBH::consume);
192
return null;
193
});
194
done[0] = true;
195
}
196
}).start();
197
if (!done[0]) {
198
throw new RuntimeException();
199
}
200
}
201
202
/**
203
* Use Stackwalker.walk() to fetch method names
204
*/
205
@Benchmark
206
public void walk_MethodNames(Blackhole bh) {
207
final Blackhole localBH = bh;
208
final boolean[] done = {false};
209
new TestStack(depth, new Runnable() {
210
public void run() {
211
WALKER_DEFAULT.walk( s -> {
212
s.map(StackFrame::getMethodName).forEach(localBH::consume);
213
return null;
214
});
215
done[0] = true;
216
}
217
}).start();
218
if (!done[0]) {
219
throw new RuntimeException();
220
}
221
}
222
223
/**
224
* Use Stackwalker.walk() to fetch declaring class instances
225
*/
226
@Benchmark
227
public void walk_DeclaringClass(Blackhole bh) {
228
final Blackhole localBH = bh;
229
final boolean[] done = {false};
230
new TestStack(depth, new Runnable() {
231
public void run() {
232
WALKER_CLASS.walk(s -> {
233
s.map(StackFrame::getDeclaringClass).forEach(localBH::consume);
234
return null;
235
});
236
done[0] = true;
237
}
238
}).start();
239
if (!done[0]) {
240
throw new RuntimeException();
241
}
242
}
243
244
/**
245
* Use StackWalker.walk() to fetch StackTraceElements
246
*/
247
@Benchmark
248
public void walk_StackTraceElements(Blackhole bh) {
249
final Blackhole localBH = bh;
250
final boolean[] done = {false};
251
new TestStack(depth, new Runnable() {
252
public void run() {
253
WALKER_DEFAULT.walk(s -> {
254
s.map(StackFrame::toStackTraceElement).forEach(localBH::consume);
255
return null;
256
});
257
done[0] = true;
258
}
259
}).start();
260
if (!done[0]) {
261
throw new RuntimeException();
262
}
263
}
264
265
/**
266
* StackWalker.getCallerClass()
267
*/
268
@Benchmark
269
public void getCallerClass(Blackhole bh) {
270
final Blackhole localBH = bh;
271
final boolean[] done = {false};
272
new TestStack(depth, new Runnable() {
273
public void run() {
274
localBH.consume(WALKER_CLASS.getCallerClass());
275
done[0] = true;
276
}
277
}).start();
278
if (!done[0]) {
279
throw new RuntimeException();
280
}
281
}
282
283
/**
284
* Use StackWalker.walk() to filter the StackFrames, looking for the
285
* TestMarker class, which will be (approximately) 'mark' calls back up the
286
* call stack.
287
*/
288
@Benchmark
289
public void walk_filterCallerClass(Blackhole bh) {
290
final Blackhole localBH = bh;
291
final boolean[] done = {false};
292
293
new MarkedTestStack(depth, mark, new Runnable() {
294
public void run() {
295
// To be comparable with Reflection.getCallerClass(), return the Class object
296
WALKER_CLASS.walk(s -> {
297
localBH.consume(s.filter(f -> TestMarker.class.equals(f.getDeclaringClass())).findFirst().get().getDeclaringClass());
298
return null;
299
});
300
done[0] = true;
301
}
302
}).start();
303
304
if (!done[0]) {
305
throw new RuntimeException();
306
}
307
}
308
309
/**
310
* Use StackWalker.walk() to filter the StackFrames, looking for the
311
* TestMarker class, which will be (approximately) depth/2 calls back up the
312
* call stack.
313
*/
314
@Benchmark
315
public void walk_filterCallerClassHalfStack(Blackhole bh) {
316
final Blackhole localBH = bh;
317
final boolean[] done = {false};
318
319
new MarkedTestStack(depth, depth / 2, new Runnable() {
320
public void run() {
321
// To be comparable with Reflection.getCallerClass(), return the Class object
322
WALKER_CLASS.walk(s -> {
323
localBH.consume(s.filter((f) -> TestMarker.class.equals(f.getDeclaringClass())).findFirst().get().getDeclaringClass());
324
return null;
325
});
326
done[0] = true;
327
}
328
}).start();
329
330
if (!done[0]) {
331
throw new RuntimeException();
332
}
333
}
334
335
// TODO: add swConsumeFramesWithReflection
336
// TODO: add swFilterOutStreamClasses
337
338
// // This benchmark is for collecting performance counter data
339
// static PerfCounter streamTime = PerfCounter.newPerfCounter("jdk.stackwalk.testStreamsElapsedTime");
340
// static PerfCounter numStream = PerfCounter.newPerfCounter("jdk.stackwalk.numTestStreams");
341
// // @Benchmark
342
// public void swStkFrmsTimed(Blackhole bh) {
343
// final Blackhole localBH = bh;
344
// final boolean[] done = {false};
345
// new TestStack(depth, new Runnable() {
346
// public void run() {
347
// long t0 = System.nanoTime();
348
// WALKER_DEFAULT.forEach(localBH::consume);
349
// streamTime.addElapsedTimeFrom(t0);
350
// numStream.increment();
351
// done[0] = true;
352
// }
353
// }).start();
354
// if (!done[0]) {
355
// throw new RuntimeException();
356
// }
357
// }
358
}
359
360