Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/Concurrent.java
41155 views
1
/*
2
* Copyright (c) 2010, 2020, 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 vm.gc.concurrent;
24
25
import java.lang.management.ManagementFactory;
26
import java.lang.management.MemoryMXBean;
27
import java.lang.management.MemoryUsage;
28
import java.util.concurrent.atomic.AtomicInteger;
29
import java.util.concurrent.locks.Lock;
30
import java.util.concurrent.locks.ReentrantLock;
31
import nsk.share.TestFailure;
32
import nsk.share.gc.GC;
33
import nsk.share.gc.Memory;
34
import nsk.share.gc.ThreadedGCTest;
35
import nsk.share.gc.gp.GarbageProducer;
36
import nsk.share.gc.gp.GarbageProducer1Aware;
37
import nsk.share.gc.gp.GarbageProducerAware;
38
import nsk.share.gc.gp.MemoryStrategy;
39
import nsk.share.gc.gp.MemoryStrategyAware;
40
import nsk.share.gc.tree.*;
41
import nsk.share.log.Log;
42
import nsk.share.test.ExecutionController;
43
import nsk.share.test.LocalRandom;
44
45
class Forest {
46
47
// the actual size of TreeNode in bytes in the memory calculated as occupied memory / count of nodes
48
static int nodeSize;
49
50
static long treeSize;
51
52
private static long allNodesCount;
53
54
/* log from test */
55
static Log log;
56
57
58
static int treeHeight;
59
60
static long actuallyMut = 0;
61
private static Forest instance = new Forest();
62
private Tree[] trees;
63
private Lock[] locks;
64
65
private int nodeGarbageSize;
66
67
private GarbageProducer gp;
68
/*
69
* Create array of trees occupyng given percent of heap
70
*/
71
static Forest createForest(long percent, int heightToSizeRatio, int nodeGarbageSize, GarbageProducer gp, Log _log) {
72
log = _log;
73
74
long size = Runtime.getRuntime().maxMemory() * percent / 100;
75
treeHeight = Memory.balancedTreeHeightFromMemory(size, (int) new TreeNode(nodeGarbageSize).getTotalSize());
76
int ntrees = 0;
77
while (treeHeight * heightToSizeRatio > ntrees) {
78
ntrees++;
79
treeHeight = Memory.balancedTreeHeightFromMemory(size / ntrees, (int) new TreeNode(nodeGarbageSize).getTotalSize());
80
}
81
82
log.debug("The expected forest paramteres: tree height = " + treeHeight + " number of trees = " + ntrees
83
+ " size = " + new TreeNode(nodeGarbageSize).getTotalSize());
84
Tree[] localTrees = new Tree[ntrees * 4];
85
Lock[] localLocks = new Lock[ntrees * 4];
86
for (int i = 0; i < ntrees * 4; i++) {
87
localTrees[i] = new Tree(Memory.makeBalancedTreeNode(treeHeight, nodeGarbageSize, gp));
88
localLocks[i] = new ReentrantLock();
89
90
int numOfAttempts = 0;
91
if (Concurrent.getPercentInfoByMBeans() > percent) {
92
log.debug("Attempt to System.gc() before control check. (" + numOfAttempts++ + ")");
93
System.gc();
94
if (Concurrent.getPercentInfoByMBeans() > percent) {
95
instance.trees = new Tree[i];
96
instance.locks = new Lock[i];
97
for (int j = 0; j < i; j++) {
98
instance.trees[j] = localTrees[j];
99
instance.locks[j] = localLocks[j];
100
}
101
allNodesCount = Memory.balancedTreeNodes(treeHeight) * instance.trees.length;
102
nodeSize = (int) (ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed() / allNodesCount);
103
treeSize = Memory.balancedTreeSize(treeHeight, nodeSize);
104
instance.where = new AtomicCycleInteger(instance.trees.length);
105
instance.nodeGarbageSize = nodeGarbageSize;
106
107
log.debug("The forest real paramteres: tree height = " + treeHeight + " number of trees = " + instance.trees.length
108
+ " number of nodes = " + allNodesCount);
109
log.debug("Approximate node size = " + nodeSize + " calc = " + instance.trees[0].getRoot().getSize());
110
return instance;
111
}
112
}
113
}
114
throw new TestFailure("Should not reach here. The correct exit point is inside cycle");
115
}
116
117
118
int treesCount() {
119
return trees.length;
120
}
121
122
long nodesCount() {
123
return allNodesCount;
124
}
125
126
127
128
// Confirms that all trees are balanced and have the correct height.
129
void checkTrees() {
130
for (int i = 0; i < trees.length; i++) {
131
locks[i].lock();
132
checkTree(trees[i]);
133
locks[i].unlock();
134
}
135
}
136
137
private static void checkTree(Tree tree) {
138
TreeNode root = tree.getRoot();
139
int h1 = root.getHeight();
140
int h2 = root.getShortestPath();
141
if ((h1 != treeHeight) || (h2 != treeHeight)) {
142
throw new TestFailure("The tree is not balanced expected " + treeHeight
143
+ " value = " + h1 + " shortedtPath = " + h2);
144
}
145
}
146
147
// Swap subtrees in 2 trees, the the path is used
148
// as sequence of 1-0 to select subtree (left-reight sequence)
149
static void swapSubtrees(Tree t1, Tree t2, int depth, int path) {
150
TreeNode tn1 = t1.getRoot();
151
TreeNode tn2 = t2.getRoot();
152
for (int i = 0; i < depth; i++) {
153
if ((path & 1) == 0) {
154
tn1 = tn1.getLeft();
155
tn2 = tn2.getLeft();
156
} else {
157
tn1 = tn1.getRight();
158
tn2 = tn2.getRight();
159
}
160
path >>= 1;
161
}
162
TreeNode tmp;
163
if ((path & 1) == 0) {
164
tmp = tn1.getLeft();
165
tn1.setLeft(tn2.getLeft());
166
tn2.setLeft(tmp);
167
} else {
168
tmp = tn1.getRight();
169
tn1.setRight(tn2.getRight());
170
tn2.setLeft(tmp);
171
}
172
}
173
174
175
// Interchanges two randomly selected subtrees (of same size and depth) several times
176
void swapSubtrees(long count) {
177
for (int i = 0; i < count; i++) {
178
int index1 = LocalRandom.nextInt(trees.length);
179
int index2 = LocalRandom.nextInt(trees.length);
180
int depth = LocalRandom.nextInt(treeHeight);
181
int path = LocalRandom.nextInt();
182
locks[index1].lock();
183
// Skip the round to avoid deadlocks
184
if (locks[index2].tryLock()) {
185
swapSubtrees(trees[index1], trees[index2], depth, path);
186
actuallyMut += 2;
187
locks[index2].unlock();
188
}
189
locks[index1].unlock();
190
191
}
192
193
}
194
195
196
static class AtomicCycleInteger extends AtomicInteger {
197
private int max;
198
public AtomicCycleInteger(int cycleLength) {
199
super();
200
this.max = cycleLength - 1;
201
}
202
public int cycleIncrementAndGet() {
203
for (;;) {
204
int current = get();
205
int next = (current == max ? 0 : current + 1);
206
if (compareAndSet(current, next)) {
207
return next;
208
}
209
}
210
}
211
}
212
213
// the index in tree array which should be chnaged during next regeneration
214
AtomicCycleInteger where = null;
215
216
// generate new full and partial trees in our forest
217
void regenerateTrees(long nodesCount) {
218
int full = (int) (nodesCount / Memory.balancedTreeNodes(treeHeight)) ;
219
int partial = (int) nodesCount % (Memory.balancedTreeNodes(treeHeight));
220
for (int i = 0; i < full; i++) {
221
int idx = where.cycleIncrementAndGet();
222
locks[idx].lock();
223
trees[idx] = new Tree(Memory.makeBalancedTreeNode(treeHeight, nodeGarbageSize));
224
locks[idx].unlock();
225
}
226
while (partial > 0) {
227
int h = Memory.balancedTreeHeightFromNodes(partial);
228
Tree newTree = new Tree(Memory.makeBalancedTreeNode(h, nodeGarbageSize));
229
int idx = where.cycleIncrementAndGet();
230
locks[idx].lock();
231
replaceTree(trees[idx], newTree);
232
locks[idx].unlock();
233
partial = partial - Memory.balancedTreeNodes(h);
234
}
235
}
236
237
238
// Given a balanced tree full and a smaller balanced tree partial,
239
// replaces an appropriate subtree of full by partial, taking care
240
// to preserve the shape of the full tree.
241
private static void replaceTree(Tree full, Tree partial) {
242
boolean dir = (partial.getHeight() % 2) == 0;
243
actuallyMut++;
244
replaceTreeWork(full.getRoot(), partial.getRoot(), dir);
245
}
246
247
// Called only by replaceTree (below) and by itself.
248
static void replaceTreeWork(TreeNode full, TreeNode partial,
249
boolean dir) {
250
boolean canGoLeft = full.getLeft() != null && full.getLeft().getHeight() > partial.getHeight();
251
boolean canGoRight = full.getRight() != null && full.getRight().getHeight() > partial.getHeight();
252
if (canGoLeft && canGoRight) {
253
if (dir) {
254
replaceTreeWork(full.getLeft(), partial, !dir);
255
} else {
256
replaceTreeWork(full.getRight(), partial, !dir);
257
}
258
} else if (!canGoLeft && !canGoRight) {
259
if (dir) {
260
full.setLeft(partial);
261
} else {
262
full.setRight(partial);
263
}
264
} else if (!canGoLeft) {
265
full.setLeft(partial);
266
} else {
267
full.setRight(partial);
268
}
269
}
270
271
272
273
}
274
public class Concurrent extends ThreadedGCTest implements GarbageProducerAware, GarbageProducer1Aware, MemoryStrategyAware {
275
276
// Heap as tree
277
Forest forest;
278
279
// GP for old gargbage production
280
GarbageProducer gpOld;
281
282
// GP for young gargbage production
283
GarbageProducer gpYoung;
284
285
MemoryStrategy ms;
286
287
private void printStatistics() {
288
log.debug("Actual mutations = " + forest.actuallyMut);
289
}
290
291
private class Worker implements Runnable {
292
293
private ExecutionController stresser;
294
295
@Override
296
public void run() {
297
if (stresser == null) {
298
stresser = getExecutionController();
299
}
300
while (stresser.continueExecution()) {
301
doStep();
302
}
303
}
304
}
305
306
@Override
307
public Runnable createRunnable(int i) {
308
return new Worker();
309
}
310
311
public static int getPercentInfoByMBeans() {
312
MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
313
return (int) (100 * mbean.getHeapMemoryUsage().getUsed() / mbean.getHeapMemoryUsage().getMax());
314
}
315
316
private void printMem(long used, long max, String source) {
317
log.debug("The Memory after allocation (" + source + "): ");
318
log.debug("Used = " + used + " Max = " + max + " Percent = " + (100 * used / max));
319
}
320
321
// Command-line parameters.
322
// young garbage in percent and absolute
323
private static int youngPercent = 0;
324
long youngGarbageSize;
325
// mutation rate (parcent and absolute trees)
326
private static int ptrMutRate = 50;
327
long mutateTrees;
328
// percent of heap to occupy by forest (long live garbage)
329
private static int livePercent = 60;
330
// the minimum of which should be available for forest
331
// test fails if it is not possible to use 60% of heap
332
private static final int MIN_AVAILABLE_MEM = 60;
333
// percent of forest to reallocate each step
334
private static int reallocatePercent = 30;
335
long reallocateSizeInNodes;
336
// sleep time in ms
337
private static int sleepTime = 100;
338
339
private void init(int longLivePercent) {
340
int numberOfThreads = runParams.getNumberOfThreads();
341
forest = Forest.createForest(longLivePercent, numberOfThreads,
342
(int) Math.sqrt(ms.getSize(Runtime.getRuntime().maxMemory())), gpOld, log);
343
344
youngGarbageSize = Runtime.getRuntime().maxMemory() * youngPercent / 100 / numberOfThreads;
345
reallocateSizeInNodes = forest.nodesCount() * reallocatePercent / 100 / numberOfThreads;
346
mutateTrees = forest.treesCount() * ptrMutRate / 100 / numberOfThreads / 2;
347
348
log.debug("Young Gen = " + youngGarbageSize);
349
log.debug("Forest contains " + forest.treesCount() + " trees and " + forest.nodesCount() + " nodes.");
350
log.debug("Count of nodes to reallocate = " + reallocateSizeInNodes);
351
log.debug("Count of tree pairs to exchange nodes = " + mutateTrees);
352
log.debug("Sleep time = " + sleepTime);
353
354
// print some info
355
MemoryUsage mbean = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
356
printMem(mbean.getUsed(), mbean.getMax(), "Beans");
357
printMem(Runtime.getRuntime().maxMemory() - Runtime.getRuntime().freeMemory(),
358
Runtime.getRuntime().maxMemory(), "System");
359
}
360
361
@Override
362
public void run() {
363
try {
364
init(livePercent);
365
} catch (OutOfMemoryError oome) {
366
if (livePercent > MIN_AVAILABLE_MEM) {
367
log.debug("Unable to use " + livePercent + " use only " + MIN_AVAILABLE_MEM);
368
init(MIN_AVAILABLE_MEM);
369
}
370
}
371
super.run();
372
printStatistics();
373
}
374
375
376
377
private void doStep() {
378
// allocate some young garbage
379
if (youngGarbageSize != 0) {
380
gpYoung.create(youngGarbageSize);
381
}
382
383
// allocate some long-live garbage (attached to our trees)
384
forest.regenerateTrees(reallocateSizeInNodes);
385
386
// mutate pointers
387
forest.swapSubtrees(mutateTrees);
388
389
// sleep to give GC time for some concurrent actions
390
try {
391
Thread.sleep(sleepTime);
392
} catch (InterruptedException ie) {
393
}
394
395
// verify trees, also read all pointers
396
forest.checkTrees();
397
}
398
399
public static void main(String[] args) {
400
init(args);
401
GC.runTest(new Concurrent(), args);
402
}
403
404
public static void init(String[] args) {
405
for (int i = 0; i < args.length; ++i) {
406
if (args[i].equals("-lp")) {
407
// percent of long lived objects
408
livePercent = Integer.parseInt(args[++i]);
409
} else if (args[i].equals("-rp")) {
410
// percent of trees to reallocate
411
reallocatePercent = Integer.parseInt(args[++i]);
412
} else if (args[i].equals("-yp")) {
413
// percent of young objects
414
youngPercent = Integer.parseInt(args[++i]);
415
} else if (args[i].equals("-mr")) {
416
// percent of trees to exchange (mutate)
417
ptrMutRate = Integer.parseInt(args[++i]);
418
} else if (args[i].equals("-st")) {
419
// sleep time in ms
420
sleepTime = Integer.parseInt(args[++i]);
421
}
422
}
423
}
424
425
@Override
426
public void setGarbageProducer(GarbageProducer gp) {
427
this.gpOld = gp;
428
}
429
430
431
@Override
432
public void setGarbageProducer1(GarbageProducer gpYoung) {
433
this.gpYoung = gpYoung;
434
}
435
436
@Override
437
public void setMemoryStrategy(MemoryStrategy ms) {
438
this.ms = ms;
439
}
440
}
441
442