1 /*
2 * Copyright (c) 2014, 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 package org.openjdk.bench.vm.compiler;
24
25 import org.openjdk.jmh.annotations.Benchmark;
26 import org.openjdk.jmh.annotations.BenchmarkMode;
27 import org.openjdk.jmh.annotations.CompilerControl;
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.Param;
33 import org.openjdk.jmh.annotations.Scope;
34 import org.openjdk.jmh.annotations.Setup;
35 import org.openjdk.jmh.annotations.State;
36 import org.openjdk.jmh.annotations.Warmup;
37 import org.openjdk.jmh.infra.Blackhole;
38
39 import java.util.concurrent.TimeUnit;
40
41 @BenchmarkMode(Mode.AverageTime)
42 @OutputTimeUnit(TimeUnit.NANOSECONDS)
43 @State(Scope.Thread)
44 @Warmup(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS)
45 @Measurement(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS)
46 @Fork(value = 3)
47 public class InterfaceCalls {
48
49 // Whether to step iteratively through the list of interfaces, or
50 // to select one in an unpredictable way.
51 @Param({"false", "true"})
52 private boolean randomized;
53
54 interface FirstInterface {
55 public int getIntFirst();
56 }
57
58 interface SecondInterface {
59 public int getIntSecond();
60 }
61
62 interface FirstInterfaceExt extends FirstInterface {
63 default int getIntFirst() { return 44; }
64 }
65
66 interface FirstInterfaceExtExt extends FirstInterfaceExt {
67 default int getIntFirst() { return 45; }
68 }
69
70 class FirstClass implements FirstInterface, SecondInterface {
71 public int getIntFirst() {
72 return 1;
73 }
74
75 public int getIntSecond() {
76 return 1;
77 }
78 }
79
80 class SecondClass implements FirstInterface, SecondInterface {
81 public int getIntFirst() {
82 return 2;
83 }
84
85 public int getIntSecond() {
86 return 1;
87 }
88 }
89
90 class ThirdClass implements FirstInterface, SecondInterface {
91 public int getIntFirst() {
92 return -3;
93 }
94
95 public int getIntSecond() {
96 return 1;
97 }
98 }
99
100 class FourthClass implements FirstInterface, SecondInterface {
101 public int getIntFirst() {
102 return -4;
103 }
104
105 public int getIntSecond() {
106 return 1;
107 }
108 }
109
110 class FifthClass implements FirstInterface, SecondInterface {
111 public int getIntFirst() {
112 return -5;
113 }
114
115 public int getIntSecond() {
116 return 1;
117 }
118 }
119
120 class FirstClassDontInline implements FirstInterface {
121 @CompilerControl(CompilerControl.Mode.DONT_INLINE)
122 public int getIntFirst() {
123 return -1;
124 }
125 }
126
127 class SecondClassDontInline implements FirstInterface {
128 @CompilerControl(CompilerControl.Mode.DONT_INLINE)
129 public int getIntFirst() {
130 return -2;
131 }
132 }
133
134 class ThirdClassDontInline implements FirstInterface {
135 @CompilerControl(CompilerControl.Mode.DONT_INLINE)
136 public int getIntFirst() {
137 return -3;
138 }
139 }
140
141 class FourthClassDontInline implements FirstInterface {
142 @CompilerControl(CompilerControl.Mode.DONT_INLINE)
143 public int getIntFirst() {
144 return -4;
145 }
146 }
147
148 class FifthClassDontInline implements FirstInterface {
149 @CompilerControl(CompilerControl.Mode.DONT_INLINE)
150 public int getIntFirst() {
151 return -5;
152 }
153 }
154
155 class FirstClassDontInlineExtExt implements FirstInterfaceExtExt {
156 @CompilerControl(CompilerControl.Mode.DONT_INLINE)
157 public int getIntFirst() {
158 return -1;
159 }
160 }
161
162 class SecondClassDontInlineExtExt implements FirstInterfaceExtExt {
163 @CompilerControl(CompilerControl.Mode.DONT_INLINE)
164 public int getIntFirst() {
165 return -2;
166 }
167 }
168
169 class ThirdClassDontInlineExtExt implements FirstInterfaceExtExt {
170 @CompilerControl(CompilerControl.Mode.DONT_INLINE)
171 public int getIntFirst() {
172 return -3;
173 }
174 }
175
176 class FourthClassDontInlineExtExt implements FirstInterfaceExtExt {
177 @CompilerControl(CompilerControl.Mode.DONT_INLINE)
178 public int getIntFirst() {
179 return -4;
180 }
181 }
182
183 class FifthClassDontInlineExtExt implements FirstInterfaceExtExt {
184 @CompilerControl(CompilerControl.Mode.DONT_INLINE)
185 public int getIntFirst() {
186 return -5;
187 }
188 }
189
190 final int asLength = 5;
191 @SuppressWarnings("initialization")
192 public FirstInterface[] as = new FirstInterface[asLength];
193 @SuppressWarnings("initialization")
194 public FirstInterface[] noninlined = new FirstInterface[asLength];
195 @SuppressWarnings("initialization")
196 public FirstInterfaceExtExt[] noninlinedextext = new FirstInterfaceExtExt[asLength];
197
198
199 @Setup
200 public void setupSubclass() {
201 as[0] = new FirstClass();
202 as[1] = new SecondClass();
203 as[2] = new ThirdClass();
204 as[3] = new FourthClass();
205 as[4] = new FifthClass();
206
207 noninlined[0] = new FirstClassDontInline();
208 noninlined[1] = new SecondClassDontInline();
209 noninlined[2] = new ThirdClassDontInline();
210 noninlined[3] = new FourthClassDontInline();
211 noninlined[4] = new FifthClassDontInline();
212
213 noninlinedextext[0] = new FirstClassDontInlineExtExt();
214 noninlinedextext[1] = new SecondClassDontInlineExtExt();
215 noninlinedextext[2] = new ThirdClassDontInlineExtExt();
216 noninlinedextext[3] = new FourthClassDontInlineExtExt();
217 noninlinedextext[4] = new FifthClassDontInlineExtExt();
218 }
219
220 /**
221 * Tests a call where there are multiple implementors but only one of the
222 * implementors is every used here so the call-site is monomorphic
223 */
224 @Benchmark
225 public int testMonomorphic() {
226 return as[0].getIntFirst();
227 }
228
229 int l = 0;
230
231 /** Tests single base interface method call */
232 @Benchmark
233 public int testIfaceCall(Blackhole bh) {
234 FirstInterface ai = noninlined[l];
235 l = ++ l % asLength;
236 return ai.getIntFirst();
237 }
238
239 /** Tests extended interface method call */
240 @Benchmark
241 public int testIfaceExtCall(Blackhole bh) {
242 FirstInterfaceExtExt ai = noninlinedextext[l];
243 l = ++ l % asLength;
244 return ai.getIntFirst();
245 }
246
247 /**
248 * Interface call address computation within loop but the receiver preexists
249 * the loop and the ac can be moved outside of the loop
250 */
251 @Benchmark
252 public int test1stInt2Types() {
253 FirstInterface ai = as[step(2)];
254 return ai.getIntFirst();
255 }
256
257 @Benchmark
258 public int test1stInt3Types() {
259 FirstInterface ai = as[step(3)];
260 return ai.getIntFirst();
261 }
262
263 @Benchmark
264 public int test1stInt5Types() {
265 FirstInterface ai = as[step(asLength)];
266 return ai.getIntFirst();
267 }
268
269 @Benchmark
270 public int test2ndInt2Types() {
271 SecondInterface ai = (SecondInterface) as[step(2)];
272 return ai.getIntSecond();
273 }
274
275 @Benchmark
276 public int test2ndInt3Types() {
277 SecondInterface ai = (SecondInterface) as[step(3)];
278 return ai.getIntSecond();
279 }
280
281 @Benchmark
282 public int test2ndInt5Types() {
283 SecondInterface ai = (SecondInterface) as[step(asLength)];
284 return ai.getIntSecond();
285 }
286
287 int step(int range) {
288 if (randomized) {
289 l = scramble(l);
290 } else {
291 l++;
292 }
293 return (l & Integer.MAX_VALUE) % range;
294 }
295
296 static final int scramble(int n) {
297 int x = n;
298 x ^= x << 13;
299 x ^= x >>> 17;
300 x ^= x << 5;
301 return x == 0 ? 1 : x;
302 }
303 }
--- EOF ---