1 /*
2 * Copyright (c) 2021, 2024, 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
24 package org.openjdk.bench.java.lang.foreign.pointers;
25
26 import org.openjdk.jmh.annotations.Benchmark;
27 import org.openjdk.jmh.annotations.BenchmarkMode;
28 import org.openjdk.jmh.annotations.Fork;
29 import org.openjdk.jmh.annotations.Measurement;
30 import org.openjdk.jmh.annotations.Mode;
31 import org.openjdk.jmh.annotations.OutputTimeUnit;
32 import org.openjdk.jmh.annotations.Scope;
33 import org.openjdk.jmh.annotations.Setup;
34 import org.openjdk.jmh.annotations.State;
35 import org.openjdk.jmh.annotations.TearDown;
36 import org.openjdk.jmh.annotations.Warmup;
37
38 import java.lang.foreign.AddressLayout;
39 import java.lang.foreign.Arena;
40 import java.lang.foreign.MemoryLayout;
41 import java.lang.foreign.MemorySegment;
42 import java.lang.foreign.ValueLayout;
43 import java.util.concurrent.TimeUnit;
44
45 @BenchmarkMode(Mode.AverageTime)
46 @Warmup(iterations = 3, time = 500, timeUnit = TimeUnit.MILLISECONDS)
47 @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
48 @OutputTimeUnit(TimeUnit.MILLISECONDS)
49 @Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED" })
50 @State(Scope.Benchmark)
51 public class PointerBench {
52
53 final Arena arena = Arena.ofConfined();
54 static final int ELEM_SIZE = 1_000_000;
55 @SuppressWarnings("initialization")
56 Pointer<Integer> intPointer = Pointer.allocate(NativeType.C_INT, ELEM_SIZE, arena);
57 @SuppressWarnings("initialization")
58 Pointer<Pointer<Integer>> intPointerPointer = Pointer.allocate(NativeType.C_INT_PTR, ELEM_SIZE, arena);
59 @SuppressWarnings("initialization")
60 Pointer<Point> pointPointer = Pointer.allocate(Point.TYPE, ELEM_SIZE, arena);
61 MemorySegment intSegment = intPointer.segment();
62 MemorySegment intPointerSegment = intPointerPointer.segment();
63 MemorySegment pointSegment = pointPointer.segment();
64
65 public static final AddressLayout UNSAFE_ADDRESS = ValueLayout.ADDRESS
66 .withTargetLayout(MemoryLayout.sequenceLayout(Long.MAX_VALUE, ValueLayout.JAVA_BYTE));
67
68 @Setup
69 public void setup() {
70 for (int i = 0 ; i < ELEM_SIZE ; i++) {
71 intSegment.setAtIndex(ValueLayout.JAVA_INT, i, i);
72 intPointerSegment.setAtIndex(ValueLayout.ADDRESS, i, intSegment.asSlice(4 * i));
73 pointSegment.setAtIndex(ValueLayout.JAVA_INT, (i * 2), i);
74 pointSegment.setAtIndex(ValueLayout.JAVA_INT, (i * 2) + 1, i);
75 }
76 }
77
78 @TearDown
79 public void teardown() {
80 arena.close();
81 }
82
83 @Benchmark
84 public int testLoopPointerInt_ptr() {
85 int sum = 0;
86 for (int i = 0 ; i < ELEM_SIZE ; i++) {
87 sum += intPointer.get(NativeType.C_INT, i);
88 }
89 return sum;
90 }
91
92 @Benchmark
93 public int testLoopPointerPointerInt_ptr() {
94 int sum = 0;
95 for (int i = 0 ; i < ELEM_SIZE ; i++) {
96 sum += intPointerPointer.get(NativeType.C_INT_PTR, i)
97 .get(NativeType.C_INT, 0);
98 }
99 return sum;
100 }
101
102 @Benchmark
103 public int testLoopPointerPoint_ptr() {
104 int sum = 0;
105 for (int i = 0 ; i < ELEM_SIZE ; i++) {
106 sum += pointPointer.get(Point.TYPE, i).x();
107 }
108 return sum;
109 }
110
111 @Benchmark
112 public int testLoopPointerInt_ptr_generic() {
113 int sum = 0;
114 for (int i = 0 ; i < ELEM_SIZE ; i++) {
115 sum += genericGet(intPointer, NativeType.C_INT, i);
116 }
117 return sum;
118 }
119
120 static <Z> Z genericGet(Pointer<Z> pz, NativeType<Z> type, long offset) {
121 return pz.get(type, offset);
122 }
123
124 @Benchmark
125 public int testLoopPointerInt_segment() {
126 int sum = 0;
127 for (int i = 0 ; i < ELEM_SIZE ; i++) {
128 sum += intSegment.getAtIndex(ValueLayout.JAVA_INT, i);
129 }
130 return sum;
131 }
132
133 @Benchmark
134 public int testLoopPointerPointerInt_segment() {
135 int sum = 0;
136 for (long i = 0 ; i < ELEM_SIZE ; i++) {
137 var segment = intPointerSegment.getAtIndex(UNSAFE_ADDRESS, i);
138 sum += segment.get(ValueLayout.JAVA_INT, 0);
139 }
140 return sum;
141 }
142
143 @Benchmark
144 public int testLoopPointerPoint_segment() {
145 int sum = 0;
146 for (int i = 0 ; i < ELEM_SIZE ; i++) {
147 sum += pointSegment.getAtIndex(ValueLayout.JAVA_INT, i * 2);
148 }
149 return sum;
150 }
151 }