1 /*
2  * Copyright (c) 2020, 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.jdk.incubator.foreign;
24 
25 import jdk.incubator.foreign.MemoryAccess;
26 import jdk.incubator.foreign.MemoryAddress;
27 import jdk.incubator.foreign.MemoryLayout;
28 import jdk.incubator.foreign.MemorySegment;
29 import org.openjdk.jmh.annotations.Benchmark;
30 import org.openjdk.jmh.annotations.BenchmarkMode;
31 import org.openjdk.jmh.annotations.Fork;
32 import org.openjdk.jmh.annotations.Measurement;
33 import org.openjdk.jmh.annotations.Mode;
34 import org.openjdk.jmh.annotations.OutputTimeUnit;
35 import org.openjdk.jmh.annotations.Param;
36 import org.openjdk.jmh.annotations.Setup;
37 import org.openjdk.jmh.annotations.State;
38 import org.openjdk.jmh.annotations.TearDown;
39 import org.openjdk.jmh.annotations.Warmup;
40 import sun.misc.Unsafe;
41 
42 import java.lang.invoke.VarHandle;
43 import java.nio.ByteBuffer;
44 import java.nio.ByteOrder;
45 import java.util.concurrent.TimeUnit;
46 
47 import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement;
48 import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT;
49 
50 @BenchmarkMode(Mode.AverageTime)
51 @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
52 @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
53 @State(org.openjdk.jmh.annotations.Scope.Thread)
54 @OutputTimeUnit(TimeUnit.MILLISECONDS)
55 @Fork(value = 3, jvmArgsAppend = { "--add-modules=jdk.incubator.foreign" })
56 public class LoopOverNonConstantHeap {
57 
58     static final Unsafe unsafe = Utils.unsafe;
59 
60     static final int ELEM_SIZE = 1_000_000;
61     static final int CARRIER_SIZE = (int)JAVA_INT.byteSize();
62     static final int ALLOC_SIZE = ELEM_SIZE * CARRIER_SIZE;
63     static final int UNSAFE_BYTE_BASE = unsafe.arrayBaseOffset(byte[].class);
64 
65     static final VarHandle VH_int = MemoryLayout.ofSequence(JAVA_INT).varHandle(int.class, sequenceElement());
66     MemorySegment segment;
67     byte[] base;
68 
69     ByteBuffer byteBuffer;
70 
71     @Param(value = {"false", "true"})
72     boolean polluteProfile;
73 
74     @Setup
setup()75     public void setup() {
76         if (polluteProfile) {
77             MemorySegment intB = MemorySegment.ofArray(new byte[ALLOC_SIZE]);
78             MemorySegment intI = MemorySegment.ofArray(new int[ALLOC_SIZE]);
79             MemorySegment intD = MemorySegment.ofArray(new double[ALLOC_SIZE]);
80             MemorySegment intF = MemorySegment.ofArray(new float[ALLOC_SIZE]);
81             try (MemorySegment s = MemorySegment.allocateNative(ALLOC_SIZE)) {
82                 for (int i = 0; i < ALLOC_SIZE; i++) {
83                     MemoryAccess.setByteAtOffset(intB, i, (byte)i);
84                     MemoryAccess.setIntAtIndex(intI, i, i);
85                     MemoryAccess.setDoubleAtIndex(intD, i, i);
86                     MemoryAccess.setFloatAtIndex(intF, i, i);
87                     MemoryAccess.setByteAtOffset(s, i, (byte) i);
88                 }
89             }
90         }
91 
92         base = new byte[ALLOC_SIZE];
93         for (int i = 0; i < ELEM_SIZE; i++) {
94             unsafe.putInt(base, UNSAFE_BYTE_BASE + (i * CARRIER_SIZE) , i);
95         }
96         segment = MemorySegment.ofArray(base);
97         byteBuffer = ByteBuffer.wrap(base).order(ByteOrder.nativeOrder());
98     }
99 
100     @TearDown
tearDown()101     public void tearDown() {
102         segment.close();
103     }
104 
105     @Benchmark
106     @OutputTimeUnit(TimeUnit.NANOSECONDS)
unsafe_get()107     public int unsafe_get() {
108         return unsafe.getInt(base, UNSAFE_BYTE_BASE);
109     }
110 
111     @Benchmark
112     @OutputTimeUnit(TimeUnit.NANOSECONDS)
segment_get()113     public int segment_get() {
114         return (int) VH_int.get(segment, 0L);
115     }
116 
117     @Benchmark
118     @OutputTimeUnit(TimeUnit.NANOSECONDS)
BB_get()119     public int BB_get() {
120         return byteBuffer.getInt(0);
121     }
122 
123     @Benchmark
unsafe_loop()124     public int unsafe_loop() {
125         int res = 0;
126         for (int i = 0; i < ELEM_SIZE; i ++) {
127             res += unsafe.getInt(base, UNSAFE_BYTE_BASE + (i * CARRIER_SIZE));
128         }
129         return res;
130     }
131 
132     @Benchmark
segment_loop()133     public int segment_loop() {
134         int sum = 0;
135         for (int i = 0; i < ELEM_SIZE; i++) {
136             sum += (int) VH_int.get(segment, (long) i);
137         }
138         return sum;
139     }
140 
141     @Benchmark
segment_loop_static()142     public int segment_loop_static() {
143         int res = 0;
144         for (int i = 0; i < ELEM_SIZE; i ++) {
145             res += MemoryAccess.getIntAtIndex(segment, i);
146         }
147         return res;
148     }
149 
150     @Benchmark
segment_loop_slice()151     public int segment_loop_slice() {
152         int sum = 0;
153         MemorySegment base = segment.asSlice(0, segment.byteSize());
154         for (int i = 0; i < ELEM_SIZE; i++) {
155             sum += (int) VH_int.get(base, (long) i);
156         }
157         return sum;
158     }
159 
160     @Benchmark
segment_loop_readonly()161     public int segment_loop_readonly() {
162         int sum = 0;
163         MemorySegment base = segment.withAccessModes(MemorySegment.READ);
164         for (int i = 0; i < ELEM_SIZE; i++) {
165             sum += (int) VH_int.get(base, (long) i);
166         }
167         return sum;
168     }
169 
170     @Benchmark
BB_loop()171     public int BB_loop() {
172         int sum = 0;
173         ByteBuffer bb = byteBuffer;
174         for (int i = 0; i < ELEM_SIZE; i++) {
175             sum += bb.getInt(i * CARRIER_SIZE);
176         }
177         return sum;
178     }
179 
180 }
181