From dc8a980a60367364e54a471d7031473957fe4b41 Mon Sep 17 00:00:00 2001 From: Amos Shi Date: Fri, 16 Aug 2024 17:20:51 +0000 Subject: [PATCH 01/16] 8313674: (fc) java/nio/channels/FileChannel/BlockDeviceSize.java should test for more block devices Reviewed-by: mbaesken Backport-of: e91492ab4333c61f39b50eb428fa932131a5b908 --- .../channels/FileChannel/BlockDeviceSize.java | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java b/test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java index 496312256be..7d430693b2f 100644 --- a/test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java +++ b/test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, 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 @@ -24,40 +24,47 @@ /* @test * @bug 8054029 * @requires (os.family == "linux") - * @summary Block devices should not report size=0 on Linux + * @summary FileChannel.size() should be equal to RandomAccessFile.size() and > 0 for block devs on Linux */ import java.io.RandomAccessFile; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.channels.FileChannel; import java.nio.file.AccessDeniedException; import java.nio.file.NoSuchFileException; +import java.util.List; + import static java.nio.file.StandardOpenOption.*; public class BlockDeviceSize { - private static final String BLK_FNAME = "/dev/sda1"; - private static final Path BLK_PATH = Paths.get(BLK_FNAME); + private static final List BLK_FNAMES = List.of("/dev/sda1", "/dev/nvme0n1", "/dev/xvda1") ; public static void main(String[] args) throws Throwable { - try (FileChannel ch = FileChannel.open(BLK_PATH, READ); - RandomAccessFile file = new RandomAccessFile(BLK_FNAME, "r")) { - - long size1 = ch.size(); - long size2 = file.length(); - if (size1 != size2) { - throw new RuntimeException("size differs when retrieved" + - " in different ways: " + size1 + " != " + size2); + for (String blkFname: BLK_FNAMES) { + Path blkPath = Path.of(blkFname); + try (FileChannel ch = FileChannel.open(blkPath, READ); + RandomAccessFile file = new RandomAccessFile(blkFname, "r")) { + + long size1 = ch.size(); + long size2 = file.length(); + if (size1 != size2) { + throw new RuntimeException("size differs when retrieved" + + " in different ways: " + size1 + " != " + size2); + } + if (size1 <= 0) { + throw new RuntimeException("size() for a block device size returns zero or a negative value"); + } + System.out.println("OK"); + + } catch (NoSuchFileException nsfe) { + System.err.println("File " + blkFname + " not found." + + " Skipping test"); + } catch (AccessDeniedException ade) { + throw new RuntimeException("Access to " + blkFname + " is denied." + + " Run test as root.", ade); + } - System.out.println("OK"); - - } catch (NoSuchFileException nsfe) { - System.err.println("File " + BLK_FNAME + " not found." + - " Skipping test"); - } catch (AccessDeniedException ade) { - System.err.println("Access to " + BLK_FNAME + " is denied." + - " Run test as root."); } } } From 60bbd3773fe0a9cd1627ebeae98a61de75f4af2d Mon Sep 17 00:00:00 2001 From: Andrew Lu Date: Wed, 21 Aug 2024 08:57:24 +0000 Subject: [PATCH 02/16] 8315684: Parallelize sun/security/util/math/TestIntegerModuloP.java Backport-of: 0f77d250b67ae0678756f986607eb239641dfb9e --- .../util/math/TestIntegerModuloP.java | 64 ++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/test/jdk/sun/security/util/math/TestIntegerModuloP.java b/test/jdk/sun/security/util/math/TestIntegerModuloP.java index 75a3d2dbc22..847262b47a0 100644 --- a/test/jdk/sun/security/util/math/TestIntegerModuloP.java +++ b/test/jdk/sun/security/util/math/TestIntegerModuloP.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, 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 @@ -22,21 +22,81 @@ */ /* - * @test + * @test id=IntegerPolynomial25519 * @bug 8181594 8208648 * @summary Test proper operation of integer field arithmetic * @modules java.base/sun.security.util java.base/sun.security.util.math java.base/sun.security.util.math.intpoly * @build BigIntegerModuloP * @run main TestIntegerModuloP sun.security.util.math.intpoly.IntegerPolynomial25519 32 0 + */ + + /* + * @test id=IntegerPolynomial448 + * @modules java.base/sun.security.util java.base/sun.security.util.math java.base/sun.security.util.math.intpoly + * @build BigIntegerModuloP * @run main TestIntegerModuloP sun.security.util.math.intpoly.IntegerPolynomial448 56 1 + */ + + /* + * @test id=IntegerPolynomial1305 + * @modules java.base/sun.security.util java.base/sun.security.util.math java.base/sun.security.util.math.intpoly + * @build BigIntegerModuloP * @run main TestIntegerModuloP sun.security.util.math.intpoly.IntegerPolynomial1305 16 2 + */ + + /* + * @test id=IntegerPolynomialP256 + * @modules java.base/sun.security.util java.base/sun.security.util.math java.base/sun.security.util.math.intpoly + * @build BigIntegerModuloP * @run main TestIntegerModuloP sun.security.util.math.intpoly.IntegerPolynomialP256 32 5 + */ + + /* + * @test id=IntegerPolynomialP384 + * @modules java.base/sun.security.util java.base/sun.security.util.math java.base/sun.security.util.math.intpoly + * @build BigIntegerModuloP * @run main TestIntegerModuloP sun.security.util.math.intpoly.IntegerPolynomialP384 48 6 + */ + + /* + * @test id=IntegerPolynomialP521 + * @modules java.base/sun.security.util java.base/sun.security.util.math java.base/sun.security.util.math.intpoly + * @build BigIntegerModuloP * @run main TestIntegerModuloP sun.security.util.math.intpoly.IntegerPolynomialP521 66 7 + */ + + /* + * @test id=P256OrderField + * @modules java.base/sun.security.util java.base/sun.security.util.math java.base/sun.security.util.math.intpoly + * @build BigIntegerModuloP * @run main TestIntegerModuloP sun.security.util.math.intpoly.P256OrderField 32 8 + */ + + /* + * @test id=P384OrderField + * @modules java.base/sun.security.util java.base/sun.security.util.math java.base/sun.security.util.math.intpoly + * @build BigIntegerModuloP * @run main TestIntegerModuloP sun.security.util.math.intpoly.P384OrderField 48 9 + */ + + /* + * @test id=P521OrderField + * @modules java.base/sun.security.util java.base/sun.security.util.math java.base/sun.security.util.math.intpoly + * @build BigIntegerModuloP * @run main TestIntegerModuloP sun.security.util.math.intpoly.P521OrderField 66 10 + */ + + /* + * @test id=Curve25519OrderField + * @modules java.base/sun.security.util java.base/sun.security.util.math java.base/sun.security.util.math.intpoly + * @build BigIntegerModuloP * @run main TestIntegerModuloP sun.security.util.math.intpoly.Curve25519OrderField 32 11 + */ + + /* + * @test id=Curve448OrderField + * @modules java.base/sun.security.util java.base/sun.security.util.math java.base/sun.security.util.math.intpoly + * @build BigIntegerModuloP * @run main TestIntegerModuloP sun.security.util.math.intpoly.Curve448OrderField 56 12 */ From 45588d69d3ba942d72a6b4ed31a5040578f5e0cc Mon Sep 17 00:00:00 2001 From: Andrew Lu Date: Wed, 21 Aug 2024 08:57:55 +0000 Subject: [PATCH 03/16] 8299813: java/nio/channels/DatagramChannel/Disconnect.java fails with jtreg test timeout due to lost datagram Backport-of: 49eb00da8dc66cff3ca430f06ab21357ee6180ef --- .../channels/DatagramChannel/Disconnect.java | 45 +++++++++++++------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java b/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java index 1ba742b6552..cdc5882fefd 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java +++ b/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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 @@ -34,6 +34,7 @@ import java.nio.*; import java.nio.channels.*; import java.io.IOException; + import jdk.test.lib.net.IPSupport; public class Disconnect { @@ -42,43 +43,61 @@ public static void main(String[] args) throws IOException { // test with default protocol family try (DatagramChannel dc = DatagramChannel.open()) { - test(dc); - test(dc); + InetAddress lo = InetAddress.getLoopbackAddress(); + System.out.println("Testing with default family and " + lo); + test(dc, lo); + test(dc, lo); } if (IPSupport.hasIPv4()) { // test with IPv4 only try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) { - test(dc); - test(dc); + InetAddress lo4 = InetAddress.ofLiteral("127.0.0.1"); + System.out.println("Testing with INET family and " + lo4); + test(dc, lo4); + test(dc, lo4); } } if (IPSupport.hasIPv6()) { // test with IPv6 only try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET6)) { - test(dc); - test(dc); + InetAddress lo6 = InetAddress.ofLiteral("::1"); + System.out.println("Testing with INET6 family and " + lo6); + test(dc, lo6); + test(dc, lo6); } } } + static int getLocalPort(DatagramChannel ch) throws IOException { + return ((InetSocketAddress) ch.getLocalAddress()).getPort(); + } + /** * Connect DatagramChannel to a server, write a datagram and disconnect. Invoke * a second or subsequent time with the same DatagramChannel instance to check * that disconnect works as expected. */ - static void test(DatagramChannel dc) throws IOException { + static void test(DatagramChannel dc, InetAddress lo) throws IOException { try (DatagramChannel server = DatagramChannel.open()) { - server.bind(new InetSocketAddress(0)); + server.bind(new InetSocketAddress(lo, 0)); - InetAddress lh = InetAddress.getLocalHost(); - dc.connect(new InetSocketAddress(lh, server.socket().getLocalPort())); + SocketAddress dcbound = dc.getLocalAddress(); + dc.connect(new InetSocketAddress(lo, server.socket().getLocalPort())); + System.out.println("dc bound to " + dcbound + " and connected from " + + dc.getLocalAddress() + " to " + dc.getRemoteAddress()); dc.write(ByteBuffer.wrap("hello".getBytes())); - ByteBuffer bb = ByteBuffer.allocate(100); - server.receive(bb); + if (getLocalPort(dc) != getLocalPort(server)) { + ByteBuffer bb = ByteBuffer.allocate(100); + server.receive(bb); + } else { + // some systems may allow dc and server to bind to the same port. + // when that happen the datagram may never be received + System.out.println("Server and clients are bound to the same port: skipping receive"); + } dc.disconnect(); From 2e640b8fceb4e391934f75b245d1a28b63ba2078 Mon Sep 17 00:00:00 2001 From: Andrew Lu Date: Wed, 21 Aug 2024 08:58:19 +0000 Subject: [PATCH 04/16] 8303891: Speed up Zip64SizeTest using a small ZIP64 file 8259866: two java.util tests failed with "IOException: There is not enough space on the disk" Backport-of: 842b895f093e15ecd8aa0153d712f5f81cf1cf67 --- .../java/util/zip/ZipFile/Zip64SizeTest.java | 209 ++++++++++++------ 1 file changed, 137 insertions(+), 72 deletions(-) diff --git a/test/jdk/java/util/zip/ZipFile/Zip64SizeTest.java b/test/jdk/java/util/zip/ZipFile/Zip64SizeTest.java index a7afa2681a0..ca472aa2aa7 100644 --- a/test/jdk/java/util/zip/ZipFile/Zip64SizeTest.java +++ b/test/jdk/java/util/zip/ZipFile/Zip64SizeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -20,117 +20,174 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; -import java.io.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * @test - * @bug 8226530 - * @summary ZIP File System tests that leverage DirectoryStream + * @bug 8226530 8303891 + * @summary Verify that ZipFile reads size fields using the Zip64 extra + * field when only the 'uncompressed size' field has the ZIP64 "magic value" 0xFFFFFFFF * @compile Zip64SizeTest.java - * @run testng Zip64SizeTest + * @run junit Zip64SizeTest */ public class Zip64SizeTest { - - private static final int BUFFER_SIZE = 2048; // ZIP file to create - private static final String ZIP_FILE_NAME = "Zip64SizeTest.zip"; - // File that will be created with a size greater than 0xFFFFFFFF - private static final String LARGE_FILE_NAME = "LargeZipEntry.txt"; - // File that will be created with a size less than 0xFFFFFFFF - private static final String SMALL_FILE_NAME = "SmallZipEntry.txt"; - // List of files to be added to the ZIP file - private static final List ZIP_ENTRIES = List.of(LARGE_FILE_NAME, - SMALL_FILE_NAME); - private static final long LARGE_FILE_SIZE = 5L * 1024L * 1024L * 1024L; // 5GB - private static final long SMALL_FILE_SIZE = 0x100000L; // 1024L x 1024L; + private static final Path ZIP_FILE = Path.of("Zip64SizeTest.zip"); + // Contents to write to ZIP entries + private static final byte[] CONTENT = "Hello".getBytes(StandardCharsets.UTF_8); + // This opaque tag will be ignored by ZipEntry.setExtra0 + private static final int UNKNOWN_TAG = 0x9902; + // Tag used when converting the extra field to a real ZIP64 extra field + private static final short ZIP64_TAG = 0x1; + // Marker value to indicate that the actual value is stored in the ZIP64 extra field + private static final int ZIP64_MAGIC_VALUE = 0xFFFFFFFF; /** - * Validate that if the size of a ZIP entry exceeds 0xFFFFFFFF, that the - * correct size is returned from the ZIP64 Extended information. - * @throws IOException + * Validate that if the 'uncompressed size' of a ZIP CEN header is 0xFFFFFFFF, then the + * actual size is retrieved from the corresponding ZIP64 Extended information field. + * + * @throws IOException if an unexpected IOException occurs */ @Test - private static void validateZipEntrySizes() throws IOException { - createFiles(); + public void validateZipEntrySizes() throws IOException { createZipFile(); System.out.println("Validating Zip Entry Sizes"); - try (ZipFile zip = new ZipFile(ZIP_FILE_NAME)) { - ZipEntry ze = zip.getEntry(LARGE_FILE_NAME); + try (ZipFile zip = new ZipFile(ZIP_FILE.toFile())) { + ZipEntry ze = zip.getEntry("first"); System.out.printf("Entry: %s, size= %s%n", ze.getName(), ze.getSize()); - assertTrue(ze.getSize() == LARGE_FILE_SIZE); - ze = zip.getEntry(SMALL_FILE_NAME); + assertEquals(CONTENT.length, ze.getSize()); + ze = zip.getEntry("second"); System.out.printf("Entry: %s, size= %s%n", ze.getName(), ze.getSize()); - assertTrue(ze.getSize() == SMALL_FILE_SIZE); - + assertEquals(CONTENT.length, ze.getSize()); } } /** - * Delete the files created for use by the test - * @throws IOException if an error occurs deleting the files + * Create a ZIP file with a CEN entry where the 'uncompressed size' is stored in + * the ZIP64 field, but the 'compressed size' is in the CEN field. This makes the + * ZIP64 data block 8 bytes long, which triggers the regression described in 8226530. + * + * The CEN entry for the "first" entry will have the following structure: + * (Note the CEN 'Uncompressed Length' being 0xFFFFFFFF and the ZIP64 + * 'Uncompressed Size' being 5) + * + * 0081 CENTRAL HEADER #1 02014B50 + * 0085 Created Zip Spec 14 '2.0' + * 0086 Created OS 00 'MS-DOS' + * [...] Omitted for brevity + * 0091 CRC F7D18982 + * 0095 Compressed Length 00000007 + * 0099 Uncompressed Length FFFFFFFF + * [...] Omitted for brevity + * 00AF Filename 'first' + * 00B4 Extra ID #0001 0001 'ZIP64' + * 00B6 Length 0008 + * 00B8 Uncompressed Size 0000000000000005 + * + * @throws IOException if an error occurs creating the ZIP File */ - private static void deleteFiles() throws IOException { - Files.deleteIfExists(Path.of(ZIP_FILE_NAME)); - Files.deleteIfExists(Path.of(LARGE_FILE_NAME)); - Files.deleteIfExists(Path.of(SMALL_FILE_NAME)); + private static void createZipFile() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (ZipOutputStream zos = new ZipOutputStream(baos)) { + + // The 'first' entry will store 'uncompressed size' in the Zip64 format + ZipEntry e1 = new ZipEntry("first"); + + // Make an extra field with the correct size for an 8-byte 'uncompressed size' + // Zip64 field. Temporarily use the 'unknown' tag 0x9902 to make + // ZipEntry.setExtra0 skip parsing this as a Zip64. + // See APPNOTE.TXT, 4.6.1 Third Party Mappings + byte[] opaqueExtra = createBlankExtra((short) UNKNOWN_TAG, (short) Long.BYTES); + e1.setExtra(opaqueExtra); + + zos.putNextEntry(e1); + zos.write(CONTENT); + + // A second entry, not in Zip64 format + ZipEntry e2 = new ZipEntry("second"); + zos.putNextEntry(e2); + zos.write(CONTENT); + } + + byte[] zip = baos.toByteArray(); + + // Update the CEN of 'first' to use the Zip64 format + updateCENHeaderToZip64(zip); + Files.write(ZIP_FILE, zip); } /** - * Create the ZIP file adding an entry whose size exceeds 0xFFFFFFFF - * @throws IOException if an error occurs creating the ZIP File + * Update the CEN entry of the "first" entry to use ZIP64 format for the + * 'uncompressed size' field. The updated extra field will have the following + * structure: + * + * 00B4 Extra ID #0001 0001 'ZIP64' + * 00B6 Length 0008 + * 00B8 Uncompressed Size 0000000000000005 + * + * @param zip the ZIP file to update to ZIP64 */ - private static void createZipFile() throws IOException { - try (FileOutputStream fos = new FileOutputStream(ZIP_FILE_NAME); - ZipOutputStream zos = new ZipOutputStream(fos)) { - System.out.printf("Creating Zip file: %s%n", ZIP_FILE_NAME); - for (String srcFile : ZIP_ENTRIES) { - System.out.printf("...Adding Entry: %s%n", srcFile); - File fileToZip = new File(srcFile); - try (FileInputStream fis = new FileInputStream(fileToZip)) { - ZipEntry zipEntry = new ZipEntry(fileToZip.getName()); - zipEntry.setSize(fileToZip.length()); - zos.putNextEntry(zipEntry); - byte[] bytes = new byte[BUFFER_SIZE]; - int length; - while ((length = fis.read(bytes)) >= 0) { - zos.write(bytes, 0, length); - } - } - } - } + private static void updateCENHeaderToZip64(byte[] zip) { + ByteBuffer buffer = ByteBuffer.wrap(zip).order(ByteOrder.LITTLE_ENDIAN); + // Find the offset of the first CEN header + int cenOffset = buffer.getInt(zip.length- ZipFile.ENDHDR + ZipFile.ENDOFF); + // Find the offset of the extra field + int nlen = buffer.getShort(cenOffset + ZipFile.CENNAM); + int extraOffset = cenOffset + ZipFile.CENHDR + nlen; + + // Change the header ID from 'unknown' to ZIP64 + buffer.putShort(extraOffset, ZIP64_TAG); + // Update the 'uncompressed size' ZIP64 value to the actual uncompressed length + int fieldOffset = extraOffset + + Short.BYTES // TAG + + Short.BYTES; // data size + buffer.putLong(fieldOffset, CONTENT.length); + + // Set the 'uncompressed size' field of the CEN to 0xFFFFFFFF + buffer.putInt(cenOffset + ZipFile.CENLEN, ZIP64_MAGIC_VALUE); } /** - * Create the files that will be added to the ZIP file - * @throws IOException if there is a problem creating the files + * Create an extra field with the given tag and data block size, and a + * blank data block. + * @return an extra field with the specified tag and size + * @param tag the header id of the extra field + * @param blockSize the size of the extra field's data block */ - private static void createFiles() throws IOException { - try (RandomAccessFile largeFile = new RandomAccessFile(LARGE_FILE_NAME, "rw"); - RandomAccessFile smallFile = new RandomAccessFile(SMALL_FILE_NAME, "rw")) { - System.out.printf("Creating %s%n", LARGE_FILE_NAME); - largeFile.setLength(LARGE_FILE_SIZE); - System.out.printf("Creating %s%n", SMALL_FILE_NAME); - smallFile.setLength(SMALL_FILE_SIZE); - } + private static byte[] createBlankExtra(short tag, short blockSize) { + int size = Short.BYTES // tag + + Short.BYTES // data block size + + blockSize; // data block; + + byte[] extra = new byte[size]; + ByteBuffer.wrap(extra).order(ByteOrder.LITTLE_ENDIAN) + .putShort(0, tag) + .putShort(Short.BYTES, blockSize); + return extra; } /** * Make sure the needed test files do not exist prior to executing the test * @throws IOException */ - @BeforeMethod + @BeforeEach public void setUp() throws IOException { deleteFiles(); } @@ -139,8 +196,16 @@ public void setUp() throws IOException { * Remove the files created for the test * @throws IOException */ - @AfterMethod + @AfterEach public void tearDown() throws IOException { deleteFiles(); } + + /** + * Delete the files created for use by the test + * @throws IOException if an error occurs deleting the files + */ + private static void deleteFiles() throws IOException { + Files.deleteIfExists(ZIP_FILE); + } } From a128c80b367bf2fd11643f0a3baaca26125b5a68 Mon Sep 17 00:00:00 2001 From: Andrew Lu Date: Wed, 21 Aug 2024 08:58:35 +0000 Subject: [PATCH 05/16] 8315936: Parallelize gc/stress/TestStressG1Humongous.java test Backport-of: 3f19df685c342cef212305cca630331878a24e79 --- .../gc/stress/TestStressG1Humongous.java | 49 +++++++++++++++---- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java b/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java index f1e23d43c07..983b9f6c33f 100644 --- a/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java +++ b/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java @@ -24,14 +24,41 @@ package gc.stress; /* - * @test TestStressG1Humongous + * @test * @key stress * @summary Stress G1 by humongous allocations in situation near OOM * @requires vm.gc.G1 * @requires !vm.flightRecorder * @library /test/lib * @modules java.base/jdk.internal.misc - * @run driver/timeout=1300 gc.stress.TestStressG1Humongous + * @run driver/timeout=180 gc.stress.TestStressG1Humongous 4 3 1.1 120 + */ + +/* + * @test + * @requires vm.gc.G1 + * @requires !vm.flightRecorder + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run driver/timeout=180 gc.stress.TestStressG1Humongous 16 5 2.1 120 + */ + +/* + * @test + * @requires vm.gc.G1 + * @requires !vm.flightRecorder + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run driver/timeout=180 gc.stress.TestStressG1Humongous 32 4 0.6 120 + */ + +/* + * @test + * @requires vm.gc.G1 + * @requires !vm.flightRecorder + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run driver/timeout=900 gc.stress.TestStressG1Humongous 1 7 0.6 600 */ import java.util.ArrayList; @@ -48,17 +75,19 @@ public class TestStressG1Humongous{ public static void main(String[] args) throws Exception { + if (args.length != 4) { + throw new IllegalArgumentException("Test expects 4 arguments"); + } + // Limit heap size on 32-bit platforms int heapSize = Platform.is32bit() ? 512 : 1024; - // Heap size, region size, threads, humongous size, timeout - run(heapSize, 4, 3, 1.1, 120); - run(heapSize, 16, 5, 2.1, 120); - run(heapSize, 32, 4, 0.6, 120); - run(heapSize, 1, 7, 0.6, 600); - } - private static void run(int heapSize, int regionSize, int threads, double humongousSize, int timeout) - throws Exception { + // Region size, threads, humongous size, and timeout passed as @run arguments + int regionSize = Integer.parseInt(args[0]); + int threads = Integer.parseInt(args[1]); + double humongousSize = Double.parseDouble(args[2]); + int timeout = Integer.parseInt(args[3]); + ArrayList options = new ArrayList<>(); Collections.addAll(options, Utils.getTestJavaOpts()); Collections.addAll(options, From c0a69209972f6dd50b0927cd3aac53694e1af977 Mon Sep 17 00:00:00 2001 From: Sonia Zaldana Calles Date: Wed, 21 Aug 2024 13:11:59 +0000 Subject: [PATCH 06/16] 8273216: JCMD does not work across container boundaries with Podman Backport-of: 9180d9a2f990e71ca6ac9c14e55a21f7372929ac --- .../jtreg/containers/docker/TestJcmd.java | 115 +++++++++++++++--- 1 file changed, 101 insertions(+), 14 deletions(-) diff --git a/test/hotspot/jtreg/containers/docker/TestJcmd.java b/test/hotspot/jtreg/containers/docker/TestJcmd.java index 7b850eb004b..c0dfb3d01d3 100644 --- a/test/hotspot/jtreg/containers/docker/TestJcmd.java +++ b/test/hotspot/jtreg/containers/docker/TestJcmd.java @@ -55,23 +55,22 @@ public class TestJcmd { private static final String IMAGE_NAME = Common.imageName("jcmd"); private static final int TIME_TO_RUN_CONTAINER_PROCESS = (int) (10 * Utils.TIMEOUT_FACTOR); // seconds private static final String CONTAINER_NAME = "test-container"; + private static final boolean IS_PODMAN = Container.ENGINE_COMMAND.contains("podman"); + private static final String ROOT_UID = "0"; public static void main(String[] args) throws Exception { DockerTestUtils.canTestDocker(); - // See JDK-8273216 for details - if (Container.ENGINE_COMMAND.equals("podman")) { - throw new SkippedException("JCMD does not work across container boundaries when using Podman"); + // podman versions below 3.3.1 hava a bug where cross-container testing with correct + // permissions fails. See JDK-8273216 + if (IS_PODMAN && PodmanVersion.VERSION_3_3_1.compareTo(getPodmanVersion()) > 0) { + throw new SkippedException("Podman version too old for this test. Expected >= 3.3.1"); } // Need to create a custom dockerfile where user name and id, as well as group name and id // of the JVM running in container must match the ones from the inspecting JCMD process. - String uid = getId("-u"); - String gid = getId("-g"); - String userName = getId("-un"); - String groupName = getId("-gn"); - String content = generateCustomDockerfile(uid, gid, userName, groupName); + String content = generateCustomDockerfile(); DockerTestUtils.buildJdkContainerImage(IMAGE_NAME, content); try { @@ -135,17 +134,26 @@ private static void testVmInfo(long pid) throws Exception { // Need to make sure that user name+id and group name+id are created for the image, and // match the host system. This is necessary to allow proper permission/access for JCMD. - private static String generateCustomDockerfile(String uid, String gid, - String userName, String groupName) throws Exception { + // For podman --userns=keep-id is sufficient. + private static String generateCustomDockerfile() throws Exception { StringBuilder sb = new StringBuilder(); sb.append(String.format("FROM %s:%s\n", DockerfileConfig.getBaseImageName(), DockerfileConfig.getBaseImageVersion())); sb.append("COPY /jdk /jdk\n"); sb.append("ENV JAVA_HOME=/jdk\n"); - sb.append(String.format("RUN groupadd --gid %s %s \n", gid, groupName)); - sb.append(String.format("RUN useradd --uid %s --gid %s %s \n", uid, gid, userName)); - sb.append(String.format("USER %s \n", userName)); + if (!IS_PODMAN) { // only needed for docker + String uid = getId("-u"); + String gid = getId("-g"); + String userName = getId("-un"); + String groupName = getId("-gn"); + // Only needed when run as regular user. UID == 0 should already exist + if (!ROOT_UID.equals(uid)) { + sb.append(String.format("RUN groupadd --gid %s %s \n", gid, groupName)); + sb.append(String.format("RUN useradd --uid %s --gid %s %s \n", uid, gid, userName)); + sb.append(String.format("USER %s \n", userName)); + } + } sb.append("CMD [\"/bin/bash\"]\n"); @@ -155,12 +163,17 @@ private static String generateCustomDockerfile(String uid, String gid, private static Process startObservedContainer() throws Exception { DockerRunOptions opts = new DockerRunOptions(IMAGE_NAME, "/jdk/bin/java", "EventGeneratorLoop"); - opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/") + opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/:z") .addJavaOpts("-cp", "/test-classes/") .addDockerOpts("--cap-add=SYS_PTRACE") .addDockerOpts("--name", CONTAINER_NAME) .addClassOptions("" + TIME_TO_RUN_CONTAINER_PROCESS); + if (IS_PODMAN) { + // map the current userid to the one in the target namespace + opts.addDockerOpts("--userns=keep-id"); + } + // avoid large Xmx opts.appendTestJavaOptions = false; @@ -190,4 +203,78 @@ private static String getId(String param) throws Exception { System.out.println("getId() " + param + " returning: " + result); return result; } + + // pre: IS_PODMAN == true + private static String getPodmanVersionStr() { + if (!IS_PODMAN) { + return null; + } + try { + ProcessBuilder pb = new ProcessBuilder(Container.ENGINE_COMMAND, "--version"); + OutputAnalyzer out = new OutputAnalyzer(pb.start()) + .shouldHaveExitValue(0); + String result = out.asLines().get(0); + System.out.println(Container.ENGINE_COMMAND + " --version returning: " + result); + return result; + } catch (Exception e) { + System.out.println(Container.ENGINE_COMMAND + " --version command failed. Returning null"); + return null; + } + } + + private static PodmanVersion getPodmanVersion() { + return PodmanVersion.fromVersionString(getPodmanVersionStr()); + } + + private static class PodmanVersion implements Comparable { + private static final PodmanVersion DEFAULT = new PodmanVersion(0, 0, 0); + private static final PodmanVersion VERSION_3_3_1 = new PodmanVersion(3, 3, 1); + private final int major; + private final int minor; + private final int micro; + + private PodmanVersion(int major, int minor, int micro) { + this.major = major; + this.minor = minor; + this.micro = micro; + } + + @Override + public int compareTo(PodmanVersion other) { + if (this.major > other.major) { + return 1; + } else if (this.major < other.major) { + return -1; + } else { // equal major + if (this.minor > other.minor) { + return 1; + } else if (this.minor < other.minor) { + return -1; + } else { // equal majors and minors + if (this.micro > other.micro) { + return 1; + } else if (this.micro < other.micro) { + return -1; + } else { + // equal majors, minors, micro + return 0; + } + } + } + } + + private static PodmanVersion fromVersionString(String version) { + try { + // Example 'podman version 3.2.1' + String versNums = version.split("\\s+", 3)[2]; + String[] numbers = versNums.split("\\.", 3); + return new PodmanVersion(Integer.parseInt(numbers[0]), + Integer.parseInt(numbers[1]), + Integer.parseInt(numbers[2])); + } catch (Exception e) { + System.out.println("Failed to parse podman version: " + version); + return DEFAULT; + } + } + } } From a1eb77778c77a67215978747a356b137a27093cf Mon Sep 17 00:00:00 2001 From: Amos Shi Date: Wed, 21 Aug 2024 23:17:52 +0000 Subject: [PATCH 07/16] 8284316: Support accessibility ManualTestFrame.java for non SwingSet tests Backport-of: 6a7c023796b0f39f54d0335f4723c1f06ff0032d --- .../accessibility/manual/SwingSetTest.java | 41 +++--- .../manual/TestJProgressBarAccessibility.java | 117 ++++++++++++++++++ .../manual/lib/DescriptionPane.java | 15 +-- .../manual/lib/ManualTestFrame.java | 81 +++++++++--- 4 files changed, 207 insertions(+), 47 deletions(-) create mode 100644 test/jdk/javax/accessibility/manual/TestJProgressBarAccessibility.java diff --git a/test/jdk/javax/accessibility/manual/SwingSetTest.java b/test/jdk/javax/accessibility/manual/SwingSetTest.java index 33bc2ff430a..8700f9a07d2 100644 --- a/test/jdk/javax/accessibility/manual/SwingSetTest.java +++ b/test/jdk/javax/accessibility/manual/SwingSetTest.java @@ -1,19 +1,18 @@ /** - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ import lib.ManualTestFrame; import lib.TestResult; -import javax.imageio.ImageIO; -import java.io.File; +import java.util.function.Consumer; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.net.URLClassLoader; -import java.nio.file.Files; import java.util.function.Supplier; +import javax.swing.JEditorPane; import static java.io.File.separator; @@ -22,10 +21,21 @@ public class SwingSetTest { public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { System.out.println("test image " + System.getenv("TEST_IMAGE_DIR")); + + Consumer testInstructionProvider = e -> { + try { + e.setContentType("text/html"); + e.setPage(SwingSetTest.class.getResource(args[0] + ".html")); + } catch (IOException exception) { + exception.printStackTrace(); + } + }; + Supplier resultSupplier = ManualTestFrame.showUI(args[0], "Wait for SwingSet2 to load, follow the instructions, select pass or fail. " + "Do not close windows manually.", - SwingSetTest.class.getResource(args[0] + ".html")); + testInstructionProvider); + String swingSetJar = System.getenv("SWINGSET2_JAR"); if (swingSetJar == null) { swingSetJar = "file://" + System.getProperty("java.home") + @@ -37,23 +47,10 @@ public static void main(String[] args) throws IOException, InterruptedException, System.out.println("Loading SwingSet2 from " + swingSetJar); ClassLoader ss = new URLClassLoader(new URL[]{new URL(swingSetJar)}); ss.loadClass("SwingSet2").getMethod("main", String[].class).invoke(null, (Object)new String[0]); + //this will block until user decision to pass or fail the test TestResult result = resultSupplier.get(); - if (result != null) { - System.err.println("Failure reason: \n" + result.getFailureDescription()); - if (result.getScreenCapture() != null) { - File screenDump = new File(System.getProperty("test.classes") + separator + args[0] + ".png"); - System.err.println("Saving screen image to " + screenDump.getAbsolutePath()); - ImageIO.write(result.getScreenCapture(), "png", screenDump); - } - Throwable e = result.getException(); - if (e != null) { - throw new RuntimeException(e); - } else { - if (!result.getStatus()) throw new RuntimeException("Test failed!"); - } - } else { - throw new RuntimeException("No result returned!"); - } + ManualTestFrame.handleResult(result, args[0]); } -} \ No newline at end of file +} + diff --git a/test/jdk/javax/accessibility/manual/TestJProgressBarAccessibility.java b/test/jdk/javax/accessibility/manual/TestJProgressBarAccessibility.java new file mode 100644 index 00000000000..0740e8d2971 --- /dev/null +++ b/test/jdk/javax/accessibility/manual/TestJProgressBarAccessibility.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2022 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 headful +@summary manual test for accessibility JProgressBar +@run main/manual TestJProgressBarAccessibility +*/ + +import java.awt.BorderLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javax.accessibility.AccessibleContext; +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.JProgressBar; +import javax.swing.SwingUtilities; + +import lib.ManualTestFrame; +import lib.TestResult; + +public class TestJProgressBarAccessibility { + + private static JFrame frame; + private static volatile int value = 10; + private static final String instruction = """ + Aim : Check whether JProgressBar value is read in case of VoiceOver or + Screen magnifier shows the magnified value in case of Screen magnifier is enabled + 1) Move the mouse pointer over the JProgressBar and if you + hear the JProgressBar value in case of VoiceOver then the test pass else fail. + 2) Move the mouse pointer over the JProgressBar and if you see the magnified value + when Screen magnifier is enabled then the test pass else fail. + """; + + private static void createTestUI() throws InterruptedException, InvocationTargetException { + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("Test JProgressBar accessibility"); + JProgressBar progressBar = new JProgressBar(); + progressBar.setValue(value); + progressBar.setStringPainted(true); + + progressBar.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + if ( value == 100) { + value = 0; + } else { + value += 5; + } + progressBar.setValue(value); + } + }); + + AccessibleContext accessibleContext = + progressBar.getAccessibleContext(); + accessibleContext.setAccessibleName("JProgressBar accessibility name"); + accessibleContext.setAccessibleDescription("Jprogress accessibility " + + "description"); + + frame.getContentPane().add(progressBar, BorderLayout.CENTER); + + frame.setSize(200,200); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, IOException { + + Consumer testInstProvider = e -> { + e.setContentType("text/plain"); + e.setText(instruction); + }; + + Supplier resultSupplier = ManualTestFrame.showUI( + "JProgressBar " + + "Accessibility Test", "Wait until the Test UI is " + + "seen", testInstProvider); + + // Create and show TestUI + createTestUI(); + + //this will block until user decision to pass or fail the test + TestResult testResult = resultSupplier.get(); + ManualTestFrame.handleResult(testResult,"TestJProgressBarAccessibility"); + } +} + diff --git a/test/jdk/javax/accessibility/manual/lib/DescriptionPane.java b/test/jdk/javax/accessibility/manual/lib/DescriptionPane.java index bdd0e23e788..59580d53ace 100644 --- a/test/jdk/javax/accessibility/manual/lib/DescriptionPane.java +++ b/test/jdk/javax/accessibility/manual/lib/DescriptionPane.java @@ -20,26 +20,26 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package lib; -import javax.swing.JEditorPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; import java.awt.BorderLayout; import java.awt.Dimension; import java.io.IOException; -import java.net.URL; +import java.util.function.Consumer; +import javax.swing.JEditorPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; /** * Displays instructions provided through a URL. */ class DescriptionPane extends JPanel { - DescriptionPane(URL instructions) throws IOException { + DescriptionPane(Consumer instructions) { JEditorPane editorPane = new JEditorPane(); editorPane.setFocusable(false); - editorPane.setContentType("text/html"); - editorPane.setPage(instructions); + instructions.accept(editorPane); editorPane.setEditable(false); JScrollPane esp = new JScrollPane(editorPane); @@ -51,3 +51,4 @@ class DescriptionPane extends JPanel { add(esp); } } + diff --git a/test/jdk/javax/accessibility/manual/lib/ManualTestFrame.java b/test/jdk/javax/accessibility/manual/lib/ManualTestFrame.java index 57117790b57..6aad4164dee 100644 --- a/test/jdk/javax/accessibility/manual/lib/ManualTestFrame.java +++ b/test/jdk/javax/accessibility/manual/lib/ManualTestFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022 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 @@ -22,25 +22,31 @@ */ package lib; -import javax.swing.BorderFactory; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JSplitPane; -import javax.swing.JTextArea; -import javax.swing.border.BevelBorder; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.GridLayout; +import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; -import java.net.URL; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Supplier; +import javax.imageio.ImageIO; +import javax.swing.BorderFactory; +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSplitPane; +import javax.swing.JTextArea; +import javax.swing.border.BevelBorder; -import static java.awt.BorderLayout.*; +import static java.awt.BorderLayout.CENTER; +import static java.awt.BorderLayout.NORTH; +import static java.awt.BorderLayout.SOUTH; +import static java.io.File.separator; import static javax.swing.SwingUtilities.invokeAndWait; /** @@ -51,7 +57,9 @@ public class ManualTestFrame extends JFrame { private boolean alreadyFailed = false; - private ManualTestFrame(String testName, String headerText, URL instructions, Consumer listener) throws IOException { + private ManualTestFrame(String testName, String headerText, + Consumer instructions, + Consumer listener) throws IOException { super(testName); @@ -124,14 +132,17 @@ private ManualTestFrame(String testName, String headerText, URL instructions, Co /** * Show a test control frame which allows a user to either pass or fail the test. - * @param testName - * @param headerText - * @param instructions + * + * @param testName name of the testcase + * @param headerText information to the user to wait for the test frame. + * @param instructions test instruction for the user * @return Returning supplier blocks till the test is passed or failed by the user. - * @throws InterruptedException - * @throws InvocationTargetException + * @throws InterruptedException exception + * @throws InvocationTargetException exception */ - public static Supplier showUI(String testName, String headerText, URL instructions) + public static Supplier showUI(String testName, + String headerText, + Consumer instructions) throws InterruptedException, InvocationTargetException { AtomicReference resultContainer = new AtomicReference<>(); CountDownLatch latch = new CountDownLatch(1); @@ -148,7 +159,12 @@ public static Supplier showUI(String testName, String headerText, UR }); return () -> { try { - latch.await(); + int timeout = Integer.getInteger("timeout", 10); + System.out.println("timeout value : " + timeout); + if (!latch.await(timeout, TimeUnit.MINUTES)) { + throw new RuntimeException("Timeout : User failed to " + + "take decision on the test result."); + } } catch (InterruptedException e) { return new TestResult(e); } @@ -156,4 +172,33 @@ public static Supplier showUI(String testName, String headerText, UR }; } + /** + * Checks the TestResult after user interacted with the manual TestFrame + * and the test UI. + * + * @param result Instance of the TestResult + * @param testName name of the testcase + * @throws IOException exception + */ + public static void handleResult(TestResult result, String testName) throws IOException { + if (result != null) { + System.err.println("Failure reason: \n" + result.getFailureDescription()); + if (result.getScreenCapture() != null) { + File screenDump = new File(System.getProperty("test.classes") + separator + testName + ".png"); + System.err.println("Saving screen image to " + screenDump.getAbsolutePath()); + ImageIO.write(result.getScreenCapture(), "png", screenDump); + } + Throwable e = result.getException(); + if (e != null) { + throw new RuntimeException(e); + } else { + if (!result.getStatus()) + throw new RuntimeException("Test failed!"); + } + } else { + throw new RuntimeException("No result returned!"); + } + } + } + From dade22a7b87a03a900f9a1221c8f9cf1bf13a81d Mon Sep 17 00:00:00 2001 From: Amos Shi Date: Wed, 21 Aug 2024 23:21:10 +0000 Subject: [PATCH 08/16] 8308891: TestCDSVMCrash.java needs @requires vm.cds Backport-of: 101bf2290da5735fd9624ab647a8183c2c21f22d --- test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java b/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java index b3db8202ab3..1a13e30f33a 100644 --- a/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java +++ b/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java @@ -24,6 +24,7 @@ /* * @test TestCDSVMCrash * @summary Verify that an exception is thrown when the VM crashes during executeAndLog + * @requires vm.cds * @modules java.base/jdk.internal.misc * @library /test/lib * @run driver TestCDSVMCrash From 533d873d296dcafe22a4cc534488d843259fe2ff Mon Sep 17 00:00:00 2001 From: Amos Shi Date: Wed, 21 Aug 2024 23:25:56 +0000 Subject: [PATCH 09/16] 8315576: compiler/codecache/CodeCacheFullCountTest.java fails after JDK-8314837 Reviewed-by: phh Backport-of: 343cc0ce2bba797e206f6b7312018a8c6d1bdb66 --- .../codecache/CodeCacheFullCountTest.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java b/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java index 652d0b0b526..ff28c588b4c 100644 --- a/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java +++ b/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java @@ -45,12 +45,20 @@ public static void main(String args[]) throws Throwable { } } - public static void wasteCodeCache() throws Exception { + public static void wasteCodeCache() throws Throwable { URL url = CodeCacheFullCountTest.class.getProtectionDomain().getCodeSource().getLocation(); - for (int i = 0; i < 500; i++) { - ClassLoader cl = new MyClassLoader(url); - refClass(cl.loadClass("SomeClass")); + try { + for (int i = 0; i < 500; i++) { + ClassLoader cl = new MyClassLoader(url); + refClass(cl.loadClass("SomeClass")); + } + } catch (Throwable t) { + // Expose the root cause of the Throwable instance. + while (t.getCause() != null) { + t = t.getCause(); + } + throw t; } } @@ -59,7 +67,7 @@ public static void runTest() throws Throwable { "-XX:ReservedCodeCacheSize=2496k", "-XX:-UseCodeCacheFlushing", "CodeCacheFullCountTest", "WasteCodeCache"); OutputAnalyzer oa = ProcessTools.executeProcess(pb); // Ignore adapter creation failures - if (oa.getExitValue() != 0 && !oa.getStderr().contains("Out of space in CodeCache for adapters")) { + if (oa.getExitValue() != 0 && !oa.getOutput().contains("Out of space in CodeCache for adapters")) { oa.reportDiagnosticSummary(); throw new RuntimeException("VM finished with exit code " + oa.getExitValue()); } From eaf95567ac2d31709f025367668f8010aee5f62f Mon Sep 17 00:00:00 2001 From: Daniel Hu Date: Fri, 23 Aug 2024 17:38:31 +0000 Subject: [PATCH 10/16] 8312049: runtime/logging/ClassLoadUnloadTest can be improved Reviewed-by: phh Backport-of: 4676b40f17dd18941f5883cb9b989ad639992a50 --- .../runtime/logging/ClassLoadUnloadTest.java | 59 +++++++++---------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/test/hotspot/jtreg/runtime/logging/ClassLoadUnloadTest.java b/test/hotspot/jtreg/runtime/logging/ClassLoadUnloadTest.java index 3fd76953377..74af1dfc9e8 100644 --- a/test/hotspot/jtreg/runtime/logging/ClassLoadUnloadTest.java +++ b/test/hotspot/jtreg/runtime/logging/ClassLoadUnloadTest.java @@ -44,8 +44,6 @@ import jdk.test.lib.classloader.ClassUnloadCommon; public class ClassLoadUnloadTest { - private static OutputAnalyzer out; - private static ProcessBuilder pb; private static class ClassUnloadTestMain { public static void main(String... args) throws Exception { String className = "test.Empty"; @@ -56,63 +54,62 @@ public static void main(String... args) throws Exception { } } - static void checkFor(String... outputStrings) throws Exception { - out = new OutputAnalyzer(pb.start()); + static void checkFor(OutputAnalyzer output, String... outputStrings) throws Exception { for (String s: outputStrings) { - out.shouldContain(s); + output.shouldContain(s); } - out.shouldHaveExitValue(0); } - static void checkAbsent(String... outputStrings) throws Exception { - out = new OutputAnalyzer(pb.start()); + static void checkAbsent(OutputAnalyzer output, String... outputStrings) throws Exception { for (String s: outputStrings) { - out.shouldNotContain(s); + output.shouldNotContain(s); } - out.shouldHaveExitValue(0); } // Use the same command-line heap size setting as ../ClassUnload/UnloadTest.java - static ProcessBuilder exec(String... args) throws Exception { + static OutputAnalyzer exec(String... args) throws Exception { List argsList = new ArrayList<>(); Collections.addAll(argsList, args); - Collections.addAll(argsList, "-Xmn8m"); - Collections.addAll(argsList, "-Dtest.class.path=" + System.getProperty("test.class.path", ".")); - Collections.addAll(argsList, "-XX:+ClassUnloading"); - Collections.addAll(argsList, ClassUnloadTestMain.class.getName()); - return ProcessTools.createJavaProcessBuilder(argsList); + Collections.addAll(argsList, "-Xmn8m", "-Dtest.class.path=" + System.getProperty("test.class.path", "."), + "-XX:+ClassUnloading", ClassUnloadTestMain.class.getName()); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(argsList); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + return output; } public static void main(String... args) throws Exception { + OutputAnalyzer output; + // -Xlog:class+unload=info - pb = exec("-Xlog:class+unload=info"); - checkFor("[class,unload]", "unloading class"); + output = exec("-Xlog:class+unload=info"); + checkFor(output, "[class,unload]", "unloading class"); // -Xlog:class+unload=off - pb = exec("-Xlog:class+unload=off"); - checkAbsent("[class,unload]"); + output = exec("-Xlog:class+unload=off"); + checkAbsent(output,"[class,unload]"); // -Xlog:class+load=info - pb = exec("-Xlog:class+load=info"); - checkFor("[class,load]", "java.lang.Object", "source:"); + output = exec("-Xlog:class+load=info"); + checkFor(output,"[class,load]", "java.lang.Object", "source:"); // -Xlog:class+load=debug - pb = exec("-Xlog:class+load=debug"); - checkFor("[class,load]", "java.lang.Object", "source:", "klass:", "super:", "loader:", "bytes:"); + output = exec("-Xlog:class+load=debug"); + checkFor(output,"[class,load]", "java.lang.Object", "source:", "klass:", "super:", "loader:", "bytes:"); // -Xlog:class+load=off - pb = exec("-Xlog:class+load=off"); - checkAbsent("[class,load]"); + output = exec("-Xlog:class+load=off"); + checkAbsent(output,"[class,load]"); // -verbose:class - pb = exec("-verbose:class"); - checkFor("[class,load]", "java.lang.Object", "source:"); - checkFor("[class,unload]", "unloading class"); + output = exec("-verbose:class"); + checkFor(output,"[class,load]", "java.lang.Object", "source:"); + checkFor(output,"[class,unload]", "unloading class"); // -Xlog:class+loader+data=trace - pb = exec("-Xlog:class+loader+data=trace"); - checkFor("[class,loader,data]", "create loader data"); + output = exec("-Xlog:class+loader+data=trace"); + checkFor(output, "[class,loader,data]", "create loader data"); } } From 2bd138bf94c380c652adcdb90611a992e83a7372 Mon Sep 17 00:00:00 2001 From: Daniel Hu Date: Mon, 26 Aug 2024 16:20:25 +0000 Subject: [PATCH 11/16] 8316193: jdk/jfr/event/oldobject/TestListenerLeak.java java.lang.Exception: Could not find leak Backport-of: f6be922952642f40dcf0d27b7896c9a6acdd6378 --- .../jfr/event/oldobject/TestListenerLeak.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/test/jdk/jdk/jfr/event/oldobject/TestListenerLeak.java b/test/jdk/jdk/jfr/event/oldobject/TestListenerLeak.java index 67ef11b2740..92610283525 100644 --- a/test/jdk/jdk/jfr/event/oldobject/TestListenerLeak.java +++ b/test/jdk/jdk/jfr/event/oldobject/TestListenerLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, 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 @@ -71,15 +71,17 @@ public void onListen() { public static void main(String[] args) throws Exception { WhiteBox.setWriteAllObjectSamples(true); - - try (Recording r = new Recording()) { - r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity"); - r.start(); - listenerLeak(); - r.stop(); - List events = Events.fromRecording(r); - if (OldObjects.countMatchingEvents(events, Stuff[].class, null, null, -1, "listenerLeak") == 0) { - throw new Exception("Could not find leak with " + Stuff[].class); + while (true) { + try (Recording r = new Recording()) { + r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity"); + r.start(); + listenerLeak(); + r.stop(); + List events = Events.fromRecording(r); + if (OldObjects.countMatchingEvents(events, Stuff[].class, null, null, -1, "listenerLeak") != 0) { + return; // Success + } + System.out.println("Could not find leak with " + Stuff[].class + ". Retrying."); } } } From e5800b8de333f49fdae37df598c0b9659cc744d4 Mon Sep 17 00:00:00 2001 From: Daniel Hu Date: Mon, 26 Aug 2024 16:20:47 +0000 Subject: [PATCH 12/16] 8303920: Avoid calling out to python in DataDescriptorSignatureMissing test Reviewed-by: phh Backport-of: 07eaea8c25bae6ed852685f082f8b50c5b20c1a9 --- .../zip/DataDescriptorSignatureMissing.java | 226 ++++++++++-------- 1 file changed, 120 insertions(+), 106 deletions(-) diff --git a/test/jdk/java/util/zip/DataDescriptorSignatureMissing.java b/test/jdk/java/util/zip/DataDescriptorSignatureMissing.java index f7a2ae2f8eb..db641ccba4c 100644 --- a/test/jdk/java/util/zip/DataDescriptorSignatureMissing.java +++ b/test/jdk/java/util/zip/DataDescriptorSignatureMissing.java @@ -1,5 +1,6 @@ /* * Copyright 2012 Google, Inc. All Rights Reserved. + * Copyright (c) 2023, 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 @@ -24,124 +25,137 @@ /** * @test * @bug 8056934 - * @summary Check ability to read zip files created by python zipfile - * implementation, which fails to write optional (but recommended) data - * descriptor signatures. Repro scenario is a Java -> Python -> Java round trip: - * - ZipOutputStream creates zip file with DEFLATED entries and data - * descriptors with optional signature "PK0x0708". - * - Python reads those entries, preserving the 0x08 flag byte - * - Python outputs those entries with data descriptors lacking the - * optional signature. - * - ZipInputStream cannot handle the missing signature - * + * @summary Verify the ability to read zip files whose local header + * data descriptor is missing the optional signature + *

* No way to adapt the technique in this test to get a ZIP64 zip file * without data descriptors was found. - * - * @ignore This test has brittle dependencies on an external working python. + * @run junit DataDescriptorSignatureMissing */ + +import org.junit.jupiter.api.Test; + import java.io.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; import java.util.zip.*; -public class DataDescriptorSignatureMissing { - void printStream(InputStream is) throws IOException { - Reader r = new InputStreamReader(is); - StringBuilder sb = new StringBuilder(); - char[] buf = new char[1024]; - int n; - while ((n = r.read(buf)) > 0) { - sb.append(buf, 0, n); - } - System.out.print(sb); - } +import static org.junit.jupiter.api.Assertions.*; + +public class DataDescriptorSignatureMissing { + + /** + * Verify that ZipInputStream correctly parses a ZIP with a Data Descriptor without + * the recommended but optional signature. + */ + @Test + public void shouldParseSignaturelessDescriptor() throws IOException { + // The ZIP with a signature-less descriptor + byte[] zip = makeZipWithSignaturelessDescriptor(); - int entryCount(File zipFile) throws IOException { - try (FileInputStream fis = new FileInputStream(zipFile); - ZipInputStream zis = new ZipInputStream(fis)) { - for (int count = 0;; count++) - if (zis.getNextEntry() == null) - return count; + // ZipInputStream should read the signature-less data descriptor + try (ZipInputStream in = new ZipInputStream( + new ByteArrayInputStream(zip))) { + ZipEntry first = in.getNextEntry(); + assertNotNull(first, "Zip file is unexpectedly missing first entry"); + assertEquals("first", first.getName()); + assertArrayEquals("first".getBytes(StandardCharsets.UTF_8), in.readAllBytes()); + + ZipEntry second = in.getNextEntry(); + assertNotNull(second, "Zip file is unexpectedly missing second entry"); + assertEquals("second", second.getName()); + assertArrayEquals("second".getBytes(StandardCharsets.UTF_8), in.readAllBytes()); } + } - void test(String[] args) throws Throwable { - if (! new File("/usr/bin/python").canExecute()) - return; - - // Create a java zip file with DEFLATED entries and data - // descriptors with signatures. - final File in = new File("in.zip"); - final File out = new File("out.zip"); - final int count = 3; - try (FileOutputStream fos = new FileOutputStream(in); - ZipOutputStream zos = new ZipOutputStream(fos)) { - for (int i = 0; i < count; i++) { - ZipEntry ze = new ZipEntry("hello.python" + i); - ze.setMethod(ZipEntry.DEFLATED); - zos.putNextEntry(ze); - zos.write(new byte[10]); - zos.closeEntry(); - } + /** + * The 'Data descriptor' record is used to facilitate ZIP streaming. If the size of an + * entry is unknown at the time the LOC header is written, bit 3 of the General Purpose Bit Flag + * is set, and the File data is immediately followed by the 'Data descriptor' record. This record + * then contains the compressed and uncompressed sizes of the entry and also the CRC value. + * + * The 'Data descriptor' record is usually preceded by the recommended, but optional + * signature value 0x08074b50. + * + * A ZIP entry in streaming mode has the following structure: + * + * ------ Local File Header ------ + * 000000 signature 0x04034b50 + * 000004 version 20 + * 000006 flags 0x0808 # Notice bit 3 is set + * [..] Omitted for brevity + * + * ------ File Data ------ + * 000035 data 7 bytes + * + * ------ Data Descriptor ------ + * 000042 signature 0x08074b50 + * 000046 crc 0x3610a686 + * 000050 csize 7 + * 000054 size 5 + * + * A signature-less data descriptor will look like the following: + * + * ------ Data Descriptor ------ + * 000042 crc 0x3610a686 + * 000046 csize 7 + * 000050 size 5 + * + * This method produces a ZIP with two entries, where the first entry + * is made signature-less. + */ + private static byte[] makeZipWithSignaturelessDescriptor() throws IOException { + // Offset of the signed data descriptor + int sigOffset; + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try (ZipOutputStream zo = new ZipOutputStream(out)) { + // Write a first entry + zo.putNextEntry(new ZipEntry("first")); + zo.write("first".getBytes(StandardCharsets.UTF_8)); + // Force the data descriptor to be written out + zo.closeEntry(); + // Signed data descriptor starts 16 bytes before current offset + sigOffset = out.size() - 4 * Integer.BYTES; + // Add a second entry + zo.putNextEntry(new ZipEntry("second")); + zo.write("second".getBytes(StandardCharsets.UTF_8)); } - // Copy the zip file using python's zipfile module - String[] python_program_lines = { - "import os", - "import zipfile", - "input_zip = zipfile.ZipFile('in.zip', mode='r')", - "output_zip = zipfile.ZipFile('out.zip', mode='w')", - "count08 = 0", - "for input_info in input_zip.infolist():", - " output_info = input_info", - " if output_info.flag_bits & 0x08 == 0x08:", - " count08 += 1", - " output_zip.writestr(output_info, input_zip.read(input_info))", - "output_zip.close()", - "if count08 == 0:", - " raise ValueError('Expected to see entries with 0x08 flag_bits set')", - }; - StringBuilder python_program_builder = new StringBuilder(); - for (String line : python_program_lines) - python_program_builder.append(line).append('\n'); - String python_program = python_program_builder.toString(); - String[] cmdline = { "/usr/bin/python", "-c", python_program }; - ProcessBuilder pb = new ProcessBuilder(cmdline); - pb.redirectErrorStream(true); - Process p = pb.start(); - printStream(p.getInputStream()); - p.waitFor(); - equal(p.exitValue(), 0); - - File pythonZipFile = new File("out.zip"); - check(pythonZipFile.exists()); - - equal(entryCount(in), - entryCount(out)); - - // We expect out to be identical to in, except for the removal of - // the optional data descriptor signatures. - final int SIG_LENGTH = 4; // length of a zip signature - PKxx - equal(in.length(), - out.length() + SIG_LENGTH * count); - - in.delete(); - out.delete(); - } + // The generated ZIP file with a signed data descriptor + byte[] sigZip = out.toByteArray(); + + // The offset of the CRC immediately following the 4-byte signature + int crcOffset = sigOffset + Integer.BYTES; + + // Create a ZIP file with a signature-less data descriptor for the first entry + ByteArrayOutputStream sigLess = new ByteArrayOutputStream(); + sigLess.write(sigZip, 0, sigOffset); + // Skip the signature + sigLess.write(sigZip, crcOffset, sigZip.length - crcOffset); + + byte[] siglessZip = sigLess.toByteArray(); - //--------------------- Infrastructure --------------------------- - volatile int passed = 0, failed = 0; - void pass() {passed++;} - void fail() {failed++; Thread.dumpStack();} - void fail(String msg) {System.err.println(msg); fail();} - void unexpected(Throwable t) {failed++; t.printStackTrace();} - void check(boolean cond) {if (cond) pass(); else fail();} - void equal(Object x, Object y) { - if (x == null ? y == null : x.equals(y)) pass(); - else fail(x + " not equal to " + y);} - public static void main(String[] args) throws Throwable { - new DataDescriptorSignatureMissing().instanceMain(args);} - public void instanceMain(String[] args) throws Throwable { - try {test(args);} catch (Throwable t) {unexpected(t);} - System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); - if (failed > 0) throw new AssertionError("Some tests failed");} + // Adjust the CEN offset in the END header + ByteBuffer buffer = ByteBuffer.wrap(siglessZip).order(ByteOrder.LITTLE_ENDIAN); + // Reduce cenOffset by 4 bytes + int cenOff = siglessZip.length - ZipFile.ENDHDR + ZipFile.ENDOFF; + int realCenOff = buffer.getInt(cenOff) - Integer.BYTES; + buffer.putInt(cenOff, realCenOff); + + // Adjust the LOC offset in the second CEN header + int cen = realCenOff; + // Skip past the first CEN header + int nlen = buffer.getShort(cen + ZipFile.CENNAM); + cen += ZipFile.CENHDR + nlen; + + // Reduce LOC offset by 4 bytes + int locOff = cen + ZipFile.CENOFF; + buffer.putInt(locOff, buffer.getInt(locOff) - Integer.BYTES); + + return siglessZip; + } } From 6ccff7f7240087f50705aa70608d3b1a3ed8be79 Mon Sep 17 00:00:00 2001 From: Amos Shi Date: Mon, 26 Aug 2024 17:28:40 +0000 Subject: [PATCH 13/16] 8332248: (fc) java/nio/channels/FileChannel/BlockDeviceSize.java failed with RuntimeException Backport-of: 0bb5ae645165b97527ecccf02308df6072c363d8 --- test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java b/test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java index 7d430693b2f..84e0bf0dd39 100644 --- a/test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java +++ b/test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java @@ -25,6 +25,7 @@ * @bug 8054029 * @requires (os.family == "linux") * @summary FileChannel.size() should be equal to RandomAccessFile.size() and > 0 for block devs on Linux + * @library /test/lib */ import java.io.RandomAccessFile; @@ -36,6 +37,7 @@ import static java.nio.file.StandardOpenOption.*; +import jtreg.SkippedException; public class BlockDeviceSize { private static final List BLK_FNAMES = List.of("/dev/sda1", "/dev/nvme0n1", "/dev/xvda1") ; @@ -61,7 +63,7 @@ public static void main(String[] args) throws Throwable { System.err.println("File " + blkFname + " not found." + " Skipping test"); } catch (AccessDeniedException ade) { - throw new RuntimeException("Access to " + blkFname + " is denied." + throw new SkippedException("Access to " + blkFname + " is denied." + " Run test as root.", ade); } From fff35ed6f64bc9eb75601dbc4aa4a51176004206 Mon Sep 17 00:00:00 2001 From: Amos Shi Date: Mon, 26 Aug 2024 18:48:09 +0000 Subject: [PATCH 14/16] 8310683: Refactor StandardCharset/standard.java to use JUnit Backport-of: 4e84d4dc514192e4cdf8e2c7c474847832987ab9 --- .../charset/StandardCharsets/Standard.java | 179 ++++++++++-------- 1 file changed, 100 insertions(+), 79 deletions(-) diff --git a/test/jdk/java/nio/charset/StandardCharsets/Standard.java b/test/jdk/java/nio/charset/StandardCharsets/Standard.java index 44c4e86a4f6..4db24b1986a 100644 --- a/test/jdk/java/nio/charset/StandardCharsets/Standard.java +++ b/test/jdk/java/nio/charset/StandardCharsets/Standard.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, 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 @@ -23,102 +23,123 @@ /* * @test - * @bug 4884238 - * @summary Test standard charset name constants. + * @bug 4884238 8310047 + * @summary Test standard charset name constants and class qualities. * @author Mike Duigou - * @run main Standard + * @run junit Standard */ import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.io.*; -import java.nio.charset.*; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; +import java.util.List; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class Standard { - private final static String standardCharsets[] = { - "US-ASCII", "ISO-8859-1", "UTF-8", - "UTF-16BE", "UTF-16LE", "UTF-16" }; + // These are the charsets StandardCharsets.java is expected to contain. + private static final String[] expectedCharsets = { + "US-ASCII", "ISO-8859-1", "UTF-8", + "UTF-16BE", "UTF-16LE", "UTF-16" + }; - public static void realMain(String[] args) { - check(StandardCharsets.US_ASCII instanceof Charset); - check(StandardCharsets.ISO_8859_1 instanceof Charset); - check(StandardCharsets.UTF_8 instanceof Charset); - check(StandardCharsets.UTF_16BE instanceof Charset); - check(StandardCharsets.UTF_16LE instanceof Charset); - check(StandardCharsets.UTF_16 instanceof Charset); + private static final Field[] standardCharsetFields = + StandardCharsets.class.getFields(); - check("US-ASCII".equals(StandardCharsets.US_ASCII.name())); - check("ISO-8859-1".equals(StandardCharsets.ISO_8859_1.name())); - check("UTF-8".equals(StandardCharsets.UTF_8.name())); - check("UTF-16BE".equals(StandardCharsets.UTF_16BE.name())); - check("UTF-16LE".equals(StandardCharsets.UTF_16LE.name())); - check("UTF-16".equals(StandardCharsets.UTF_16.name())); + /** + * Validates that the Charset constants from the data provider + * are of type Charset. + */ + @ParameterizedTest + @MethodSource("charsetProvider") + public void typeTest(Charset charset) { + // Doubly checked, as it is validated when passed as a param + assertTrue(charset instanceof Charset); + } + + /** + * Validates that calling .name() on a Charset constant is equal + * to the matching String value from the data provider. + */ + @ParameterizedTest + @MethodSource("charsetProvider") + public void nameMethodTest(Charset charset, String charString) { + assertEquals(charset.name(), charString); + } - check(Charset.forName("US-ASCII") == StandardCharsets.US_ASCII); - check(Charset.forName("ISO-8859-1") == StandardCharsets.ISO_8859_1); - check(Charset.forName("UTF-8") == StandardCharsets.UTF_8); - check(Charset.forName("UTF-16BE") == StandardCharsets.UTF_16BE); - check(Charset.forName("UTF-16LE") == StandardCharsets.UTF_16LE); - check(Charset.forName("UTF-16") == StandardCharsets.UTF_16); + /** + * Validates that calling Charset.forName() on a String is equal + * to the matching Charset constant from the data provider. + */ + @ParameterizedTest + @MethodSource("charsetProvider") + public void forNameMethodTest(Charset charset, String charString) { + assertEquals(Charset.forName(charString), charset); + } - Set charsets = new HashSet<>(); - Field standardCharsetFields[] = StandardCharsets.class.getFields(); + /** + * Validates the qualities of a StandardCharsets field are as expected: + * The field is final, static, public, and one can access + * the underlying value of the field. + */ + @ParameterizedTest + @MethodSource("charsetFields") + public void charsetModifiersTest(Field charsetField) throws IllegalAccessException { + // Check modifiers + assertEquals(StandardCharsets.class, charsetField.getDeclaringClass()); + assertTrue(Modifier.isFinal(charsetField.getModifiers())); + assertTrue(Modifier.isStatic(charsetField.getModifiers())); + assertTrue(Modifier.isPublic(charsetField.getModifiers())); + // Check that the value can be accessed, and it is a Charset + Object valueOfField = charsetField.get(null); + assertTrue(valueOfField instanceof Charset); + } - for(Field charsetField : standardCharsetFields) { - check(StandardCharsets.class == charsetField.getDeclaringClass()); - check(Modifier.isFinal(charsetField.getModifiers())); - check(Modifier.isStatic(charsetField.getModifiers())); - check(Modifier.isPublic(charsetField.getModifiers())); - Object value; + /** + * Validates that the Charsets contained in StandardCharsets are equal + * to the expected Charsets list defined in the test. This test should fail if + * either the actual or expected (standard) Charsets are modified, and + * the others are not. + */ + @Test + public void correctCharsetsTest() { + // Grab the value from each Standard Charset field + List actualCharsets = charsetFields().map(field -> { try { - value = charsetField.get(null); - } catch(IllegalAccessException failure) { - unexpected(failure); - continue; + return ((Charset) field.get(null)).name(); + } catch (IllegalAccessException e) { + throw new RuntimeException("Can not test correctCharsetsTest() due to %s", e); } - check(value instanceof Charset); - charsets.add(((Charset)value).name()); - } - - check(charsets.containsAll(Arrays.asList(standardCharsets))); - charsets.removeAll(Arrays.asList(standardCharsets)); - check(charsets.isEmpty()); + }).toList(); + assertEquals(actualCharsets, Arrays.asList(expectedCharsets)); } - //--------------------- Infrastructure --------------------------- - static volatile int passed = 0, failed = 0; - static void pass() { passed++; } - static void fail() { failed++; Thread.dumpStack(); } - static void fail(String msg) { System.out.println(msg); fail(); } - static void unexpected(Throwable t) { failed++; t.printStackTrace(); } - static void check(boolean cond) { if (cond) pass(); else fail(); } - static void equal(Object x, Object y) { - if (x == null ? y == null : x.equals(y)) pass(); - else {System.out.println(x + " not equal to " + y); fail();}} - static void equal2(Object x, Object y) {equal(x, y); equal(y, x);} - public static void main(String[] args) throws Throwable { - try { realMain(args); } catch (Throwable t) { unexpected(t); } - - System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); - if (failed > 0) throw new Exception("Some tests failed"); + /** + * Provides the constant Charset and associated String value of + * the standard charsets. + */ + private static Stream charsetProvider() { + return Stream.of( + Arguments.of(StandardCharsets.US_ASCII, "US-ASCII"), + Arguments.of(StandardCharsets.ISO_8859_1, "ISO-8859-1"), + Arguments.of(StandardCharsets.UTF_8, "UTF-8"), + Arguments.of(StandardCharsets.UTF_16BE, "UTF-16BE"), + Arguments.of(StandardCharsets.UTF_16LE, "UTF-16LE"), + Arguments.of(StandardCharsets.UTF_16, "UTF-16") + ); } - static byte[] serializedForm(Object obj) { - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - new ObjectOutputStream(baos).writeObject(obj); - return baos.toByteArray(); - } catch (IOException e) { throw new Error(e); }} - static Object readObject(byte[] bytes) - throws IOException, ClassNotFoundException { - InputStream is = new ByteArrayInputStream(bytes); - return new ObjectInputStream(is).readObject();} - @SuppressWarnings("unchecked") - static T serialClone(T obj) { - try { return (T) readObject(serializedForm(obj)); } - catch (Exception e) { throw new Error(e); }} + private static Stream charsetFields() { + return Arrays.stream(standardCharsetFields); + } } From ba98d8bf983ef3057102503379c1258ef5d1940c Mon Sep 17 00:00:00 2001 From: Amos Shi Date: Mon, 26 Aug 2024 18:49:44 +0000 Subject: [PATCH 15/16] 8302800: Augment NaN handling tests of FDLIBM methods Reviewed-by: mbaesken Backport-of: dfce4e1943f2f95b74b5a9cdde9d738dcffd0b43 --- test/jdk/java/lang/Math/CubeRootTests.java | 25 ++- test/jdk/java/lang/Math/Expm1Tests.java | 24 ++- test/jdk/java/lang/Math/HyperbolicTests.java | 52 ++--- test/jdk/java/lang/Math/InverseTrigTests.java | 187 ++++++++++++++++++ test/jdk/java/lang/Math/Log10Tests.java | 36 ++-- test/jdk/java/lang/Math/Log1pTests.java | 21 +- test/jdk/java/lang/Math/Tests.java | 35 +++- 7 files changed, 286 insertions(+), 94 deletions(-) create mode 100644 test/jdk/java/lang/Math/InverseTrigTests.java diff --git a/test/jdk/java/lang/Math/CubeRootTests.java b/test/jdk/java/lang/Math/CubeRootTests.java index a6350702d90..9347160d719 100644 --- a/test/jdk/java/lang/Math/CubeRootTests.java +++ b/test/jdk/java/lang/Math/CubeRootTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, 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 @@ -25,6 +25,7 @@ * @test * @library /test/lib * @build jdk.test.lib.RandomFactory + * @build Tests * @run main CubeRootTests * @bug 4347132 4939441 8078672 * @summary Tests for {Math, StrictMath}.cbrt (use -Dseed=X to set PRNG seed) @@ -32,6 +33,7 @@ */ import jdk.test.lib.RandomFactory; +import static java.lang.Double.longBitsToDouble; public class CubeRootTests { private CubeRootTests(){} @@ -42,7 +44,7 @@ private CubeRootTests(){} // Initialize shared random number generator static java.util.Random rand = RandomFactory.getRandom(); - static int testCubeRootCase(double input, double expected) { + private static int testCubeRootCase(double input, double expected) { int failures=0; failures+=Tests.test("Math.cbrt", input, Math::cbrt, expected); @@ -53,22 +55,17 @@ static int testCubeRootCase(double input, double expected) { return failures; } - static int testCubeRoot() { + private static int testCubeRoot() { int failures = 0; + + for(double nan : Tests.NaNs) { + failures += testCubeRootCase(nan, NaNd); + } + double [][] testCases = { - {NaNd, NaNd}, - {Double.longBitsToDouble(0x7FF0000000000001L), NaNd}, - {Double.longBitsToDouble(0xFFF0000000000001L), NaNd}, - {Double.longBitsToDouble(0x7FF8555555555555L), NaNd}, - {Double.longBitsToDouble(0xFFF8555555555555L), NaNd}, - {Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), NaNd}, - {Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), NaNd}, - {Double.longBitsToDouble(0x7FFDeadBeef00000L), NaNd}, - {Double.longBitsToDouble(0xFFFDeadBeef00000L), NaNd}, - {Double.longBitsToDouble(0x7FFCafeBabe00000L), NaNd}, - {Double.longBitsToDouble(0xFFFCafeBabe00000L), NaNd}, {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY}, {Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY}, + {+0.0, +0.0}, {-0.0, -0.0}, {+1.0, +1.0}, diff --git a/test/jdk/java/lang/Math/Expm1Tests.java b/test/jdk/java/lang/Math/Expm1Tests.java index 204fe44ef15..61f02acfe21 100644 --- a/test/jdk/java/lang/Math/Expm1Tests.java +++ b/test/jdk/java/lang/Math/Expm1Tests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, 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 @@ -24,9 +24,14 @@ /* * @test * @bug 4851638 4900189 4939441 + * @build Tests + * @build Expm1Tests + * @run main Expm1Tests * @summary Tests for {Math, StrictMath}.expm1 */ +import static java.lang.Double.longBitsToDouble; + /* * The Taylor expansion of expxm1(x) = exp(x) -1 is * @@ -48,21 +53,14 @@ private Expm1Tests(){} static final double infinityD = Double.POSITIVE_INFINITY; static final double NaNd = Double.NaN; - static int testExpm1() { + private static int testExpm1() { int failures = 0; + for(double nan : Tests.NaNs) { + failures += testExpm1Case(nan, NaNd); + } + double [][] testCases = { - {Double.NaN, NaNd}, - {Double.longBitsToDouble(0x7FF0000000000001L), NaNd}, - {Double.longBitsToDouble(0xFFF0000000000001L), NaNd}, - {Double.longBitsToDouble(0x7FF8555555555555L), NaNd}, - {Double.longBitsToDouble(0xFFF8555555555555L), NaNd}, - {Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), NaNd}, - {Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), NaNd}, - {Double.longBitsToDouble(0x7FFDeadBeef00000L), NaNd}, - {Double.longBitsToDouble(0xFFFDeadBeef00000L), NaNd}, - {Double.longBitsToDouble(0x7FFCafeBabe00000L), NaNd}, - {Double.longBitsToDouble(0xFFFCafeBabe00000L), NaNd}, {infinityD, infinityD}, {-infinityD, -1.0}, {-0.0, -0.0}, diff --git a/test/jdk/java/lang/Math/HyperbolicTests.java b/test/jdk/java/lang/Math/HyperbolicTests.java index 8309606f63d..c0ce8f49ef3 100644 --- a/test/jdk/java/lang/Math/HyperbolicTests.java +++ b/test/jdk/java/lang/Math/HyperbolicTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, 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 @@ -24,9 +24,14 @@ /* * @test * @bug 4851625 4900189 4939441 + * @build Tests + * @build HyperbolicTests + * @run main HyperbolicTests * @summary Tests for {Math, StrictMath}.{sinh, cosh, tanh} */ +import static java.lang.Double.longBitsToDouble; + public class HyperbolicTests { private HyperbolicTests(){} @@ -248,19 +253,12 @@ static int testSinh() { 3.0); } + for(double nan : Tests.NaNs) { + failures += testSinhCaseWithUlpDiff(nan, NaNd, 0); + } + double [][] specialTestCases = { {0.0, 0.0}, - {NaNd, NaNd}, - {Double.longBitsToDouble(0x7FF0000000000001L), NaNd}, - {Double.longBitsToDouble(0xFFF0000000000001L), NaNd}, - {Double.longBitsToDouble(0x7FF8555555555555L), NaNd}, - {Double.longBitsToDouble(0xFFF8555555555555L), NaNd}, - {Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), NaNd}, - {Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), NaNd}, - {Double.longBitsToDouble(0x7FFDeadBeef00000L), NaNd}, - {Double.longBitsToDouble(0xFFFDeadBeef00000L), NaNd}, - {Double.longBitsToDouble(0x7FFCafeBabe00000L), NaNd}, - {Double.longBitsToDouble(0xFFFCafeBabe00000L), NaNd}, {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY} }; @@ -590,19 +588,12 @@ static int testCosh() { 3.0); } + for(double nan : Tests.NaNs) { + failures += testCoshCaseWithUlpDiff(nan, NaNd, 0); + } + double [][] specialTestCases = { {0.0, 1.0}, - {NaNd, NaNd}, - {Double.longBitsToDouble(0x7FF0000000000001L), NaNd}, - {Double.longBitsToDouble(0xFFF0000000000001L), NaNd}, - {Double.longBitsToDouble(0x7FF8555555555555L), NaNd}, - {Double.longBitsToDouble(0xFFF8555555555555L), NaNd}, - {Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), NaNd}, - {Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), NaNd}, - {Double.longBitsToDouble(0x7FFDeadBeef00000L), NaNd}, - {Double.longBitsToDouble(0xFFFDeadBeef00000L), NaNd}, - {Double.longBitsToDouble(0x7FFCafeBabe00000L), NaNd}, - {Double.longBitsToDouble(0xFFFCafeBabe00000L), NaNd}, {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY} }; @@ -938,19 +929,12 @@ static int testTanh() { 3.0); } + for(double nan : Tests.NaNs) { + failures += testTanhCaseWithUlpDiff(nan, NaNd, 0); + } + double [][] specialTestCases = { {0.0, 0.0}, - {NaNd, NaNd}, - {Double.longBitsToDouble(0x7FF0000000000001L), NaNd}, - {Double.longBitsToDouble(0xFFF0000000000001L), NaNd}, - {Double.longBitsToDouble(0x7FF8555555555555L), NaNd}, - {Double.longBitsToDouble(0xFFF8555555555555L), NaNd}, - {Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), NaNd}, - {Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), NaNd}, - {Double.longBitsToDouble(0x7FFDeadBeef00000L), NaNd}, - {Double.longBitsToDouble(0xFFFDeadBeef00000L), NaNd}, - {Double.longBitsToDouble(0x7FFCafeBabe00000L), NaNd}, - {Double.longBitsToDouble(0xFFFCafeBabe00000L), NaNd}, {Double.POSITIVE_INFINITY, 1.0} }; diff --git a/test/jdk/java/lang/Math/InverseTrigTests.java b/test/jdk/java/lang/Math/InverseTrigTests.java new file mode 100644 index 00000000000..f533b509d3d --- /dev/null +++ b/test/jdk/java/lang/Math/InverseTrigTests.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2003, 2023, 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 + * @bug 8302026 + * @build Tests + * @build InverseTrigTests + * @run main InverseTrigTests + * @summary Tests for {Math, StrictMath}.{asin, acos, atan} + */ + +import static java.lang.Double.longBitsToDouble; + +public class InverseTrigTests { + private InverseTrigTests(){} + + public static void main(String... args) { + int failures = 0; + + failures += testAsinSpecialCases(); + failures += testAcosSpecialCases(); + failures += testAtanSpecialCases(); + + if (failures > 0) { + System.err.println("Testing inverse trig mthods incurred " + + failures + " failures."); + throw new RuntimeException(); + } + } + + private static final double InfinityD = Double.POSITIVE_INFINITY; + private static final double NaNd = Double.NaN; + + /** + * From the spec for Math.asin: + * + * "Special cases: + * + * If the argument is NaN or its absolute value is greater than 1, + * then the result is NaN. + * + * If the argument is zero, then the result is a zero with the + * same sign as the argument." + */ + private static int testAsinSpecialCases() { + int failures = 0; + + for(double nan : Tests.NaNs) { + failures += testAsinCase(nan, NaNd); + } + + double [][] testCases = { + {Math.nextUp(1.0), NaNd}, + {Math.nextDown(-1.0), NaNd}, + { InfinityD, NaNd}, + {-InfinityD, NaNd}, + + {-0.0, -0.0}, + {+0.0, +0.0}, + }; + + for(int i = 0; i < testCases.length; i++) { + failures += testAsinCase(testCases[i][0], + testCases[i][1]); + } + + return failures; + } + + private static int testAsinCase(double input, double expected) { + int failures=0; + + failures += Tests.test("Math.asin", input, Math::asin, expected); + failures += Tests.test("StrictMath.asin", input, StrictMath::asin, expected); + + return failures; + } + + /** + * From the spec for Math.acos: + * + * "Special case: + * + * If the argument is NaN or its absolute value is greater than 1, + * then the result is NaN. + * + * If the argument is 1.0, the result is positive zero." + */ + private static int testAcosSpecialCases() { + int failures = 0; + + for(double nan : Tests.NaNs) { + failures += testAcosCase(nan, NaNd); + } + + double [][] testCases = { + {Math.nextUp(1.0), NaNd}, + {Math.nextDown(-1.0), NaNd}, + {InfinityD, NaNd}, + {-InfinityD, NaNd}, + + {1.0, +0.0}, + }; + + for(int i = 0; i < testCases.length; i++) { + failures += testAcosCase(testCases[i][0], + testCases[i][1]); + } + + return failures; + } + + private static int testAcosCase(double input, double expected) { + int failures=0; + + failures += Tests.test("Math.acos", input, Math::acos, expected); + failures += Tests.test("StrictMath.acos", input, StrictMath::acos, expected); + + return failures; + } + + /** + * From the spec for Math.atan: + * + * "Special cases: + * + * If the argument is NaN, then the result is NaN. + * + * If the argument is zero, then the result is a zero with the + * same sign as the argument. + * + * If the argument is infinite, then the result is the closest + * value to pi/2 with the same sign as the input." + */ + private static int testAtanSpecialCases() { + int failures = 0; + + for(double nan : Tests.NaNs) { + failures += testAtanCase(nan, NaNd); + } + + double [][] testCases = { + {-0.0, -0.0}, + {+0.0, +0.0}, + + { InfinityD, +Math.PI/2.0}, + {-InfinityD, -Math.PI/2.0}, + }; + + for(int i = 0; i < testCases.length; i++) { + failures += testAtanCase(testCases[i][0], + testCases[i][1]); + } + + return failures; + } + + private static int testAtanCase(double input, double expected) { + int failures=0; + + failures += Tests.test("Math.atan", input, Math::atan, expected); + failures += Tests.test("StrictMath.atan", input, StrictMath::atan, expected); + + return failures; + } +} diff --git a/test/jdk/java/lang/Math/Log10Tests.java b/test/jdk/java/lang/Math/Log10Tests.java index dbdd7c14179..f53004ca0bc 100644 --- a/test/jdk/java/lang/Math/Log10Tests.java +++ b/test/jdk/java/lang/Math/Log10Tests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, 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 @@ -24,43 +24,41 @@ /* * @test * @bug 4074599 4939441 + * @build Tests + * @build Log10Tests + * @run main Log10Tests * @summary Tests for {Math, StrictMath}.log10 */ +import static java.lang.Double.longBitsToDouble; + public class Log10Tests { private Log10Tests(){} - static final double infinityD = Double.POSITIVE_INFINITY; - static final double NaNd = Double.NaN; - static final double LN_10 = StrictMath.log(10.0); + private static final double infinityD = Double.POSITIVE_INFINITY; + private static final double NaNd = Double.NaN; + private static final double LN_10 = StrictMath.log(10.0); // Initialize shared random number generator static java.util.Random rand = new java.util.Random(0L); - static int testLog10Case(double input, double expected) { + private static int testLog10Case(double input, double expected) { int failures=0; - failures+=Tests.test("Math.log10", input, Math::log10, expected); - failures+=Tests.test("StrictMath.log10", input, StrictMath::log10, expected); + failures += Tests.test("Math.log10", input, Math::log10, expected); + failures += Tests.test("StrictMath.log10", input, StrictMath::log10, expected); return failures; } - static int testLog10() { + private static int testLog10() { int failures = 0; + for(double nan : Tests.NaNs) { + failures += testLog10Case(nan, NaNd); + } + double [][] testCases = { - {Double.NaN, NaNd}, - {Double.longBitsToDouble(0x7FF0000000000001L), NaNd}, - {Double.longBitsToDouble(0xFFF0000000000001L), NaNd}, - {Double.longBitsToDouble(0x7FF8555555555555L), NaNd}, - {Double.longBitsToDouble(0xFFF8555555555555L), NaNd}, - {Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), NaNd}, - {Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), NaNd}, - {Double.longBitsToDouble(0x7FFDeadBeef00000L), NaNd}, - {Double.longBitsToDouble(0xFFFDeadBeef00000L), NaNd}, - {Double.longBitsToDouble(0x7FFCafeBabe00000L), NaNd}, - {Double.longBitsToDouble(0xFFFCafeBabe00000L), NaNd}, {Double.NEGATIVE_INFINITY, NaNd}, {-8.0, NaNd}, {-1.0, NaNd}, diff --git a/test/jdk/java/lang/Math/Log1pTests.java b/test/jdk/java/lang/Math/Log1pTests.java index 2fa7ddec442..89412fc971e 100644 --- a/test/jdk/java/lang/Math/Log1pTests.java +++ b/test/jdk/java/lang/Math/Log1pTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, 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 @@ -25,6 +25,8 @@ * @test * @library /test/lib * @build jdk.test.lib.RandomFactory + * @build Tests + * @build Log1pTests * @run main Log1pTests * @bug 4851638 4939441 8078672 * @summary Tests for {Math, StrictMath}.log1p (use -Dseed=X to set PRNG seed) @@ -59,21 +61,14 @@ static double hp15cLogp(double x) { * Also x/(x+1) < ln(1+x) < x */ - static int testLog1p() { + private static int testLog1p() { int failures = 0; + for(double nan : Tests.NaNs) { + failures += testLog1pCase(nan, NaNd); + } + double [][] testCases = { - {Double.NaN, NaNd}, - {Double.longBitsToDouble(0x7FF0000000000001L), NaNd}, - {Double.longBitsToDouble(0xFFF0000000000001L), NaNd}, - {Double.longBitsToDouble(0x7FF8555555555555L), NaNd}, - {Double.longBitsToDouble(0xFFF8555555555555L), NaNd}, - {Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), NaNd}, - {Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), NaNd}, - {Double.longBitsToDouble(0x7FFDeadBeef00000L), NaNd}, - {Double.longBitsToDouble(0xFFFDeadBeef00000L), NaNd}, - {Double.longBitsToDouble(0x7FFCafeBabe00000L), NaNd}, - {Double.longBitsToDouble(0xFFFCafeBabe00000L), NaNd}, {Double.NEGATIVE_INFINITY, NaNd}, {-8.0, NaNd}, {-1.0, -infinityD}, diff --git a/test/jdk/java/lang/Math/Tests.java b/test/jdk/java/lang/Math/Tests.java index f1de6319a9e..60981e318e2 100644 --- a/test/jdk/java/lang/Math/Tests.java +++ b/test/jdk/java/lang/Math/Tests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, 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 @@ -24,6 +24,7 @@ import java.util.function.DoubleBinaryOperator; import java.util.function.DoubleUnaryOperator; import java.util.function.DoubleToIntFunction; +import static java.lang.Double.longBitsToDouble; /* * Shared static test methods for numerical tests. Sharing these @@ -37,6 +38,38 @@ public class Tests { private Tests(){}; // do not instantiate + // Used to create a NaN value at runtime; mark as volatile to foil + // compile-time constant folding. + static volatile double zero = 0.0; + + private static final double PLATFORM_NAN = zero / zero; + + public static final double[] NaNs = { + Double.NaN, + PLATFORM_NAN, + bitwiseNegate(PLATFORM_NAN), + // Exotic NaN bit patterns. Includes values that would + // *not* be considered a NaN if only the high-order + // 32-bits were examined. + longBitsToDouble(0x7FF0_0000_0000_0001L), + longBitsToDouble(0xFFF0_0000_0000_0001L), + longBitsToDouble(0x7FF8_5555_5555_5555L), + longBitsToDouble(0xFFF8_5555_5555_5555L), + longBitsToDouble(0x7FFF_FFFF_FFFF_FFFFL), + longBitsToDouble(0xFFFF_FFFF_FFFF_FFFFL), + longBitsToDouble(0x7FF0_0000_7FFF_FFFFL), + longBitsToDouble(0xFFF0_0000_7FFF_FFFFL), + longBitsToDouble(0x7FF0_Dead_Beef_0000L), + longBitsToDouble(0xFFF0_Dead_Beef_0000L), + longBitsToDouble(0x7FF0_Cafe_Babe_0000L), + longBitsToDouble(0xFFF0_Cafe_Babe_0000L), + }; + + public static double bitwiseNegate(double d) { + long SIGNBIT = 0x8000_0000_0000_0000L; + return longBitsToDouble(Double.doubleToRawLongBits(d) ^ SIGNBIT ); + } + public static String toHexString(float f) { if (!Float.isNaN(f)) return Float.toHexString(f); From 5fef984e1136d727e82cc8c1f12b731eb9dbe2e2 Mon Sep 17 00:00:00 2001 From: Amos Shi Date: Mon, 26 Aug 2024 18:50:06 +0000 Subject: [PATCH 16/16] 8315024: Vector API FP reduction tests should not test for exact equality Reviewed-by: mdoerr Backport-of: e6f23a90d4a53339a3c9c2b76fc5d317940e4472 --- .../vector/Double128VectorTests.java | 47 +++++++++++---- .../vector/Double256VectorTests.java | 47 +++++++++++---- .../vector/Double512VectorTests.java | 47 +++++++++++---- .../incubator/vector/Double64VectorTests.java | 47 +++++++++++---- .../vector/DoubleMaxVectorTests.java | 48 ++++++++++++---- .../incubator/vector/Float128VectorTests.java | 47 +++++++++++---- .../incubator/vector/Float256VectorTests.java | 47 +++++++++++---- .../incubator/vector/Float512VectorTests.java | 47 +++++++++++---- .../incubator/vector/Float64VectorTests.java | 47 +++++++++++---- .../incubator/vector/FloatMaxVectorTests.java | 48 ++++++++++++---- .../Unit-Reduction-Masked-op.template | 4 ++ .../templates/Unit-Reduction-op.template | 4 ++ .../vector/templates/Unit-header.template | 57 +++++++++++++++++++ 13 files changed, 417 insertions(+), 120 deletions(-) diff --git a/test/jdk/jdk/incubator/vector/Double128VectorTests.java b/test/jdk/jdk/incubator/vector/Double128VectorTests.java index b00b0cbaaab..bf9c717cc59 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorTests.java @@ -59,6 +59,8 @@ public class Double128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); @@ -118,15 +120,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (double)0.0); + } + + static void assertReductionArraysEquals(double[] r, double rc, double[] a, + FReductionOp f, FReductionAllOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -140,15 +148,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (double)0.0); + } + + static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -986,6 +1001,14 @@ static long bits(double e) { return fill(s * BUFFER_REPS, i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1))); }), + withToString("double[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)0.01 + ((double)i / (i + 1))); + }), + withToString("double[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (double)0.01 + ((double)i / (i + 1))); + }), withToString("double[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2135,7 +2158,7 @@ static void ADDReduceDouble128VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double128VectorTests::ADDReduce, Double128VectorTests::ADDReduceAll); + Double128VectorTests::ADDReduce, Double128VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { double res = 0; @@ -2179,7 +2202,7 @@ static void ADDReduceDouble128VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double128VectorTests::ADDReduceMasked, Double128VectorTests::ADDReduceAllMasked); + Double128VectorTests::ADDReduceMasked, Double128VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MULReduce(double[] a, int idx) { double res = 1; @@ -2220,7 +2243,7 @@ static void MULReduceDouble128VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double128VectorTests::MULReduce, Double128VectorTests::MULReduceAll); + Double128VectorTests::MULReduce, Double128VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { double res = 1; @@ -2264,7 +2287,7 @@ static void MULReduceDouble128VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double128VectorTests::MULReduceMasked, Double128VectorTests::MULReduceAllMasked); + Double128VectorTests::MULReduceMasked, Double128VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MINReduce(double[] a, int idx) { double res = Double.POSITIVE_INFINITY; diff --git a/test/jdk/jdk/incubator/vector/Double256VectorTests.java b/test/jdk/jdk/incubator/vector/Double256VectorTests.java index 008b4dcc348..bb4694966d8 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorTests.java @@ -59,6 +59,8 @@ public class Double256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); @@ -118,15 +120,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (double)0.0); + } + + static void assertReductionArraysEquals(double[] r, double rc, double[] a, + FReductionOp f, FReductionAllOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -140,15 +148,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (double)0.0); + } + + static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -986,6 +1001,14 @@ static long bits(double e) { return fill(s * BUFFER_REPS, i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1))); }), + withToString("double[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)0.01 + ((double)i / (i + 1))); + }), + withToString("double[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (double)0.01 + ((double)i / (i + 1))); + }), withToString("double[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2135,7 +2158,7 @@ static void ADDReduceDouble256VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double256VectorTests::ADDReduce, Double256VectorTests::ADDReduceAll); + Double256VectorTests::ADDReduce, Double256VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { double res = 0; @@ -2179,7 +2202,7 @@ static void ADDReduceDouble256VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double256VectorTests::ADDReduceMasked, Double256VectorTests::ADDReduceAllMasked); + Double256VectorTests::ADDReduceMasked, Double256VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MULReduce(double[] a, int idx) { double res = 1; @@ -2220,7 +2243,7 @@ static void MULReduceDouble256VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double256VectorTests::MULReduce, Double256VectorTests::MULReduceAll); + Double256VectorTests::MULReduce, Double256VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { double res = 1; @@ -2264,7 +2287,7 @@ static void MULReduceDouble256VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double256VectorTests::MULReduceMasked, Double256VectorTests::MULReduceAllMasked); + Double256VectorTests::MULReduceMasked, Double256VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MINReduce(double[] a, int idx) { double res = Double.POSITIVE_INFINITY; diff --git a/test/jdk/jdk/incubator/vector/Double512VectorTests.java b/test/jdk/jdk/incubator/vector/Double512VectorTests.java index ce25f8ea703..72bb1a49c36 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorTests.java @@ -59,6 +59,8 @@ public class Double512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); @@ -118,15 +120,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (double)0.0); + } + + static void assertReductionArraysEquals(double[] r, double rc, double[] a, + FReductionOp f, FReductionAllOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -140,15 +148,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (double)0.0); + } + + static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -986,6 +1001,14 @@ static long bits(double e) { return fill(s * BUFFER_REPS, i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1))); }), + withToString("double[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)0.01 + ((double)i / (i + 1))); + }), + withToString("double[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (double)0.01 + ((double)i / (i + 1))); + }), withToString("double[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2135,7 +2158,7 @@ static void ADDReduceDouble512VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double512VectorTests::ADDReduce, Double512VectorTests::ADDReduceAll); + Double512VectorTests::ADDReduce, Double512VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { double res = 0; @@ -2179,7 +2202,7 @@ static void ADDReduceDouble512VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double512VectorTests::ADDReduceMasked, Double512VectorTests::ADDReduceAllMasked); + Double512VectorTests::ADDReduceMasked, Double512VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MULReduce(double[] a, int idx) { double res = 1; @@ -2220,7 +2243,7 @@ static void MULReduceDouble512VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double512VectorTests::MULReduce, Double512VectorTests::MULReduceAll); + Double512VectorTests::MULReduce, Double512VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { double res = 1; @@ -2264,7 +2287,7 @@ static void MULReduceDouble512VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double512VectorTests::MULReduceMasked, Double512VectorTests::MULReduceAllMasked); + Double512VectorTests::MULReduceMasked, Double512VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MINReduce(double[] a, int idx) { double res = Double.POSITIVE_INFINITY; diff --git a/test/jdk/jdk/incubator/vector/Double64VectorTests.java b/test/jdk/jdk/incubator/vector/Double64VectorTests.java index c4270d0f268..b445995543f 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorTests.java @@ -59,6 +59,8 @@ public class Double64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); @@ -118,15 +120,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (double)0.0); + } + + static void assertReductionArraysEquals(double[] r, double rc, double[] a, + FReductionOp f, FReductionAllOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -140,15 +148,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (double)0.0); + } + + static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -986,6 +1001,14 @@ static long bits(double e) { return fill(s * BUFFER_REPS, i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1))); }), + withToString("double[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)0.01 + ((double)i / (i + 1))); + }), + withToString("double[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (double)0.01 + ((double)i / (i + 1))); + }), withToString("double[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2135,7 +2158,7 @@ static void ADDReduceDouble64VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double64VectorTests::ADDReduce, Double64VectorTests::ADDReduceAll); + Double64VectorTests::ADDReduce, Double64VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { double res = 0; @@ -2179,7 +2202,7 @@ static void ADDReduceDouble64VectorTestsMasked(IntFunction fa, IntFunc } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double64VectorTests::ADDReduceMasked, Double64VectorTests::ADDReduceAllMasked); + Double64VectorTests::ADDReduceMasked, Double64VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MULReduce(double[] a, int idx) { double res = 1; @@ -2220,7 +2243,7 @@ static void MULReduceDouble64VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double64VectorTests::MULReduce, Double64VectorTests::MULReduceAll); + Double64VectorTests::MULReduce, Double64VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { double res = 1; @@ -2264,7 +2287,7 @@ static void MULReduceDouble64VectorTestsMasked(IntFunction fa, IntFunc } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double64VectorTests::MULReduceMasked, Double64VectorTests::MULReduceAllMasked); + Double64VectorTests::MULReduceMasked, Double64VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MINReduce(double[] a, int idx) { double res = Double.POSITIVE_INFINITY; diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java index df037495d89..9db85a2f20e 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java @@ -65,6 +65,9 @@ static VectorShape getMaxBit() { private static final int Max = 256; // juts so we can do N/Max + // for floating point reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); interface FUnOp { @@ -123,15 +126,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (double)0.0); + } + + static void assertReductionArraysEquals(double[] r, double rc, double[] a, + FReductionOp f, FReductionAllOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -145,15 +154,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (double)0.0); + } + + static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -991,6 +1007,14 @@ static long bits(double e) { return fill(s * BUFFER_REPS, i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1))); }), + withToString("double[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)0.01 + ((double)i / (i + 1))); + }), + withToString("double[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (double)0.01 + ((double)i / (i + 1))); + }), withToString("double[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2140,7 +2164,7 @@ static void ADDReduceDoubleMaxVectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - DoubleMaxVectorTests::ADDReduce, DoubleMaxVectorTests::ADDReduceAll); + DoubleMaxVectorTests::ADDReduce, DoubleMaxVectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { double res = 0; @@ -2184,7 +2208,7 @@ static void ADDReduceDoubleMaxVectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - DoubleMaxVectorTests::ADDReduceMasked, DoubleMaxVectorTests::ADDReduceAllMasked); + DoubleMaxVectorTests::ADDReduceMasked, DoubleMaxVectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MULReduce(double[] a, int idx) { double res = 1; @@ -2225,7 +2249,7 @@ static void MULReduceDoubleMaxVectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - DoubleMaxVectorTests::MULReduce, DoubleMaxVectorTests::MULReduceAll); + DoubleMaxVectorTests::MULReduce, DoubleMaxVectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { double res = 1; @@ -2269,7 +2293,7 @@ static void MULReduceDoubleMaxVectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - DoubleMaxVectorTests::MULReduceMasked, DoubleMaxVectorTests::MULReduceAllMasked); + DoubleMaxVectorTests::MULReduceMasked, DoubleMaxVectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MINReduce(double[] a, int idx) { double res = Double.POSITIVE_INFINITY; diff --git a/test/jdk/jdk/incubator/vector/Float128VectorTests.java b/test/jdk/jdk/incubator/vector/Float128VectorTests.java index ae38b606da9..c8a9aa4a80c 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorTests.java @@ -59,6 +59,8 @@ public class Float128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); @@ -118,15 +120,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (float)0.0); + } + + static void assertReductionArraysEquals(float[] r, float rc, float[] a, + FReductionOp f, FReductionAllOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -140,15 +148,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (float)0.0); + } + + static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -996,6 +1011,14 @@ static int bits(float e) { return fill(s * BUFFER_REPS, i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1))); }), + withToString("float[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)0.01 + ((float)i / (i + 1))); + }), + withToString("float[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (float)0.01 + ((float)i / (i + 1))); + }), withToString("float[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2145,7 +2168,7 @@ static void ADDReduceFloat128VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float128VectorTests::ADDReduce, Float128VectorTests::ADDReduceAll); + Float128VectorTests::ADDReduce, Float128VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { float res = 0; @@ -2189,7 +2212,7 @@ static void ADDReduceFloat128VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float128VectorTests::ADDReduceMasked, Float128VectorTests::ADDReduceAllMasked); + Float128VectorTests::ADDReduceMasked, Float128VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MULReduce(float[] a, int idx) { float res = 1; @@ -2230,7 +2253,7 @@ static void MULReduceFloat128VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float128VectorTests::MULReduce, Float128VectorTests::MULReduceAll); + Float128VectorTests::MULReduce, Float128VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { float res = 1; @@ -2274,7 +2297,7 @@ static void MULReduceFloat128VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float128VectorTests::MULReduceMasked, Float128VectorTests::MULReduceAllMasked); + Float128VectorTests::MULReduceMasked, Float128VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MINReduce(float[] a, int idx) { float res = Float.POSITIVE_INFINITY; diff --git a/test/jdk/jdk/incubator/vector/Float256VectorTests.java b/test/jdk/jdk/incubator/vector/Float256VectorTests.java index be55fa2b458..fcbf7df409b 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorTests.java @@ -59,6 +59,8 @@ public class Float256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); @@ -118,15 +120,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (float)0.0); + } + + static void assertReductionArraysEquals(float[] r, float rc, float[] a, + FReductionOp f, FReductionAllOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -140,15 +148,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (float)0.0); + } + + static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -996,6 +1011,14 @@ static int bits(float e) { return fill(s * BUFFER_REPS, i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1))); }), + withToString("float[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)0.01 + ((float)i / (i + 1))); + }), + withToString("float[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (float)0.01 + ((float)i / (i + 1))); + }), withToString("float[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2145,7 +2168,7 @@ static void ADDReduceFloat256VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float256VectorTests::ADDReduce, Float256VectorTests::ADDReduceAll); + Float256VectorTests::ADDReduce, Float256VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { float res = 0; @@ -2189,7 +2212,7 @@ static void ADDReduceFloat256VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float256VectorTests::ADDReduceMasked, Float256VectorTests::ADDReduceAllMasked); + Float256VectorTests::ADDReduceMasked, Float256VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MULReduce(float[] a, int idx) { float res = 1; @@ -2230,7 +2253,7 @@ static void MULReduceFloat256VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float256VectorTests::MULReduce, Float256VectorTests::MULReduceAll); + Float256VectorTests::MULReduce, Float256VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { float res = 1; @@ -2274,7 +2297,7 @@ static void MULReduceFloat256VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float256VectorTests::MULReduceMasked, Float256VectorTests::MULReduceAllMasked); + Float256VectorTests::MULReduceMasked, Float256VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MINReduce(float[] a, int idx) { float res = Float.POSITIVE_INFINITY; diff --git a/test/jdk/jdk/incubator/vector/Float512VectorTests.java b/test/jdk/jdk/incubator/vector/Float512VectorTests.java index f1f1b884d6b..597a590098a 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorTests.java @@ -59,6 +59,8 @@ public class Float512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); @@ -118,15 +120,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (float)0.0); + } + + static void assertReductionArraysEquals(float[] r, float rc, float[] a, + FReductionOp f, FReductionAllOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -140,15 +148,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (float)0.0); + } + + static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -996,6 +1011,14 @@ static int bits(float e) { return fill(s * BUFFER_REPS, i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1))); }), + withToString("float[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)0.01 + ((float)i / (i + 1))); + }), + withToString("float[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (float)0.01 + ((float)i / (i + 1))); + }), withToString("float[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2145,7 +2168,7 @@ static void ADDReduceFloat512VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float512VectorTests::ADDReduce, Float512VectorTests::ADDReduceAll); + Float512VectorTests::ADDReduce, Float512VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { float res = 0; @@ -2189,7 +2212,7 @@ static void ADDReduceFloat512VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float512VectorTests::ADDReduceMasked, Float512VectorTests::ADDReduceAllMasked); + Float512VectorTests::ADDReduceMasked, Float512VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MULReduce(float[] a, int idx) { float res = 1; @@ -2230,7 +2253,7 @@ static void MULReduceFloat512VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float512VectorTests::MULReduce, Float512VectorTests::MULReduceAll); + Float512VectorTests::MULReduce, Float512VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { float res = 1; @@ -2274,7 +2297,7 @@ static void MULReduceFloat512VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float512VectorTests::MULReduceMasked, Float512VectorTests::MULReduceAllMasked); + Float512VectorTests::MULReduceMasked, Float512VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MINReduce(float[] a, int idx) { float res = Float.POSITIVE_INFINITY; diff --git a/test/jdk/jdk/incubator/vector/Float64VectorTests.java b/test/jdk/jdk/incubator/vector/Float64VectorTests.java index 47f0cf3f15b..b5877b9de46 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorTests.java @@ -59,6 +59,8 @@ public class Float64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); @@ -118,15 +120,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (float)0.0); + } + + static void assertReductionArraysEquals(float[] r, float rc, float[] a, + FReductionOp f, FReductionAllOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -140,15 +148,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (float)0.0); + } + + static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -996,6 +1011,14 @@ static int bits(float e) { return fill(s * BUFFER_REPS, i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1))); }), + withToString("float[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)0.01 + ((float)i / (i + 1))); + }), + withToString("float[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (float)0.01 + ((float)i / (i + 1))); + }), withToString("float[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2145,7 +2168,7 @@ static void ADDReduceFloat64VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float64VectorTests::ADDReduce, Float64VectorTests::ADDReduceAll); + Float64VectorTests::ADDReduce, Float64VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { float res = 0; @@ -2189,7 +2212,7 @@ static void ADDReduceFloat64VectorTestsMasked(IntFunction fa, IntFuncti } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float64VectorTests::ADDReduceMasked, Float64VectorTests::ADDReduceAllMasked); + Float64VectorTests::ADDReduceMasked, Float64VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MULReduce(float[] a, int idx) { float res = 1; @@ -2230,7 +2253,7 @@ static void MULReduceFloat64VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float64VectorTests::MULReduce, Float64VectorTests::MULReduceAll); + Float64VectorTests::MULReduce, Float64VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { float res = 1; @@ -2274,7 +2297,7 @@ static void MULReduceFloat64VectorTestsMasked(IntFunction fa, IntFuncti } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float64VectorTests::MULReduceMasked, Float64VectorTests::MULReduceAllMasked); + Float64VectorTests::MULReduceMasked, Float64VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MINReduce(float[] a, int idx) { float res = Float.POSITIVE_INFINITY; diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java index 511afbb680e..9a40694f869 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java @@ -65,6 +65,9 @@ static VectorShape getMaxBit() { private static final int Max = 256; // juts so we can do N/Max + // for floating point reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; + static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); interface FUnOp { @@ -123,15 +126,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (float)0.0); + } + + static void assertReductionArraysEquals(float[] r, float rc, float[] a, + FReductionOp f, FReductionAllOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -145,15 +154,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (float)0.0); + } + + static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1001,6 +1017,14 @@ static int bits(float e) { return fill(s * BUFFER_REPS, i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1))); }), + withToString("float[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)0.01 + ((float)i / (i + 1))); + }), + withToString("float[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (float)0.01 + ((float)i / (i + 1))); + }), withToString("float[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2150,7 +2174,7 @@ static void ADDReduceFloatMaxVectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - FloatMaxVectorTests::ADDReduce, FloatMaxVectorTests::ADDReduceAll); + FloatMaxVectorTests::ADDReduce, FloatMaxVectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { float res = 0; @@ -2194,7 +2218,7 @@ static void ADDReduceFloatMaxVectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - FloatMaxVectorTests::ADDReduceMasked, FloatMaxVectorTests::ADDReduceAllMasked); + FloatMaxVectorTests::ADDReduceMasked, FloatMaxVectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MULReduce(float[] a, int idx) { float res = 1; @@ -2235,7 +2259,7 @@ static void MULReduceFloatMaxVectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - FloatMaxVectorTests::MULReduce, FloatMaxVectorTests::MULReduceAll); + FloatMaxVectorTests::MULReduce, FloatMaxVectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { float res = 1; @@ -2279,7 +2303,7 @@ static void MULReduceFloatMaxVectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - FloatMaxVectorTests::MULReduceMasked, FloatMaxVectorTests::MULReduceAllMasked); + FloatMaxVectorTests::MULReduceMasked, FloatMaxVectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MINReduce(float[] a, int idx) { float res = Float.POSITIVE_INFINITY; diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op.template index 70ffa79bf6f..1ded00af608 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op.template @@ -2,5 +2,9 @@ static void [[TEST]]Reduce$vectorteststype$Masked(IntFunction<$type$[]> fa, IntFunction fm) { [[KERNEL]] assertReductionArraysEqualsMasked(r, ra, a, mask, +#if[FP] + $vectorteststype$::[[TEST]]ReduceMasked, $vectorteststype$::[[TEST]]ReduceAllMasked, RELATIVE_ROUNDING_ERROR); +#else[FP] $vectorteststype$::[[TEST]]ReduceMasked, $vectorteststype$::[[TEST]]ReduceAllMasked); +#end[FP] } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template index b86248f3f09..15a3ba8c66c 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template @@ -2,5 +2,9 @@ static void [[TEST]]Reduce$vectorteststype$(IntFunction<$type$[]> fa) { [[KERNEL]] assertReductionArraysEquals(r, ra, a, +#if[FP] + $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll, RELATIVE_ROUNDING_ERROR); +#else[FP] $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll); +#end[FP] } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-header.template b/test/jdk/jdk/incubator/vector/templates/Unit-header.template index 3e78d5897d5..089f9fef8d2 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-header.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-header.template @@ -88,6 +88,10 @@ public class $vectorteststype$ extends AbstractVectorTest { private static final int Max = 256; // juts so we can do N/$bits$ #end[MaxBit] +#if[FP] + // for floating point reduction ops that may introduce rounding errors + private static final $type$ RELATIVE_ROUNDING_ERROR = ($type$)0.000001; +#end[FP] static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / $bits$); @@ -147,6 +151,9 @@ public class $vectorteststype$ extends AbstractVectorTest { static void assertReductionArraysEquals($type$[] r, $type$ rc, $type$[] a, FReductionOp f, FReductionAllOp fa) { +#if[FP] + assertReductionArraysEquals(r, rc, a, f, fa, ($type$)0.0); +#else[FP] int i = 0; try { Assert.assertEquals(rc, fa.apply(a)); @@ -157,7 +164,25 @@ public class $vectorteststype$ extends AbstractVectorTest { Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); } +#end[FP] + } +#if[FP] + + static void assertReductionArraysEquals($type$[] r, $type$ rc, $type$[] a, + FReductionOp f, FReductionAllOp fa, + $type$ relativeError) { + int i = 0; + try { + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); + for (; i < a.length; i += SPECIES.length()) { + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); + } + } catch (AssertionError e) { + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); + } } +#end[FP] interface FReductionMaskedOp { $type$ apply($type$[] a, int idx, boolean[] mask); @@ -169,6 +194,9 @@ public class $vectorteststype$ extends AbstractVectorTest { static void assertReductionArraysEqualsMasked($type$[] r, $type$ rc, $type$[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { +#if[FP] + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, ($type$)0.0); +#else[FP] int i = 0; try { Assert.assertEquals(rc, fa.apply(a, mask)); @@ -179,7 +207,26 @@ public class $vectorteststype$ extends AbstractVectorTest { Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); } +#end[FP] + } +#if[FP] + + static void assertReductionArraysEqualsMasked($type$[] r, $type$ rc, $type$[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + $type$ relativeError) { + int i = 0; + try { + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); + for (; i < a.length; i += SPECIES.length()) { + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); + } + } catch (AssertionError e) { + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); + } } +#end[FP] #if[!Long] interface FReductionOpLong { @@ -1051,6 +1098,16 @@ public class $vectorteststype$ extends AbstractVectorTest { return fill(s * BUFFER_REPS, i -> ((($type$)(i + 1) == 0) ? 1 : ($type$)(i + 1))); }), +#if[FP] + withToString("$type$[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> ($type$)0.01 + (($type$)i / (i + 1))); + }), + withToString("$type$[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : ($type$)0.01 + (($type$)i / (i + 1))); + }), +#end[FP] withToString("$type$[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i));