Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/DekkerTest.java
41155 views
1
/*
2
* Copyright (c) 2014, 2018, 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
24
package vm.mlvm.share;
25
26
import java.util.concurrent.BrokenBarrierException;
27
import java.util.concurrent.CyclicBarrier;
28
import nsk.share.Log.TraceLevel;
29
import vm.share.options.Option;
30
31
/**
32
* The test looks for late CPU stores, which is not visible for other CPU.
33
* <p>
34
* In absence of synchronization (such as memory barriers and so on), typical modern CPUs
35
* (Intel x86 32/64, SPARC in TSO mode) put stores into buffer instead of immediately writing them to memory.
36
*
37
* So the following program:
38
* <code>
39
* write A
40
* read B
41
* </code>
42
* can actually be transformed to and seen by other processors as:
43
* <code>
44
* read B
45
* write A
46
* </code>
47
* <p>
48
* DekkerTest runs two threads, A and B, which perform operations on a shared array of Actors concurrently.
49
* Reordering mentioned above is detected by the test and reported as failure
50
* (unless mayFail option is specified in the constructor or command-line option).
51
*
52
* <p>
53
* The tests should subclass Actor with test-specific data and code.
54
* The Actor subclass requirements:
55
*
56
* <ul>
57
* <li>the class should have two data fields:
58
* <code>
59
* A
60
* B
61
* </code>
62
* of the same type, which are able hold one of two values.
63
* Let's call these values TRUE and FALSE (these can be any two values, say 0 and 1).
64
*
65
* <li>* actorA() is called from thread A and should implement the following pseudo-code:
66
* <code>
67
* A = TRUE
68
* optional MEMBAR #StoreLoad
69
* return (B == TRUE)
70
* </code>
71
*
72
* <li>actorB() is called from thread B and should do the following:
73
* <code>
74
* {
75
* B = TRUE
76
* optional MEMBAR #StoreLoad
77
* return (A == TRUE)
78
* }
79
* </code>
80
*
81
* <li>reset() method should do the following:
82
* <code>
83
* {
84
* A = FALSE
85
* B = FALSE
86
* }
87
* </code>
88
*
89
* The use of memory barriers in actorX() methods is up to the implementor -- depending on the goal of testing.
90
*
91
*/
92
public class DekkerTest extends MlvmTest {
93
94
@Option(name = "actorClass", default_value = "", description = "Name of actor class (see test comments)")
95
private String actorClassNameOpt = "";
96
97
@Option(name = "mayFail", default_value = "false", description = "Don't report test failure (use it just a stress test)")
98
private boolean mayFailOpt;
99
100
@Option(name = "iterations", default_value = "1000000", description = "Number of iterations in each Actor thread (i.e., shared array size)")
101
private int iterationsOpt = 1000000;
102
103
/**
104
* Actor interface, which should be implemented for using with DekkerTest.
105
* The requirements for Actor implementation are outlined in {@link DekkerTest} class documentation.
106
*/
107
public interface Actor {
108
/**
109
* Sets fields A and B to false
110
*/
111
void reset();
112
113
/**
114
* Sets field A to true, and returns field B contents
115
* @return field B contents
116
* @throws Throwable in case of error
117
*/
118
boolean actorA() throws Throwable;
119
120
/**
121
* Sets field B to true, and returns field A contents
122
* @return field A contents
123
* @throws Throwable in case of error
124
*/
125
boolean actorB() throws Throwable;
126
}
127
128
private static final class ResultData {
129
public boolean a;
130
public boolean b;
131
132
public ResultData() {
133
}
134
135
public void reset() {
136
a = false;
137
b = false;
138
}
139
}
140
141
private static class RaceStatistics {
142
public int syncErrors;
143
public int runSideBySide;
144
public int A_outruns_B;
145
public int B_outruns_A;
146
147
public void reset() {
148
syncErrors = 0;
149
runSideBySide = 0;
150
A_outruns_B = 0;
151
B_outruns_A = 0;
152
}
153
}
154
155
private Class<? extends Actor> actorClass;
156
private final CyclicBarrier startBarrier = new CyclicBarrier(2); // We have two actors
157
private Actor[] testData;
158
private ResultData[] results;
159
private final RaceStatistics raceStatistics = new RaceStatistics();
160
161
public DekkerTest() {
162
}
163
164
/**
165
* Sets actor class.
166
* @param ac Actor class, which implements DekkerTest.Actor interface
167
*/
168
public void setActorClass(Class<? extends Actor> ac) {
169
actorClass = ac;
170
}
171
172
/**
173
* Sets mayFail option. When set to true, synchronization failure is not reported as test failure (DekkerTest is used as a stress test).
174
* @param mayFail if true, don't report sync failure as test failure, false otherwise
175
*/
176
public void setMayFailOpt(boolean mayFail) {
177
mayFailOpt = mayFail;
178
}
179
180
/**
181
* Initializes test data, parses command-line options and checks Actor class
182
*/
183
@Override
184
public void initializeTest() {
185
// Override values set by setActorClass() by command-line option, if any
186
try {
187
if (!actorClassNameOpt.isEmpty()) {
188
actorClass = Class.forName(actorClassNameOpt).asSubclass(Actor.class);
189
} else {
190
if (actorClass == null) {
191
throw new RuntimeException("Test error: the actor class should be specified via command-line options or in the constructor");
192
}
193
}
194
195
} catch (ClassNotFoundException e) {
196
throw new RuntimeException("Actor class '" + actorClassNameOpt + "' not found", e);
197
} catch (ClassCastException e) {
198
throw new RuntimeException("Test error: the actor class " + actorClass.getName() + " should implement " + Actor.class.getName() + " interface", e);
199
}
200
201
// Generate data
202
int iterations = iterationsOpt * getStressOptions().getIterationsFactor();
203
if (iterations <= 0) {
204
throw new RuntimeException("Invalid number of iterations specified in -iterations and -stressIterationsFactor options: " + iterations);
205
}
206
207
results = new ResultData[iterations];
208
for (int i = 0; i < results.length; ++i) {
209
results[i] = new ResultData();
210
}
211
212
testData = new Actor[results.length];
213
try {
214
for (int i = 0; i < testData.length; ++i) {
215
testData[i] = actorClass.newInstance();
216
}
217
} catch (ReflectiveOperationException e) {
218
throw new RuntimeException("Test error: can't instantiate class " + actorClass.getName(), e);
219
}
220
}
221
222
/**
223
* Resets the test data between test runs
224
*/
225
@Override
226
public void resetTest() {
227
for (Actor a : testData) {
228
a.reset();
229
}
230
for (ResultData d : results) {
231
d.reset();
232
}
233
}
234
235
private class RunnerA extends Thread {
236
@Override
237
public void run() {
238
try {
239
startBarrier.await();
240
for (int i = 0; i < results.length; ++i) {
241
results[i].a = testData[i].actorA();
242
}
243
} catch (Throwable t) {
244
markTestFailed("Exception in RunnerA", t);
245
}
246
}
247
}
248
249
private class RunnerB extends Thread {
250
@Override
251
public void run() {
252
try {
253
startBarrier.await();
254
for (int i = 0; i < results.length; ++i) {
255
results[i].b = testData[i].actorB();
256
}
257
} catch (Throwable t) {
258
markTestFailed("Exception in RunnerB", t);
259
}
260
}
261
}
262
263
@Override
264
public boolean run() throws Throwable {
265
RunnerA threadA = new RunnerA();
266
threadA.start();
267
268
RunnerB threadB = new RunnerB();
269
threadB.start();
270
271
threadA.join();
272
threadB.join();
273
274
if (isMarkedFailed())
275
return false;
276
277
analyzeResults();
278
printResults();
279
280
if (mayFailOpt) {
281
return true;
282
}
283
284
return (raceStatistics.syncErrors == 0);
285
}
286
287
private void analyzeResults() {
288
raceStatistics.reset();
289
290
for (int i = 0; i < results.length; ++i) {
291
boolean resultA = results[i].a;
292
boolean resultB = results[i].b;
293
294
if (resultA && resultB) {
295
296
++raceStatistics.runSideBySide;
297
298
} else if (resultA && !resultB) {
299
300
++raceStatistics.A_outruns_B;
301
302
} else if (!resultA && resultB) {
303
304
++raceStatistics.B_outruns_A;
305
306
} else if (!resultA && !resultB) {
307
308
++raceStatistics.syncErrors;
309
310
} else {
311
312
throw new RuntimeException("Should not reach here");
313
}
314
}
315
}
316
317
private void printResults() {
318
int logLevel = (raceStatistics.syncErrors != 0) ? TraceLevel.TRACE_IMPORTANT : TraceLevel.TRACE_NORMAL;
319
320
Env.getLog().trace(logLevel, "\n"
321
+ "Late stores (sync. errors): " + raceStatistics.syncErrors + "\n"
322
+ "B outruns A : " + raceStatistics.B_outruns_A + "\n"
323
+ "A outruns B : " + raceStatistics.A_outruns_B + "\n"
324
+ "A and B run side by side : " + raceStatistics.runSideBySide);
325
}
326
327
public static void main(String[] args) {
328
MlvmTest.launch(args);
329
}
330
}
331
332
333