1 /*
  2  * Copyright (c) 2007, 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 
 25 /*
 26  * @test
 27  * @key stress randomness
 28  *
 29  * @summary converted from VM testbase nsk/stress/jni/gclocker/gcl001.
 30  * VM testbase keywords: [stress, quick, feature_283, nonconcurrent]
 31  * VM testbase readme:
 32  * DESCRIPTION
 33  *     Check compatibility of GC Locker improvements with JNI CS
 34  * Two types of concurrent threads are present:
 35  * A) Create N 'JNI CS' threads. Each of them will:
 36  *    1. Create primitive array and string with random data
 37  *    2. Pass it to native method
 38  *    3. Sort/Hash data in JNI CS mixing string and array critical sections
 39  *    4. Return from native
 40  *    5. Check data to be processed correctly
 41  * B) Create M ' Garbage producer/memory allocation' threads. Each of them will:
 42  *    1. Allocate memory blocks and make them garbage.
 43  *    2. Check for OOM errors.
 44  *
 45  * @library /vmTestbase
 46  *          /test/lib
 47  * @run main/othervm/native/timeout=480
 48  *      -XX:-UseGCOverheadLimit
 49  *      nsk.stress.jni.gclocker.gcl001
 50  *      -stressThreadsFactor 8
 51  */
 52 
 53 package nsk.stress.jni.gclocker;
 54 
 55 import nsk.share.gc.DefaultProducer;
 56 import nsk.share.gc.GC;
 57 import nsk.share.gc.ThreadedGCTest;
 58 import nsk.share.gc.gp.array.BooleanArrayProducer;
 59 import nsk.share.gc.gp.array.ByteArrayProducer;
 60 import nsk.share.gc.gp.array.CharArrayProducer;
 61 import nsk.share.gc.gp.array.DoubleArrayProducer;
 62 import nsk.share.gc.gp.array.FloatArrayProducer;
 63 import nsk.share.gc.gp.array.IntArrayProducer;
 64 import nsk.share.gc.gp.array.LongArrayProducer;
 65 import nsk.share.gc.gp.array.ShortArrayProducer;
 66 import nsk.share.test.ExecutionController;
 67 import nsk.share.test.LocalRandom;
 68 
 69 public class gcl001 extends ThreadedGCTest {
 70 
 71     static {
 72         System.loadLibrary("gcl001");
 73     }
 74 
 75     int maxBlockSize;
 76 
 77     public static void main(String[] args) {
 78         GC.runTest(new gcl001(), args);
 79     }
 80 
 81     @Override
 82     public void run() {
 83         // each thread have only one block at the time
 84         // so we should occupy less then 60% of heap with live objects
 85         long maxSize = runParams.getTestMemory() / runParams.getNumberOfThreads();
 86         if (maxSize > Integer.MAX_VALUE - 1) {
 87             maxSize = Integer.MAX_VALUE - 1;
 88         }
 89         maxBlockSize = (int) maxSize;
 90         log.info("Maximium block size = " + maxBlockSize);
 91         super.run();
 92     }
 93 
 94     @Override
 95     protected Runnable createRunnable(int i) {
 96         if (i < runParams.getNumberOfThreads() / 2) {
 97             return CreateJNIWorker(i, maxBlockSize);
 98         } else {
 99             return new GarbageProducer(maxBlockSize);
100         }
101     }
102 
103     public Runnable CreateJNIWorker(int number, int size) {
104         JNIAbstractWorker worker = null;
105         switch (number % 8) {
106             case 0:
107                 worker = new JNIBooleanWorker(size);
108                 break;
109             case 1:
110                 worker = new JNIByteWorker(size);
111                 break;
112             case 2:
113                 worker = new JNICharWorker(size);
114                 break;
115             case 3:
116                 worker = new JNIShortWorker(size);
117                 break;
118             case 4:
119                 worker = new JNIIntWorker(size);
120                 break;
121             case 5:
122                 worker = new JNILongWorker(size);
123                 break;
124             case 6:
125                 worker = new JNIFloatWorker(size);
126                 break;
127             case 7:
128                 worker = new JNIDoubleWorker(size);
129                 break;
130         }
131         return worker;
132     }
133 
134     int random(int maxSize) {
135         int res = LocalRandom.nextInt(maxSize);
136         return res > 128 ? res : 128;
137     }
138 
139     public static Object tmp;
140 
141     class GarbageProducer implements Runnable {
142 
143         private int maxSize;
144         ExecutionController stresser;
145         DefaultProducer gp;
146 
147         GarbageProducer(int size) {
148             this.maxSize = size;
149             gp = new DefaultProducer();
150         }
151 
152         public void run() {
153             if (stresser == null) {
154                 stresser = getExecutionController();
155             }
156 
157             while (stresser.continueExecution()) {
158                 try {
159                     tmp = gp.create(random(maxSize));
160                 } catch (OutOfMemoryError oome) {
161                     // Do nothing.
162                 }
163             }
164         }
165     }
166 
167     abstract class JNIAbstractWorker extends JNIWorker implements Runnable {
168 
169         ExecutionController stresser;
170         private int maxSize;
171 
172         public JNIAbstractWorker(int maxSize) {
173             this.maxSize = maxSize;
174         }
175 
176         public void check(boolean condition, String message) {
177             if (!condition) {
178                 throw new Error(message);
179             }
180         }
181 
182         abstract void doit(int size);
183 
184         public void run() {
185             // create array with random elements
186             // store min and max element for further check
187             // create new string
188             // call JNI methods
189             // check min/max as sort result
190             // check string hash
191 
192             if (stresser == null) {
193                 stresser = getExecutionController();
194             }
195             while (stresser.continueExecution()) {
196                 // let make at least several values for long/float
197                 try {
198                     doit(random(maxSize));
199                 } catch (OutOfMemoryError oome) {
200                     // Do nothing.
201                 }
202             }
203         }
204     }
205 
206     // BYTE
207     class JNIBooleanWorker extends JNIAbstractWorker {
208 
209         BooleanArrayProducer gp = new BooleanArrayProducer();
210 
211         public JNIBooleanWorker(int size) {
212             super(size);
213         }
214 
215         void doit(int size) {
216 
217             boolean[] array = gp.create(size);
218             // just to be sure that we have true & false
219             array[0] = true;
220             array[array.length - 1] = false;
221             String str = "unsupported";
222             int nativeHash = NativeCall(array, str);
223             int javaHash = 0;
224             for (int i = 0; i < str.length(); ++i) {
225                 javaHash += (int) str.charAt(i);
226             }
227             javaHash += javaHash;
228             check(array[0] == false && array[array.length - 1] == true
229                     && javaHash == nativeHash, "Data validation failure");
230 
231         }
232     }
233 
234     class JNIByteWorker extends JNIAbstractWorker {
235 
236         ByteArrayProducer gp = new ByteArrayProducer();
237 
238         public JNIByteWorker(int size) {
239             super(size);
240         }
241 
242         void doit(int size) {
243 
244             byte[] array = gp.create(size);
245             byte min = Byte.MAX_VALUE, max = Byte.MIN_VALUE;
246             for (int i = 0; i < array.length; ++i) {
247                 if (array[i] > max) {
248                     max = array[i];
249                 }
250 
251                 if (array[i] < min) {
252                     min = array[i];
253                 }
254             }
255             String str = "Min: " + min + " Max: " + max;
256             int nativeHash = NativeCall(array, str);
257             int javaHash = 0;
258             for (int i = 0; i < str.length(); ++i) {
259                 javaHash += (int) str.charAt(i);
260             }
261             javaHash += javaHash;
262             check(array[0] == min && array[array.length - 1] == max
263                     && javaHash == nativeHash, "Data validation failure");
264 
265         }
266     }
267 
268     // CHAR
269     class JNICharWorker extends JNIAbstractWorker {
270 
271         CharArrayProducer gp = new CharArrayProducer();
272 
273         public JNICharWorker(int size) {
274             super(size);
275         }
276 
277         void doit(int size) {
278             char[] array = gp.create(size);
279             char min = 0xffff, max = 0;
280             for (int i = 0; i < array.length; ++i) {
281                 array[i] = (char) LocalRandom.nextInt();
282                 if (array[i] > max) {
283                     max = array[i];
284                 }
285 
286                 if (array[i] < min) {
287                     min = array[i];
288                 }
289             }
290             String str = "Min: " + min + " Max: " + max;
291             int nativeHash = NativeCall(array, str);
292             int javaHash = 0;
293             for (int i = 0; i < str.length(); ++i) {
294                 javaHash += (int) str.charAt(i);
295             }
296             javaHash += javaHash;
297             check(array[0] == min && array[array.length - 1] == max
298                     && javaHash == nativeHash, "Data validation failure");
299 
300         }
301     }
302 
303     // SHORT
304     class JNIShortWorker extends JNIAbstractWorker {
305 
306         ShortArrayProducer gp = new ShortArrayProducer();
307 
308         public JNIShortWorker(int size) {
309             super(size);
310         }
311 
312         void doit(int size) {
313 
314             short[] array = gp.create(size);
315             short min = Short.MAX_VALUE, max = Short.MIN_VALUE;
316             for (int i = 0; i < array.length; ++i) {
317                 if (array[i] > max) {
318                     max = array[i];
319                 }
320 
321                 if (array[i] < min) {
322                     min = array[i];
323                 }
324             }
325             String str = "Min: " + min + " Max: " + max;
326             int nativeHash = NativeCall(array, str);
327             int javaHash = 0;
328             for (int i = 0; i < str.length(); ++i) {
329                 javaHash += (int) str.charAt(i);
330             }
331             javaHash += javaHash;
332             check(array[0] == min && array[array.length - 1] == max
333                     && javaHash == nativeHash, "Data validation failure");
334         }
335     }
336 
337     // INT
338     class JNIIntWorker extends JNIAbstractWorker {
339 
340         IntArrayProducer gp = new IntArrayProducer();
341 
342         public JNIIntWorker(int size) {
343             super(size);
344         }
345 
346         void doit(int size) {
347             int[] array = gp.create(size);
348             int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
349             for (int i = 0; i < array.length; ++i) {
350                 if (array[i] > max) {
351                     max = array[i];
352                 }
353 
354                 if (array[i] < min) {
355                     min = array[i];
356                 }
357             }
358             String str = "Min: " + min + " Max: " + max;
359             int nativeHash = NativeCall(array, str);
360             int javaHash = 0;
361             for (int i = 0; i < str.length(); ++i) {
362                 javaHash += (int) str.charAt(i);
363             }
364             javaHash += javaHash;
365             check(array[0] == min && array[array.length - 1] == max
366                     && javaHash == nativeHash, "Data validation failure");
367 
368         }
369     }
370 
371     // LONG
372     class JNILongWorker extends JNIAbstractWorker {
373 
374         LongArrayProducer gp = new LongArrayProducer();
375 
376         public JNILongWorker(int size) {
377             super(size);
378         }
379 
380         void doit(int size) {
381 
382             long[] array = gp.create(size);
383             long min = Long.MAX_VALUE, max = Long.MIN_VALUE;
384             for (int i = 0; i < array.length; ++i) {
385                 if (array[i] > max) {
386                     max = array[i];
387                 }
388 
389                 if (array[i] < min) {
390                     min = array[i];
391                 }
392             }
393             String str = "Min: " + min + " Max: " + max;
394             int nativeHash = NativeCall(array, str);
395             int javaHash = 0;
396             for (int i = 0; i < str.length(); ++i) {
397                 javaHash += (int) str.charAt(i);
398             }
399             javaHash += javaHash;
400             check(array[0] == min && array[array.length - 1] == max
401                     && javaHash == nativeHash, "Data validation failure");
402 
403         }
404     }
405 
406     // FLOAT
407     class JNIFloatWorker extends JNIAbstractWorker {
408 
409         FloatArrayProducer gp = new FloatArrayProducer();
410 
411         public JNIFloatWorker(int size) {
412             super(size);
413         }
414 
415         void doit(int size) {
416 
417             float[] array = gp.create(size);
418             float min = Float.MAX_VALUE, max = Float.MIN_VALUE;
419             for (int i = 0; i < array.length; ++i) {
420                 if (array[i] > max) {
421                     max = array[i];
422                 }
423 
424                 if (array[i] < min) {
425                     min = array[i];
426                 }
427             }
428             String str = "Min: " + min + " Max: " + max;
429             int nativeHash = NativeCall(array, str);
430             int javaHash = 0;
431             for (int i = 0; i < str.length(); ++i) {
432                 javaHash += (int) str.charAt(i);
433             }
434             javaHash += javaHash;
435             check(array[0] == min && array[array.length - 1] == max
436                     && javaHash == nativeHash, "Data validation failure");
437         }
438     }
439 
440     // DOUBLE
441     class JNIDoubleWorker extends JNIAbstractWorker {
442 
443         DoubleArrayProducer gp = new DoubleArrayProducer();
444 
445         public JNIDoubleWorker(int size) {
446             super(size);
447         }
448 
449         void doit(int size) {
450 
451             double[] array = gp.create(size);
452             double min = Double.MAX_VALUE, max = Double.MIN_VALUE;
453             for (int i = 0; i < array.length; ++i) {
454                 if (array[i] > max) {
455                     max = array[i];
456                 }
457 
458                 if (array[i] < min) {
459                     min = array[i];
460                 }
461             }
462             String str = "Min: " + min + " Max: " + max;
463             int nativeHash = NativeCall(array, str);
464             int javaHash = 0;
465             for (int i = 0; i < str.length(); ++i) {
466                 javaHash += (int) str.charAt(i);
467             }
468             javaHash += javaHash;
469             check(array[0] == min && array[array.length - 1] == max
470                     && javaHash == nativeHash, "Data validation failure");
471         }
472     }
473 }
474 
475 class JNIWorker {
476 
477     protected native int NativeCall(boolean[] array, String str);
478 
479     protected native int NativeCall(byte[] array, String str);
480 
481     protected native int NativeCall(char[] array, String str);
482 
483     protected native int NativeCall(short[] array, String str);
484 
485     protected native int NativeCall(int[] array, String str);
486 
487     protected native int NativeCall(long[] array, String str);
488 
489     protected native int NativeCall(float[] array, String str);
490 
491     protected native int NativeCall(double[] array, String str);
492 }