1 /* 2 * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.openjdk.bench.java.lang.foreign; 24 25 import java.lang.foreign.Arena; 26 import java.lang.foreign.MemorySegment; 27 28 import org.openjdk.jmh.annotations.Benchmark; 29 import org.openjdk.jmh.annotations.BenchmarkMode; 30 import org.openjdk.jmh.annotations.Fork; 31 import org.openjdk.jmh.annotations.Measurement; 32 import org.openjdk.jmh.annotations.Mode; 33 import org.openjdk.jmh.annotations.OutputTimeUnit; 34 import org.openjdk.jmh.annotations.Setup; 35 import org.openjdk.jmh.annotations.State; 36 import org.openjdk.jmh.annotations.TearDown; 37 import org.openjdk.jmh.annotations.Warmup; 38 39 import java.nio.ByteBuffer; 40 import java.nio.ByteOrder; 41 import java.nio.IntBuffer; 42 import java.util.Iterator; 43 import java.util.concurrent.TimeUnit; 44 45 import static java.lang.foreign.ValueLayout.JAVA_INT; 46 47 @BenchmarkMode(Mode.AverageTime) 48 @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) 49 @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) 50 @State(org.openjdk.jmh.annotations.Scope.Thread) 51 @OutputTimeUnit(TimeUnit.MILLISECONDS) 52 @Fork(value = 3, jvmArgsAppend = { "--enable-preview", "--enable-native-access=ALL-UNNAMED" }) 53 54 public class LoopOverSlice { 55 56 static final int ELEM_SIZE = 1_000_000; 57 static final int CARRIER_SIZE = (int)JAVA_INT.byteSize(); 58 static final int ALLOC_SIZE = ELEM_SIZE * CARRIER_SIZE; 59 60 Arena arena; 61 MemorySegment nativeSegment, heapSegment; 62 IntBuffer nativeBuffer, heapBuffer; 63 64 @Setup 65 public void setup() { 66 arena = Arena.ofConfined(); 67 nativeSegment = arena.allocate(ALLOC_SIZE, 1); 68 heapSegment = MemorySegment.ofArray(new int[ELEM_SIZE]); 69 nativeBuffer = ByteBuffer.allocateDirect(ALLOC_SIZE).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer(); 70 heapBuffer = IntBuffer.wrap(new int[ELEM_SIZE]); 71 } 72 73 @TearDown 74 public void tearDown() { 75 arena.close(); 76 } 77 78 @Benchmark 79 public void native_segment_slice_loop() { 80 new NativeSegmentWrapper(nativeSegment).forEach(NativeSegmentWrapper.Element::get); 81 } 82 83 @Benchmark 84 public void native_buffer_slice_loop() { 85 new NativeBufferWrapper(nativeBuffer).forEach(NativeBufferWrapper.Element::get); 86 } 87 88 @Benchmark 89 public void heap_segment_slice_loop() { 90 new HeapSegmentWrapper(heapSegment).forEach(HeapSegmentWrapper.Element::get); 91 } 92 93 @Benchmark 94 public void heap_buffer_slice_loop() { 95 new HeapBufferWrapper(heapBuffer).forEach(HeapBufferWrapper.Element::get); 96 } 97 98 class HeapSegmentWrapper implements Iterable<HeapSegmentWrapper.Element> { 99 final MemorySegment segment; 100 101 public HeapSegmentWrapper(MemorySegment segment) { 102 this.segment = segment; 103 } 104 105 @Override 106 public Iterator<Element> iterator() { 107 return new Iterator<Element>() { 108 109 MemorySegment current = segment; 110 111 @Override 112 public boolean hasNext() { 113 return current.byteSize() > 4; 114 } 115 116 @Override 117 public Element next() { 118 Element element = new Element(current); 119 current = current.asSlice(4); 120 return element; 121 } 122 }; 123 } 124 125 static class Element { 126 final MemorySegment segment; 127 128 public Element(MemorySegment segment) { 129 this.segment = segment; 130 } 131 132 int get() { 133 return segment.getAtIndex(JAVA_INT, 0); 134 } 135 } 136 } 137 138 class NativeSegmentWrapper implements Iterable<NativeSegmentWrapper.Element> { 139 final MemorySegment segment; 140 141 public NativeSegmentWrapper(MemorySegment segment) { 142 this.segment = segment; 143 } 144 145 @Override 146 public Iterator<Element> iterator() { 147 return new Iterator<Element>() { 148 149 MemorySegment current = segment; 150 151 @Override 152 public boolean hasNext() { 153 return current.byteSize() > 4; 154 } 155 156 @Override 157 public Element next() { 158 Element element = new Element(current); 159 current = current.asSlice(4); 160 return element; 161 } 162 }; 163 } 164 165 static class Element { 166 final MemorySegment segment; 167 168 public Element(MemorySegment segment) { 169 this.segment = segment; 170 } 171 172 int get() { 173 return segment.getAtIndex(JAVA_INT, 0); 174 } 175 } 176 } 177 178 class NativeBufferWrapper implements Iterable<NativeBufferWrapper.Element> { 179 final IntBuffer buffer; 180 181 public NativeBufferWrapper(IntBuffer buffer) { 182 this.buffer = buffer; 183 } 184 185 @Override 186 public Iterator<Element> iterator() { 187 return new Iterator<Element>() { 188 189 IntBuffer current = buffer; 190 191 @Override 192 public boolean hasNext() { 193 return current.position() < current.limit(); 194 } 195 196 @Override 197 public Element next() { 198 Element element = new Element(current); 199 int lim = current.limit(); 200 current = current.slice(1, lim - 1); 201 return element; 202 } 203 }; 204 } 205 206 static class Element { 207 final IntBuffer buffer; 208 209 public Element(IntBuffer segment) { 210 this.buffer = segment; 211 } 212 213 int get() { 214 return buffer.get( 0); 215 } 216 } 217 } 218 219 class HeapBufferWrapper implements Iterable<HeapBufferWrapper.Element> { 220 final IntBuffer buffer; 221 222 public HeapBufferWrapper(IntBuffer buffer) { 223 this.buffer = buffer; 224 } 225 226 @Override 227 public Iterator<Element> iterator() { 228 return new Iterator<Element>() { 229 230 IntBuffer current = buffer; 231 232 @Override 233 public boolean hasNext() { 234 return current.position() < current.limit(); 235 } 236 237 @Override 238 public Element next() { 239 Element element = new Element(current); 240 int lim = current.limit(); 241 current = current.slice(1, lim - 1); 242 return element; 243 } 244 }; 245 } 246 247 static class Element { 248 final IntBuffer buffer; 249 250 public Element(IntBuffer segment) { 251 this.buffer = segment; 252 } 253 254 int get() { 255 return buffer.get( 0); 256 } 257 } 258 } 259 }