Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/sun/nio/ch/TestMaxCachedBufferSize.java
38840 views
/*1* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.io.IOException;2425import java.lang.management.BufferPoolMXBean;26import java.lang.management.ManagementFactory;2728import java.nio.ByteBuffer;2930import java.nio.channels.FileChannel;3132import java.nio.file.Path;33import java.nio.file.Paths;3435import static java.nio.file.StandardOpenOption.CREATE;36import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;37import static java.nio.file.StandardOpenOption.WRITE;3839import java.util.List;40import java.util.Random;4142/*43* @test44* @requires sun.arch.data.model == "64"45* @build TestMaxCachedBufferSize46* @run main/othervm TestMaxCachedBufferSize47* @run main/othervm -Djdk.nio.maxCachedBufferSize=0 TestMaxCachedBufferSize48* @run main/othervm -Djdk.nio.maxCachedBufferSize=2000 TestMaxCachedBufferSize49* @run main/othervm -Djdk.nio.maxCachedBufferSize=100000 TestMaxCachedBufferSize50* @run main/othervm -Djdk.nio.maxCachedBufferSize=10000000 TestMaxCachedBufferSize51* @summary Test the implementation of the jdk.nio.maxCachedBufferSize property.52*/53public class TestMaxCachedBufferSize {54private static final int DEFAULT_ITERS = 10 * 1000;55private static final int DEFAULT_THREAD_NUM = 4;5657private static final int SMALL_BUFFER_MIN_SIZE = 4 * 1024;58private static final int SMALL_BUFFER_MAX_SIZE = 64 * 1024;59private static final int SMALL_BUFFER_DIFF_SIZE =60SMALL_BUFFER_MAX_SIZE - SMALL_BUFFER_MIN_SIZE;6162private static final int LARGE_BUFFER_MIN_SIZE = 512 * 1024;63private static final int LARGE_BUFFER_MAX_SIZE = 4 * 1024 * 1024;64private static final int LARGE_BUFFER_DIFF_SIZE =65LARGE_BUFFER_MAX_SIZE - LARGE_BUFFER_MIN_SIZE;6667private static final int LARGE_BUFFER_FREQUENCY = 100;6869private static final String FILE_NAME_PREFIX = "nio-out-file-";70private static final int VERBOSE_PERIOD = 5 * 1000;7172private static int iters = DEFAULT_ITERS;73private static int threadNum = DEFAULT_THREAD_NUM;7475private static BufferPoolMXBean getDirectPool() {76final List<BufferPoolMXBean> pools =77ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class);78for (BufferPoolMXBean pool : pools) {79if (pool.getName().equals("direct")) {80return pool;81}82}83throw new Error("could not find direct pool");84}85private static final BufferPoolMXBean directPool = getDirectPool();8687// Each worker will do write operations on a file channel using88// buffers of various sizes. The buffer size is randomly chosen to89// be within a small or a large range. This way we can control90// which buffers can be cached (all, only the small ones, or none)91// by setting the jdk.nio.maxCachedBufferSize property.92private static class Worker implements Runnable {93private final int id;94private final Random random = new Random();95private long smallBufferCount = 0;96private long largeBufferCount = 0;9798private int getWriteSize() {99int minSize = 0;100int diff = 0;101if (random.nextInt() % LARGE_BUFFER_FREQUENCY != 0) {102// small buffer103minSize = SMALL_BUFFER_MIN_SIZE;104diff = SMALL_BUFFER_DIFF_SIZE;105smallBufferCount += 1;106} else {107// large buffer108minSize = LARGE_BUFFER_MIN_SIZE;109diff = LARGE_BUFFER_DIFF_SIZE;110largeBufferCount += 1;111}112return minSize + random.nextInt(diff);113}114115private void loop() {116final String fileName = String.format("%s%d", FILE_NAME_PREFIX, id);117118try {119for (int i = 0; i < iters; i += 1) {120final int writeSize = getWriteSize();121122// This will allocate a HeapByteBuffer. It should not123// be a direct buffer, otherwise the write() method on124// the channel below will not create a temporary125// direct buffer for the write.126final ByteBuffer buffer = ByteBuffer.allocate(writeSize);127128// Put some random data on it.129while (buffer.hasRemaining()) {130buffer.put((byte) random.nextInt());131}132buffer.rewind();133134final Path file = Paths.get(fileName);135try (FileChannel outChannel = FileChannel.open(file, CREATE, TRUNCATE_EXISTING, WRITE)) {136// The write() method will create a temporary137// direct buffer for the write and attempt to cache138// it. It's important that buffer is not a139// direct buffer, otherwise the temporary buffer140// will not be created.141long res = outChannel.write(buffer);142}143144if ((i + 1) % VERBOSE_PERIOD == 0) {145System.out.printf(146" Worker %3d | %8d Iters | Small %8d Large %8d | Direct %4d / %7dK\n",147id, i + 1, smallBufferCount, largeBufferCount,148directPool.getCount(), directPool.getTotalCapacity() / 1024);149}150}151} catch (IOException e) {152throw new Error("I/O error", e);153}154}155156@Override157public void run() {158loop();159}160161public Worker(int id) {162this.id = id;163}164}165166public static void checkDirectBuffers(long expectedCount, long expectedMax) {167final long directCount = directPool.getCount();168final long directTotalCapacity = directPool.getTotalCapacity();169System.out.printf("Direct %d / %dK\n",170directCount, directTotalCapacity / 1024);171172// Note that directCount could be < expectedCount. This can173// happen if a GC occurs after one of the worker threads exits174// since its thread-local DirectByteBuffer could be cleaned up175// before we reach here.176if (directCount > expectedCount) {177throw new Error(String.format(178"inconsistent direct buffer total count, expected = %d, found = %d",179expectedCount, directCount));180}181182if (directTotalCapacity > expectedMax) {183throw new Error(String.format(184"inconsistent direct buffer total capacity, expectex max = %d, found = %d",185expectedMax, directTotalCapacity));186}187}188189public static void main(String[] args) {190final String maxBufferSizeStr = System.getProperty("jdk.nio.maxCachedBufferSize");191final long maxBufferSize =192(maxBufferSizeStr != null) ? Long.valueOf(maxBufferSizeStr) : Long.MAX_VALUE;193194// We assume that the max cannot be equal to a size of a195// buffer that can be allocated (makes sanity checking at the196// end easier).197if ((SMALL_BUFFER_MIN_SIZE <= maxBufferSize &&198maxBufferSize <= SMALL_BUFFER_MAX_SIZE) ||199(LARGE_BUFFER_MIN_SIZE <= maxBufferSize &&200maxBufferSize <= LARGE_BUFFER_MAX_SIZE)) {201throw new Error(String.format("max buffer size = %d not allowed",202maxBufferSize));203}204205System.out.printf("Threads %d | Iterations %d | MaxBufferSize %d\n",206threadNum, iters, maxBufferSize);207System.out.println();208209final Thread[] threads = new Thread[threadNum];210for (int i = 0; i < threadNum; i += 1) {211threads[i] = new Thread(new Worker(i));212threads[i].start();213}214215try {216for (int i = 0; i < threadNum; i += 1) {217threads[i].join();218}219} catch (InterruptedException e) {220throw new Error("join() interrupted!", e);221}222223// There is an assumption here that, at this point, only the224// cached DirectByteBuffers should be active. Given we225// haven't used any other DirectByteBuffers in this test, this226// should hold.227//228// Also note that we can only do the sanity checking at the229// end and not during the run given that, at any time, there230// could be buffers currently in use by some of the workers231// that will not be cached.232233System.out.println();234if (maxBufferSize < SMALL_BUFFER_MAX_SIZE) {235// The max buffer size is smaller than all buffers that236// were allocated. No buffers should have been cached.237checkDirectBuffers(0, 0);238} else if (maxBufferSize < LARGE_BUFFER_MIN_SIZE) {239// The max buffer size is larger than all small buffers240// but smaller than all large buffers that were241// allocated. Only small buffers could have been cached.242checkDirectBuffers(threadNum,243(long) threadNum * (long) SMALL_BUFFER_MAX_SIZE);244} else {245// The max buffer size is larger than all buffers that246// were allocated. All buffers could have been cached.247checkDirectBuffers(threadNum,248(long) threadNum * (long) LARGE_BUFFER_MAX_SIZE);249}250}251}252253254