| /* | |
| * Copyright (c) 2019, 2025, 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. | |
| */ | |
| /* | |
| * This test is manually run because it requires an NVRAM device to be | |
| * mapped as DAX file system or, at least, to be simulated by a | |
| * volatile RAM mapped file system. Also, on AArch64 it requires an | |
| * ARMV8.2 CPU which implements the dc CVAP instruction (CPU feature | |
| * dcpop) and an OS that makes it available from user space. | |
| * | |
| * If the test runs on such a host without throwing an exception then | |
| * that confirms that NVRAM-backed byte buffers can be allocated, | |
| * updated and forced via cache line writeback. | |
| */ | |
| /* | |
| * How to run this test: | |
| * | |
| * Ideally this test should be run on a x86_64/amd64 or aarch64 host | |
| * fitted with an NVRAM memory device. The NVRAM should appear as | |
| * /dev/pmem0 or some equivalent DAX file device. The file device | |
| * should be mounted at /mnt/pmem with a directory tmp created | |
| * directly under that mount point with a+rwx access. | |
| * | |
| * It is possible to run the test on x86_64 using a volatile RAM | |
| * backed device to simulate NVRAM, even though this does not provide | |
| * any guarantee of persistence of data across program runs. For the | |
| * latter case the following instructions explain how to set up the | |
| * simulated NVRAM device. | |
| * | |
| * https://developers.redhat.com/blog/2016/12/05/configuring-and-using-persistent-memory-rhel-7-3/ | |
| * https://nvdimm.wiki.kernel.org/ | |
| * TL;DR: add "memmap=1G!4G" to /etc/default/grub, eg. GRUB_CMDLINE_LINUX="memmap=1G!4G" | |
| * then ("sudo" may required) | |
| * for RHEL(BIOS-based): grub2-mkconfig -o /boot/grub2/grub.cfg | |
| * for RHEL(UEFI-based): grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg | |
| * for Ubuntu: update-grub2 | |
| * finally reboot | |
| * after the host been rebooted, a new /dev/pmem{N} device should exist, | |
| * naming conversion starts at /dev/pmem0 | |
| * | |
| * Prepare test directory follow below commands, "sudo" may required | |
| * (if ndctl or mkfs.xfs not exist, install ndctl or xfsprogs package first) | |
| * (for RHEL8, when call mkfs.xfs, specify the -m reflink=0 option to disable reflink feature) | |
| * | |
| * ndctl create-namespace -f -e namespace0.0 -m memory -M mem | |
| * mkdir /mnt/pmem | |
| * mkfs.xfs -f /dev/pmem0; mount -o dax /dev/pmem0 /mnt/pmem/ | |
| * mkdir /mnt/pmem/test; chmod a+rwx /mnt/pmem/test | |
| * | |
| * Now run the test program | |
| * | |
| * java PmemTest | |
| * | |
| * or | |
| * | |
| * make test TEST=jdk/java/nio/MappedByteBuffer/PmemTest.java | |
| */ | |
| /* @test id=default_architecture_test_case | |
| * @summary Testing NVRAM mapped byte buffer support | |
| * @run main/manual PmemTest | |
| * @requires (os.family == "linux") | |
| * @requires ((os.arch == "x86_64")|(os.arch == "amd64")) | |
| */ | |
| /* @test id=other_architectures_test_case | |
| * @summary Testing NVRAM mapped byte buffer support | |
| * @run main/manual PmemTest | |
| * @requires (os.family == "linux") | |
| * @requires ((os.arch == "aarch64")|(os.arch == "ppc64le")) | |
| * @ignore The test described here is currently disabled on systems that are not | |
| * x64-based and lack an external NVRAM memory device. In order to re-enable the | |
| * test, you will need to mount the NVRAM device, which will typically appear as | |
| * /dev/pmem0, to the directory /mnt/pmem. Once that is done, you can follow the | |
| * instructions above to create a test directory and remove the ignore tag. | |
| */ | |
| import java.io.File; | |
| import java.nio.MappedByteBuffer; | |
| import java.nio.channels.FileChannel; | |
| import java.nio.file.Files; | |
| import java.nio.file.Path; | |
| import java.nio.file.StandardOpenOption; | |
| import java.util.EnumSet; | |
| import java.util.List; | |
| import jdk.nio.mapmode.ExtendedMapMode; | |
| import java.lang.management.ManagementFactory; | |
| import java.lang.management.BufferPoolMXBean; | |
| public class PmemTest { | |
| public static final int K = 1024; | |
| public static final int NUM_KBS = 16; | |
| public static void main(String[] args) throws Exception { | |
| System.out.println("test"); | |
| String dir = "/tmp"; // mapSync should fail | |
| dir = "/mnt/pmem/test"; // mapSync should work, since fs mount is -o dax | |
| Path path = new File(dir, "pmemtest").toPath(); | |
| FileChannel fileChannel = (FileChannel) Files | |
| .newByteChannel(path, EnumSet.of( | |
| StandardOpenOption.READ, | |
| StandardOpenOption.WRITE, | |
| StandardOpenOption.CREATE)); | |
| MappedByteBuffer mappedByteBuffer = fileChannel.map(ExtendedMapMode.READ_WRITE_SYNC, 0, NUM_KBS * K); | |
| dumpBufferPoolBeans(); | |
| // for (int loops = 0; loops < 1000; loops++) { | |
| for (int loops = 0; loops < 100; loops++) { | |
| int base = K * (loops % NUM_KBS); | |
| for (int i = 0; i < K ; i++) { | |
| for (int j = 0; j < K ;j++) { | |
| testBuffer(mappedByteBuffer, base, (i << 3) + j); | |
| commitBuffer(mappedByteBuffer, base); | |
| } | |
| } | |
| } | |
| dumpBufferPoolBeans(); | |
| } | |
| public static void testBuffer(MappedByteBuffer mappedByteBuffer, int base, int start) { | |
| for (int k = 0; k < 8; k++) { | |
| int idx = (start + k) % K; | |
| byte z = mappedByteBuffer.get(base + idx); | |
| z++; | |
| mappedByteBuffer.put(base + idx, z); | |
| } | |
| } | |
| public static void commitBuffer(MappedByteBuffer mappedByteBuffer, int base) | |
| { | |
| mappedByteBuffer.force(base, K); | |
| } | |
| public static void dumpBufferPoolBeans() | |
| { | |
| List<BufferPoolMXBean> beansList = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class); | |
| for (BufferPoolMXBean bean : beansList) { | |
| System.out.println("BufferPoolMXBean {" + | |
| "\n\tname: " + bean.getName() + | |
| "\n\tcount: " + bean.getCount() + | |
| "\n\ttotalCapacity: " + bean.getTotalCapacity() + | |
| "\n\tmemoryUsed: " + bean.getMemoryUsed() + | |
| "\n}"); | |
| } | |
| } | |
| } |