1 /*
  2  * Copyright (c) 2025, 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.valhalla.invoke.field;
 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.OperationsPerInvocation;
 32 import org.openjdk.jmh.annotations.OutputTimeUnit;
 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 
 38 import java.util.concurrent.TimeUnit;
 39 
 40 @Fork(3)
 41 @Warmup(iterations = 5, time = 1)
 42 @Measurement(iterations = 5, time = 1)
 43 @OutputTimeUnit(TimeUnit.NANOSECONDS)
 44 @BenchmarkMode(Mode.AverageTime)
 45 @State(Scope.Thread)
 46 public class Identity {
 47 
 48     /*
 49         virtual method invocations:
 50         target0 - statically known target method.
 51         target1 - the single invoked method (should be inlined)
 52         target2 - two invoked method (should be inlined, cache-inline)
 53         target3 - thee invoked method (shouldn't be inlined)
 54 
 55      */
 56 
 57 
 58     public static final int SIZE = 128;
 59 
 60     public interface InterfaceInt {
 61         public int value();
 62     }
 63 
 64     public static class IdentityInt0 implements InterfaceInt {
 65         public final int value;
 66         public IdentityInt0(int value) {
 67             this.value = value;
 68         }
 69         @Override
 70         public int value() {
 71             return value;
 72         }
 73     }
 74 
 75     public static class IdentityInt1 implements InterfaceInt {
 76         public final int value;
 77         public IdentityInt1(int value) {
 78             this.value = value;
 79         }
 80         @Override
 81         public int value() {
 82             return value;
 83         }
 84     }
 85 
 86     public static class IdentityInt2 implements InterfaceInt {
 87         public final int value;
 88         public IdentityInt2(int value) {
 89             this.value = value;
 90         }
 91         @Override
 92         public int value() {
 93             return value;
 94         }
 95     }
 96 
 97     public static class IntWrapper {
 98         final InterfaceInt f;
 99 
100         public IntWrapper(InterfaceInt f) {
101             this.f = f;
102         }
103     }
104 
105     public static class RefWrapper {
106         final IdentityInt0 f;
107 
108         public RefWrapper(IdentityInt0 f) {
109             this.f = f;
110         }
111     }
112 
113     @State(Scope.Thread)
114     public static class Int0State {
115         public IntWrapper[] arr;
116         @Setup
117         public void setup() {
118             arr = new IntWrapper[SIZE];
119             for (int i = 0; i < arr.length; i++) {
120                 arr[i] = new IntWrapper(new IdentityInt0(i));
121             }
122         }
123     }
124 
125     @State(Scope.Thread)
126     public static class Int1State {
127         public IntWrapper[] arr;
128         @Setup
129         public void setup() {
130             arr = new IntWrapper[SIZE];
131             for (int i = 0; i < arr.length; i++) {
132                 arr[i] = new IntWrapper(new IdentityInt1(i));
133             }
134         }
135     }
136 
137     @State(Scope.Thread)
138     public static class Int2State {
139         public IntWrapper[] arr;
140         @Setup
141         public void setup() {
142             arr = new IntWrapper[SIZE];
143             for (int i = 0; i < arr.length; i++) {
144                 arr[i] = new IntWrapper(new IdentityInt2(i));
145             }
146         }
147     }
148 
149     @State(Scope.Thread)
150     public static class Ref0State {
151         public RefWrapper[] arr;
152         @Setup
153         public void setup() {
154             arr = new RefWrapper[SIZE];
155             for (int i = 0; i < arr.length; i++) {
156                 arr[i] = new RefWrapper(new IdentityInt0(i));
157             }
158         }
159     }
160 
161 
162     @CompilerControl(CompilerControl.Mode.DONT_INLINE)
163     public int reduce_int(IntWrapper[] arr) {
164         int r = 0;
165         for (int i = 0; i < arr.length; i++) {
166             r += arr[i].f.value();
167         }
168         return r;
169     }
170 
171     @CompilerControl(CompilerControl.Mode.DONT_INLINE)
172     public int reduce_ref(RefWrapper[] arr) {
173         int r = 0;
174         for (int i = 0; i < arr.length; i++) {
175             r += arr[i].f.value();
176         }
177         return r;
178     }
179 
180     @Benchmark
181     @OperationsPerInvocation(SIZE * 6)
182     @CompilerControl(CompilerControl.Mode.INLINE)
183     public int target0(Ref0State st0, Ref0State st1, Ref0State st2, Ref0State st3, Ref0State st4, Ref0State st5) {
184         return reduce_ref(st0.arr) +
185                reduce_ref(st1.arr) +
186                reduce_ref(st2.arr) +
187                reduce_ref(st3.arr) +
188                reduce_ref(st4.arr) +
189                reduce_ref(st5.arr);
190     }
191 
192     @Benchmark
193     @OperationsPerInvocation(SIZE * 6)
194     @CompilerControl(CompilerControl.Mode.INLINE)
195     public int target1(Int0State st0, Int0State st1, Int0State st2, Int0State st3, Int0State st4, Int0State st5) {
196         return reduce_int(st0.arr) +
197                reduce_int(st1.arr) +
198                reduce_int(st2.arr) +
199                reduce_int(st3.arr) +
200                reduce_int(st4.arr) +
201                reduce_int(st5.arr);
202     }
203 
204     @Benchmark
205     @OperationsPerInvocation(SIZE * 6)
206     @CompilerControl(CompilerControl.Mode.INLINE)
207     public int target2(Int0State st0, Int0State st1, Int0State st2, Int1State st3, Int1State st4, Int1State st5) {
208         return reduce_int(st0.arr) +
209                reduce_int(st1.arr) +
210                reduce_int(st2.arr) +
211                reduce_int(st3.arr) +
212                reduce_int(st4.arr) +
213                reduce_int(st5.arr);
214     }
215 
216     @Benchmark
217     @OperationsPerInvocation(SIZE * 6)
218     @CompilerControl(CompilerControl.Mode.INLINE)
219     public int target3(Int0State st0, Int0State st1, Int1State st2, Int1State st3, Int2State st4, Int2State st5) {
220         return reduce_int(st0.arr) +
221                 reduce_int(st1.arr) +
222                 reduce_int(st2.arr) +
223                 reduce_int(st3.arr) +
224                 reduce_int(st4.arr) +
225                 reduce_int(st5.arr);
226     }
227 
228 }