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 }