/* * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test * @key stress * * @summary converted from VM testbase nsk/stress/jni/gclocker/gcl001. * VM testbase keywords: [stress, quick, feature_283, nonconcurrent, exclude] * VM testbase comments: 8208207 * VM testbase readme: * DESCRIPTION * Check compatibility of GC Locker improvements with JNI CS * Two types of concurrent threads are present: * A) Create N 'JNI CS' threads. Each of them will: * 1. Create primitive array and string with random data * 2. Pass it to native method * 3. Sort/Hash data in JNI CS mixing string and array critical sections * 4. Check isCopy == false * 5. Return from native * 6. Check data to be processed correctly * B) Create M ' Garbage producer/memory allocation' threads. Each of them will: * 1. Allocate memory blocks and make them garbage. * 2. Check for OOM errors. * * @library /vmTestbase * /test/lib * @run driver jdk.test.lib.FileInstaller . . * @ignore 8208207 * @run main/othervm/native/timeout=480 * -XX:-UseGCOverheadLimit * nsk.stress.jni.gclocker.gcl001 * -stressThreadsFactor 8 */ package nsk.stress.jni.gclocker; import nsk.share.gc.GC; import nsk.share.gc.ThreadedGCTest; import nsk.share.gc.gp.array.BooleanArrayProducer; import nsk.share.gc.gp.array.ByteArrayProducer; import nsk.share.gc.gp.array.CharArrayProducer; import nsk.share.gc.gp.array.DoubleArrayProducer; import nsk.share.gc.gp.array.FloatArrayProducer; import nsk.share.gc.gp.array.IntArrayProducer; import nsk.share.gc.gp.array.LongArrayProducer; import nsk.share.gc.gp.array.ShortArrayProducer; import nsk.share.test.ExecutionController; import nsk.share.test.LocalRandom; import java.util.Random; public class gcl001 extends ThreadedGCTest { static { System.loadLibrary("gcl001"); } int maxBlockSize; public static void main(String[] args) { GC.runTest(new gcl001(), args); } @Override public void run() { // each thread have only one block at the time // so we should occupy less then 60% of heap with live objects long maxSize = runParams.getTestMemory() / runParams.getNumberOfThreads(); if (maxSize > Integer.MAX_VALUE - 1) { maxSize = Integer.MAX_VALUE - 1; } maxBlockSize = (int) maxSize; log.info("Maximium block size = " + maxBlockSize); super.run(); } @Override protected Runnable createRunnable(int i) { if (i < runParams.getNumberOfThreads() / 2) { return CreateJNIWorker(i, maxBlockSize); } else { return new GarbageProducer(maxBlockSize); } } public Runnable CreateJNIWorker(int number, int size) { JNIAbstractWorker worker = null; switch (number % 8) { case 0: worker = new JNIBooleanWorker(size); break; case 1: worker = new JNIByteWorker(size); break; case 2: worker = new JNICharWorker(size); break; case 3: worker = new JNIShortWorker(size); break; case 4: worker = new JNIIntWorker(size); break; case 5: worker = new JNILongWorker(size); break; case 6: worker = new JNIFloatWorker(size); break; case 7: worker = new JNIDoubleWorker(size); break; } return worker; } int random(int maxSize) { int res = LocalRandom.nextInt(maxSize); return res > 128 ? res : 128; } public static Object tmp; class GarbageProducer implements Runnable { private int maxSize; ExecutionController stresser; ByteArrayProducer bp; GarbageProducer(int size) { this.maxSize = size; bp = new ByteArrayProducer(); } public void run() { if (stresser == null) { stresser = getExecutionController(); } while (stresser.continueExecution()) { try { byte[] arr = bp.create(random(maxSize)); tmp = arr; } catch (OutOfMemoryError oome) { // Do nothing. } } } } abstract class JNIAbstractWorker extends JNIWorker implements Runnable { ExecutionController stresser; private int maxSize; public JNIAbstractWorker(int maxSize) { this.maxSize = maxSize; } public void check(boolean condition, String message) { if (!condition) { throw new Error(message); } } abstract void doit(int size); public void run() { // create array with random elements // store min and max element for further check // create new string // call JNI methods // check min/max as sort result // check string hash if (stresser == null) { stresser = getExecutionController(); } while (stresser.continueExecution()) { // let make at least several values for long/float try { doit(random(maxSize)); } catch (OutOfMemoryError oome) { // Do nothing. } } } } // BYTE class JNIBooleanWorker extends JNIAbstractWorker { BooleanArrayProducer gp = new BooleanArrayProducer(); public JNIBooleanWorker(int size) { super(size); } void doit(int size) { boolean[] array = gp.create(size); // just to be sure that we have true & false array[0] = true; array[array.length - 1] = false; String str = "unsupported"; int nativeHash = NativeCall(array, str); int javaHash = 0; for (int i = 0; i < str.length(); ++i) { javaHash += (int) str.charAt(i); } check(array[0] == false && array[array.length - 1] == true && javaHash == nativeHash, "Data validation failure"); } } class JNIByteWorker extends JNIAbstractWorker { ByteArrayProducer gp = new ByteArrayProducer(); public JNIByteWorker(int size) { super(size); } void doit(int size) { byte[] array = gp.create(size); byte min = Byte.MAX_VALUE, max = Byte.MIN_VALUE; for (int i = 0; i < array.length; ++i) { if (array[i] > max) { max = array[i]; } if (array[i] < min) { min = array[i]; } } String str = "Min: " + min + " Max: " + max; int nativeHash = NativeCall(array, str); int javaHash = 0; for (int i = 0; i < str.length(); ++i) { javaHash += (int) str.charAt(i); } check(array[0] == min && array[array.length - 1] == max && javaHash == nativeHash, "Data validation failure"); } } // CHAR class JNICharWorker extends JNIAbstractWorker { CharArrayProducer gp = new CharArrayProducer(); public JNICharWorker(int size) { super(size); } void doit(int size) { char[] array = gp.create(size); Random rand = new Random(); char min = 0xffff, max = 0; for (int i = 0; i < array.length; ++i) { array[i] = (char) rand.nextInt(); if (array[i] > max) { max = array[i]; } if (array[i] < min) { min = array[i]; } } String str = "Min: " + min + " Max: " + max; int nativeHash = NativeCall(array, str); int javaHash = 0; for (int i = 0; i < str.length(); ++i) { javaHash += (int) str.charAt(i); } check(array[0] == min && array[array.length - 1] == max && javaHash == nativeHash, "Data validation failure"); } } // SHORT class JNIShortWorker extends JNIAbstractWorker { ShortArrayProducer gp = new ShortArrayProducer(); public JNIShortWorker(int size) { super(size); } void doit(int size) { short[] array = gp.create(size); short min = Short.MAX_VALUE, max = Short.MIN_VALUE; for (int i = 0; i < array.length; ++i) { if (array[i] > max) { max = array[i]; } if (array[i] < min) { min = array[i]; } } String str = "Min: " + min + " Max: " + max; int nativeHash = NativeCall(array, str); int javaHash = 0; for (int i = 0; i < str.length(); ++i) { javaHash += (int) str.charAt(i); } check(array[0] == min && array[array.length - 1] == max && javaHash == nativeHash, "Data validation failure"); } } // INT class JNIIntWorker extends JNIAbstractWorker { IntArrayProducer gp = new IntArrayProducer(); public JNIIntWorker(int size) { super(size); } void doit(int size) { int[] array = gp.create(size); int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE; for (int i = 0; i < array.length; ++i) { if (array[i] > max) { max = array[i]; } if (array[i] < min) { min = array[i]; } } String str = "Min: " + min + " Max: " + max; int nativeHash = NativeCall(array, str); int javaHash = 0; for (int i = 0; i < str.length(); ++i) { javaHash += (int) str.charAt(i); } check(array[0] == min && array[array.length - 1] == max && javaHash == nativeHash, "Data validation failure"); } } // LONG class JNILongWorker extends JNIAbstractWorker { LongArrayProducer gp = new LongArrayProducer(); public JNILongWorker(int size) { super(size); } void doit(int size) { long[] array = gp.create(size); long min = Long.MAX_VALUE, max = Long.MIN_VALUE; for (int i = 0; i < array.length; ++i) { if (array[i] > max) { max = array[i]; } if (array[i] < min) { min = array[i]; } } String str = "Min: " + min + " Max: " + max; int nativeHash = NativeCall(array, str); int javaHash = 0; for (int i = 0; i < str.length(); ++i) { javaHash += (int) str.charAt(i); } check(array[0] == min && array[array.length - 1] == max && javaHash == nativeHash, "Data validation failure"); } } // FLOAT class JNIFloatWorker extends JNIAbstractWorker { FloatArrayProducer gp = new FloatArrayProducer(); public JNIFloatWorker(int size) { super(size); } void doit(int size) { float[] array = gp.create(size); float min = Float.MAX_VALUE, max = Float.MIN_VALUE; for (int i = 0; i < array.length; ++i) { if (array[i] > max) { max = array[i]; } if (array[i] < min) { min = array[i]; } } String str = "Min: " + min + " Max: " + max; int nativeHash = NativeCall(array, str); int javaHash = 0; for (int i = 0; i < str.length(); ++i) { javaHash += (int) str.charAt(i); } check(array[0] == min && array[array.length - 1] == max && javaHash == nativeHash, "Data validation failure"); } } // DOUBLE class JNIDoubleWorker extends JNIAbstractWorker { DoubleArrayProducer gp = new DoubleArrayProducer(); public JNIDoubleWorker(int size) { super(size); } void doit(int size) { double[] array = gp.create(size); Random rand = new Random(); double min = Double.MAX_VALUE, max = Double.MIN_VALUE; for (int i = 0; i < array.length; ++i) { if (array[i] > max) { max = array[i]; } if (array[i] < min) { min = array[i]; } } String str = "Min: " + min + " Max: " + max; int nativeHash = NativeCall(array, str); int javaHash = 0; for (int i = 0; i < str.length(); ++i) { javaHash += (int) str.charAt(i); } check(array[0] == min && array[array.length - 1] == max && javaHash == nativeHash, "Data validation failure"); } } } class JNIWorker { protected native int NativeCall(boolean[] array, String str); protected native int NativeCall(byte[] array, String str); protected native int NativeCall(char[] array, String str); protected native int NativeCall(short[] array, String str); protected native int NativeCall(int[] array, String str); protected native int NativeCall(long[] array, String str); protected native int NativeCall(float[] array, String str); protected native int NativeCall(double[] array, String str); }