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 public FirstInterface[] as = new FirstInterface[asLength]; 192 public FirstInterface[] noninlined = new FirstInterface[asLength]; 193 public FirstInterfaceExtExt[] noninlinedextext = new FirstInterfaceExtExt[asLength]; 194 195 196 @Setup 197 public void setupSubclass() { 198 as[0] = new FirstClass(); 199 as[1] = new SecondClass(); 200 as[2] = new ThirdClass(); 201 as[3] = new FourthClass(); 202 as[4] = new FifthClass(); 203 204 noninlined[0] = new FirstClassDontInline(); 205 noninlined[1] = new SecondClassDontInline(); 206 noninlined[2] = new ThirdClassDontInline(); 207 noninlined[3] = new FourthClassDontInline(); 208 noninlined[4] = new FifthClassDontInline(); 209 210 noninlinedextext[0] = new FirstClassDontInlineExtExt(); 211 noninlinedextext[1] = new SecondClassDontInlineExtExt(); 212 noninlinedextext[2] = new ThirdClassDontInlineExtExt(); 213 noninlinedextext[3] = new FourthClassDontInlineExtExt(); 214 noninlinedextext[4] = new FifthClassDontInlineExtExt(); 215 } 216 217 /** 218 * Tests a call where there are multiple implementors but only one of the 219 * implementors is every used here so the call-site is monomorphic 220 */ 221 @Benchmark 222 public int testMonomorphic() { 223 return as[0].getIntFirst(); 224 } 225 226 int l = 0; 227 228 /** Tests single base interface method call */ 229 @Benchmark 230 public int testIfaceCall(Blackhole bh) { 231 FirstInterface ai = noninlined[l]; 232 l = ++ l % asLength; 233 return ai.getIntFirst(); 234 } 235 236 /** Tests extended interface method call */ 237 @Benchmark 238 public int testIfaceExtCall(Blackhole bh) { 239 FirstInterfaceExtExt ai = noninlinedextext[l]; 240 l = ++ l % asLength; 241 return ai.getIntFirst(); 242 } 243 244 /** 245 * Interface call address computation within loop but the receiver preexists 246 * the loop and the ac can be moved outside of the loop 247 */ 248 @Benchmark 249 public int test1stInt2Types() { 250 FirstInterface ai = as[step(2)]; 251 return ai.getIntFirst(); 252 } 253 254 @Benchmark 255 public int test1stInt3Types() { 256 FirstInterface ai = as[step(3)]; 257 return ai.getIntFirst(); 258 } 259 260 @Benchmark 261 public int test1stInt5Types() { 262 FirstInterface ai = as[step(asLength)]; 263 return ai.getIntFirst(); 264 } 265 266 @Benchmark 267 public int test2ndInt2Types() { 268 SecondInterface ai = (SecondInterface) as[step(2)]; 269 return ai.getIntSecond(); 270 } 271 272 @Benchmark 273 public int test2ndInt3Types() { 274 SecondInterface ai = (SecondInterface) as[step(3)]; 275 return ai.getIntSecond(); 276 } 277 278 @Benchmark 279 public int test2ndInt5Types() { 280 SecondInterface ai = (SecondInterface) as[step(asLength)]; 281 return ai.getIntSecond(); 282 } 283 284 int step(int range) { 285 if (randomized) { 286 l = scramble(l); 287 } else { 288 l++; 289 } 290 return (l & Integer.MAX_VALUE) % range; 291 } 292 293 static final int scramble(int n) { 294 int x = n; 295 x ^= x << 13; 296 x ^= x >>> 17; 297 x ^= x << 5; 298 return x == 0 ? 1 : x; 299 } 300 }