Path: blob/master/test/jdk/java/foreign/TestHandshake.java
41144 views
/*1* Copyright (c) 2020, 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*/2223/*24* @test25* @modules jdk.incubator.foreign java.base/jdk.internal.vm.annotation java.base/jdk.internal.misc26* @key randomness27* @run testng/othervm TestHandshake28* @run testng/othervm -Xint TestHandshake29* @run testng/othervm -XX:TieredStopAtLevel=1 TestHandshake30* @run testng/othervm -XX:-TieredCompilation TestHandshake31*/3233import jdk.incubator.foreign.MemoryAccess;34import jdk.incubator.foreign.MemorySegment;3536import java.lang.invoke.MethodHandles;37import java.lang.invoke.VarHandle;38import java.nio.ByteBuffer;39import java.nio.ByteOrder;40import java.util.concurrent.ExecutorService;41import java.util.concurrent.Executors;42import java.util.concurrent.ThreadLocalRandom;43import java.util.concurrent.TimeUnit;44import java.util.concurrent.atomic.AtomicBoolean;45import java.util.concurrent.atomic.AtomicLong;4647import jdk.incubator.foreign.ResourceScope;48import org.testng.annotations.DataProvider;49import org.testng.annotations.Test;50import static org.testng.Assert.*;5152public class TestHandshake {5354static final int ITERATIONS = 5;55static final int SEGMENT_SIZE = 1_000_000;56static final int MAX_DELAY_MILLIS = 500;57static final int MAX_EXECUTOR_WAIT_SECONDS = 20;58static final int MAX_THREAD_SPIN_WAIT_MILLIS = 200;5960static final int NUM_ACCESSORS = Math.min(10, Runtime.getRuntime().availableProcessors());6162static final AtomicLong start = new AtomicLong();63static final AtomicBoolean started = new AtomicBoolean();6465@Test(dataProvider = "accessors")66public void testHandshake(String testName, AccessorFactory accessorFactory) throws InterruptedException {67for (int it = 0 ; it < ITERATIONS ; it++) {68ResourceScope scope = ResourceScope.newSharedScope();69MemorySegment segment = MemorySegment.allocateNative(SEGMENT_SIZE, 1, scope);70System.out.println("ITERATION " + it);71ExecutorService accessExecutor = Executors.newCachedThreadPool();72start.set(System.currentTimeMillis());73started.set(false);74for (int i = 0; i < NUM_ACCESSORS ; i++) {75accessExecutor.execute(accessorFactory.make(i, segment));76}77int delay = ThreadLocalRandom.current().nextInt(MAX_DELAY_MILLIS);78System.out.println("Starting handshaker with delay set to " + delay + " millis");79Thread.sleep(delay);80accessExecutor.execute(new Handshaker(scope));81accessExecutor.shutdown();82assertTrue(accessExecutor.awaitTermination(MAX_EXECUTOR_WAIT_SECONDS, TimeUnit.SECONDS));83assertTrue(!segment.scope().isAlive());84}85}8687static abstract class AbstractSegmentAccessor implements Runnable {88final MemorySegment segment;89final int id;9091AbstractSegmentAccessor(int id, MemorySegment segment) {92this.id = id;93this.segment = segment;94}9596@Override97public final void run() {98start("\"Accessor #\" + id");99outer: while (segment.scope().isAlive()) {100try {101doAccess();102} catch (IllegalStateException ex) {103long delay = System.currentTimeMillis() - start.get();104System.out.println("Accessor #" + id + " suspending - elapsed (ms): " + delay);105backoff();106delay = System.currentTimeMillis() - start.get();107System.out.println("Accessor #" + id + " resuming - elapsed (ms): " + delay);108continue outer;109}110}111long delay = System.currentTimeMillis() - start.get();112System.out.println("Accessor #" + id + " terminated - elapsed (ms): " + delay);113}114115abstract void doAccess();116117private void backoff() {118try {119Thread.sleep(ThreadLocalRandom.current().nextInt(MAX_THREAD_SPIN_WAIT_MILLIS));120} catch (InterruptedException ex) {121throw new AssertionError(ex);122}123}124}125126static void start(String name) {127if (started.compareAndSet(false, true)) {128long delay = System.currentTimeMillis() - start.get();129System.out.println("Started first thread: " + name + " ; elapsed (ms): " + delay);130}131}132133static abstract class AbstractBufferAccessor extends AbstractSegmentAccessor {134final ByteBuffer bb;135136AbstractBufferAccessor(int id, MemorySegment segment) {137super(id, segment);138this.bb = segment.asByteBuffer();139}140}141142static class SegmentAccessor extends AbstractSegmentAccessor {143144SegmentAccessor(int id, MemorySegment segment) {145super(id, segment);146}147148@Override149void doAccess() {150int sum = 0;151for (int i = 0; i < segment.byteSize(); i++) {152sum += MemoryAccess.getByteAtOffset(segment, i);153}154}155}156157static class SegmentCopyAccessor extends AbstractSegmentAccessor {158159MemorySegment first, second;160161162SegmentCopyAccessor(int id, MemorySegment segment) {163super(id, segment);164long split = segment.byteSize() / 2;165first = segment.asSlice(0, split);166second = segment.asSlice(split);167}168169@Override170public void doAccess() {171first.copyFrom(second);172}173}174175static class SegmentFillAccessor extends AbstractSegmentAccessor {176177SegmentFillAccessor(int id, MemorySegment segment) {178super(id, segment);179}180181@Override182public void doAccess() {183segment.fill((byte) ThreadLocalRandom.current().nextInt(10));184}185}186187static class SegmentMismatchAccessor extends AbstractSegmentAccessor {188189final MemorySegment copy;190191SegmentMismatchAccessor(int id, MemorySegment segment) {192super(id, segment);193this.copy = MemorySegment.allocateNative(SEGMENT_SIZE, 1, segment.scope());194copy.copyFrom(segment);195MemoryAccess.setByteAtOffset(copy, ThreadLocalRandom.current().nextInt(SEGMENT_SIZE), (byte)42);196}197198@Override199public void doAccess() {200segment.mismatch(copy);201}202}203204static class BufferAccessor extends AbstractBufferAccessor {205206BufferAccessor(int id, MemorySegment segment) {207super(id, segment);208}209210@Override211public void doAccess() {212int sum = 0;213for (int i = 0; i < bb.capacity(); i++) {214sum += bb.get(i);215}216}217}218219static class BufferHandleAccessor extends AbstractBufferAccessor {220221static VarHandle handle = MethodHandles.byteBufferViewVarHandle(short[].class, ByteOrder.nativeOrder());222223public BufferHandleAccessor(int id, MemorySegment segment) {224super(id, segment);225}226227@Override228public void doAccess() {229int sum = 0;230for (int i = 0; i < bb.capacity() / 2; i++) {231sum += (short) handle.get(bb, i);232}233}234};235236static class Handshaker implements Runnable {237238final ResourceScope scope;239240Handshaker(ResourceScope scope) {241this.scope = scope;242}243244@Override245public void run() {246start("Handshaker");247while (true) {248try {249scope.close();250break;251} catch (IllegalStateException ex) {252Thread.onSpinWait();253}254}255long delay = System.currentTimeMillis() - start.get();256System.out.println("Segment closed - elapsed (ms): " + delay);257}258}259260interface AccessorFactory {261AbstractSegmentAccessor make(int id, MemorySegment segment);262}263264@DataProvider265static Object[][] accessors() {266return new Object[][] {267{ "SegmentAccessor", (AccessorFactory)SegmentAccessor::new },268{ "SegmentCopyAccessor", (AccessorFactory)SegmentCopyAccessor::new },269{ "SegmentMismatchAccessor", (AccessorFactory)SegmentMismatchAccessor::new },270{ "SegmentFillAccessor", (AccessorFactory)SegmentFillAccessor::new },271{ "BufferAccessor", (AccessorFactory)BufferAccessor::new },272{ "BufferHandleAccessor", (AccessorFactory)BufferHandleAccessor::new }273};274}275}276277278