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 /*
24  * This test stress RememberetSet procerssing in the G1 by creation of references
25  * between different 1MB blocks.
26  * Test is specific for G1, for other GCs it should just pass.
27  */
28 
29 
30 /*
31  * @test
32  * @modules java.base/jdk.internal.misc:+open java.base/jdk.internal.vm.annotation:+open java.base/sun.reflect.annotation:+open
33  * @key stress
34  *
35  * @summary converted from VM Testbase gc/gctests/RememberedSet.
36  * VM Testbase keywords: [gc, stress, stressopt, feature_g1, nonconcurrent]
37  *
38  * @library /vmTestbase
39  *          /test/lib
40  * @run main/othervm -XX:-UseGCOverheadLimit gc.gctests.RememberedSet.RememberedSet
41  */
42 
43 package gc.gctests.RememberedSet;
44 
45 import java.lang.reflect.Field;
46 import java.util.ArrayList;
47 import java.util.List;
48 import nsk.share.gc.GC;
49 import nsk.share.gc.MemoryObject;
50 import nsk.share.gc.ThreadedGCTest;
51 import nsk.share.test.ExecutionController;
52 import jdk.internal.misc.Unsafe;
53 
54 public class RememberedSet extends ThreadedGCTest {
55 
56     static class PointerUtils {
57         private static Unsafe unsafe;
58         private static long fieldOffset;
59         private static PointerUtils instance = new PointerUtils();
60         private static boolean compressedRef = false;
61 
62         static {
63             try {
64                 unsafe = Unsafe.getUnsafe();
65                 fieldOffset = unsafe.objectFieldOffset(PointerUtils.class.getDeclaredField("obj"));
66                 long fieldOffset0 = unsafe.objectFieldOffset(PointerUtils.class.getDeclaredField("obj0"));
67                 int oopSize = (int)Math.abs(fieldOffset - fieldOffset0);
68 
69                 if (oopSize != unsafe.addressSize()) {
70                     System.out.println("Compressed oops detected");
71                     compressedRef = true;
72                 }
73             } catch (Exception ex) {
74                 throw new RuntimeException(ex);
75             }
76         }
77 
78         private Object obj;
79         private Object obj0;
80 
toAddress(Object o)81         public synchronized static long toAddress(Object o) {
82             long address;
83             instance.obj = o;
84 
85             if (compressedRef || unsafe.addressSize() == 4) {
86                 address = unsafe.getInt(instance, fieldOffset);
87             }
88             else {
89                 address = unsafe.getLong(instance, fieldOffset);
90             }
91 
92             return address;
93         }
94 
95     }
96     private ExecutionController stresser;
97 
98     @Override
createRunnable(int i)99     protected Runnable createRunnable(int i) {
100         return new Worker();
101     }
102 
103     class Worker implements Runnable {
104 
105         static final long BLOCK_SIZE = 1024 * 1024;
106 
107 
108         // this method tries to allocate a new MemoryObject
109         // which is in another 1MB block
getOutOfTheBlockObject(int size, Object obj)110         MemoryObject getOutOfTheBlockObject(int size, Object obj) {
111             long address = PointerUtils.toAddress(obj);
112             MemoryObject ref = new MemoryObject(size);
113             int attempt = (int) (BLOCK_SIZE / size);
114             while (attempt != 0 && Math.abs(address - PointerUtils.toAddress(ref)) < BLOCK_SIZE) {
115                 ref = new MemoryObject(size);
116                 attempt--;
117             }
118             return ref;
119         }
120 
121         @Override
run()122         public void run() {
123 
124             int size = (int) Math.sqrt(BLOCK_SIZE);
125             int refsCount = (int) (runParams.getTestMemory() / BLOCK_SIZE);
126             int count = (int) (runParams.getTestMemory() / runParams.getNumberOfThreads() / (refsCount * size));
127             // Each cycle 10% of references and 10% of arrays are reallocated
128             int step = 10;
129 
130             List<List<MemoryObject>> objs = new ArrayList<List<MemoryObject>>(count);
131             for (int i = 0; i < count; i++) {
132                 List<MemoryObject> obj = new ArrayList<MemoryObject>();
133                 objs.add(obj);
134                 for (int j = 0; j < refsCount; j++) {
135                     obj.add(getOutOfTheBlockObject(size, obj));
136                 }
137             }
138             if (stresser == null) {
139                 stresser = getExecutionController();
140             }
141             int shift = 0;
142             while (stresser.continueExecution()) {
143                 for (int j = shift; j < refsCount; j += step) {
144                     for (int i = 0; i < count; i ++) {
145                         // update each 10th reference to allow GC previous one
146                         List<MemoryObject> obj = objs.get(i);
147                         obj.set(j, getOutOfTheBlockObject(size, obj));
148                     }
149                 }
150                 for (int i = step - shift; i < count; i += step) {
151                     // update each 10th array of references
152                     // to allocate it in the another 1MB block (as new young object)
153                     List<MemoryObject> obj = new ArrayList<MemoryObject>();
154                     objs.set(i, obj);
155                     for (int j = 0; j < refsCount; j++) {
156                         obj.add(getOutOfTheBlockObject(size, obj));
157                     }
158                 }
159                 // shift is changed from 0 to step - 1
160                 log.debug("shift = " + shift);
161                 shift = (shift + 1) % step;
162             }
163         }
164     }
165 
main(String[] args)166     public static void main(String[] args) {
167         GC.runTest(new RememberedSet(), args);
168     }
169 }
170