1 /*
  2  *  Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
  3  *  Copyright (c) 2021, Rado Smogura. All rights reserved.
  4  *
  5  *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  6  *
  7  *  This code is free software; you can redistribute it and/or modify it
  8  *  under the terms of the GNU General Public License version 2 only, as
  9  *  published by the Free Software Foundation.
 10  *
 11  *  This code is distributed in the hope that it will be useful, but WITHOUT
 12  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  *  version 2 for more details (a copy is included in the LICENSE file that
 15  *  accompanied this code).
 16  *
 17  *  You should have received a copy of the GNU General Public License version
 18  *  2 along with this work; if not, write to the Free Software Foundation,
 19  *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  *  Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  *  or visit www.oracle.com if you need additional information or have any
 23  *  questions.
 24  *
 25  */
 26 package org.openjdk.bench.jdk.incubator.vector;
 27 
 28 import java.nio.ByteBuffer;
 29 import java.nio.ByteOrder;
 30 import java.util.concurrent.TimeUnit;
 31 import jdk.incubator.vector.ByteVector;
 32 import jdk.incubator.vector.VectorSpecies;
 33 import org.openjdk.jmh.annotations.Benchmark;
 34 import org.openjdk.jmh.annotations.BenchmarkMode;
 35 import org.openjdk.jmh.annotations.CompilerControl;
 36 import org.openjdk.jmh.annotations.Fork;
 37 import org.openjdk.jmh.annotations.Measurement;
 38 import org.openjdk.jmh.annotations.Mode;
 39 import org.openjdk.jmh.annotations.OutputTimeUnit;
 40 import org.openjdk.jmh.annotations.Param;
 41 import org.openjdk.jmh.annotations.Setup;
 42 import org.openjdk.jmh.annotations.State;
 43 import org.openjdk.jmh.annotations.Warmup;
 44 
 45 @BenchmarkMode(Mode.AverageTime)
 46 @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
 47 @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
 48 @State(org.openjdk.jmh.annotations.Scope.Benchmark)
 49 @OutputTimeUnit(TimeUnit.NANOSECONDS)
 50 @Fork(value = 1, jvmArgsAppend = {
 51     "--add-modules=jdk.incubator.foreign,jdk.incubator.vector",
 52     "-Dforeign.restricted=permit",
 53     "--enable-native-access", "ALL-UNNAMED"})
 54 public class ByteBufferVectorAccess {
 55   private static final VectorSpecies<Byte> SPECIES = VectorSpecies.ofLargestShape(byte.class);
 56 
 57   @Param("1024")
 58   private int size;
 59 
 60   ByteBuffer directIn, directOut;
 61   ByteBuffer heapIn, heapOut;
 62 
 63   ByteBuffer directInRo, directOutRo;
 64   ByteBuffer heapInRo, heapOutRo;
 65 
 66   @Setup
 67   public void setup() {
 68     directIn = ByteBuffer.allocateDirect(size);
 69     directOut = ByteBuffer.allocateDirect(size);
 70 
 71     heapIn = ByteBuffer.wrap(new byte[size]);
 72     heapOut = ByteBuffer.wrap(new byte[size]);
 73 
 74     directInRo = directIn.asReadOnlyBuffer();
 75     directOutRo = directOut.asReadOnlyBuffer();
 76 
 77     heapInRo = heapIn.asReadOnlyBuffer();
 78     heapOutRo = heapOut.asReadOnlyBuffer();
 79   }
 80 
 81   @Benchmark
 82   public void directBuffers() {
 83     copyMemory(directIn, directOut);
 84   }
 85 
 86   @Benchmark
 87   public void heapBuffers() {
 88     copyMemory(heapIn, heapOut);
 89   }
 90 
 91   @Benchmark
 92   public void pollutedBuffers2() {
 93     copyIntoNotInlined(directIn, directOut);
 94     copyIntoNotInlined(heapIn, heapOut);
 95   }
 96 
 97   @Benchmark
 98   public void pollutedBuffers3() {
 99     copyIntoNotInlined(directIn, directOut);
100     copyIntoNotInlined(heapIn, heapOut);
101 
102     copyIntoNotInlined(directInRo, directOut);
103     copyIntoNotInlined(heapInRo, heapOut);
104   }
105 
106   @Benchmark
107   public void pollutedBuffers4() {
108     copyIntoNotInlined(directIn, heapOut); // Pollute if unswitch on 2nd param
109     copyIntoNotInlined(heapIn, heapOut);
110 
111     copyIntoNotInlined(heapIn, directIn); // Pollute if unswitch on 1st param
112     copyIntoNotInlined(heapIn, directOut);
113   }
114 
115 
116   boolean readOnlyException;
117 
118   @Benchmark
119   public void pollutedBuffers5() {
120     copyIntoNotInlined(directIn, heapOut);
121     copyIntoNotInlined(heapIn, heapOut);
122 
123     copyIntoNotInlined(heapIn, directIn);
124     copyIntoNotInlined(heapIn, directOut);
125 
126     if (readOnlyException) {
127       try {
128         copyIntoNotInlined(heapIn, directOutRo);
129       } catch (Exception ignored) {}
130       readOnlyException = !readOnlyException;
131     }
132   }
133 
134   @Benchmark
135   public void arrayCopy() {
136     byte[] in = heapIn.array();
137     byte[] out = heapOut.array();
138 
139     for (int i=0; i < SPECIES.loopBound(in.length); i += SPECIES.vectorByteSize()) {
140       final var v = ByteVector.fromArray(SPECIES, in, i);
141       v.intoArray(out, i);
142     }
143   }
144 
145   @CompilerControl(CompilerControl.Mode.DONT_INLINE)
146   protected void copyIntoNotInlined(ByteBuffer in, ByteBuffer out) {
147     copyMemory(in, out);
148   }
149 
150   @CompilerControl(CompilerControl.Mode.INLINE)
151   protected void copyMemory(ByteBuffer in, ByteBuffer out) {
152     for (int i=0; i < SPECIES.loopBound(in.limit()); i += SPECIES.vectorByteSize()) {
153       final var v = ByteVector.fromByteBuffer(SPECIES, in, i, ByteOrder.nativeOrder());
154       v.intoByteBuffer(out, i, ByteOrder.nativeOrder());
155     }
156   }
157 }