1 /*
  2  * Copyright (c) 2014, 2021, 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.lang;
 24 
 25 import org.openjdk.jmh.annotations.Benchmark;
 26 import org.openjdk.jmh.annotations.BenchmarkMode;
 27 import org.openjdk.jmh.annotations.Fork;
 28 import org.openjdk.jmh.annotations.Measurement;
 29 import org.openjdk.jmh.annotations.Mode;
 30 import org.openjdk.jmh.annotations.OutputTimeUnit;
 31 import org.openjdk.jmh.annotations.Param;
 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.Threads;
 36 import org.openjdk.jmh.annotations.Warmup;
 37 
 38 import java.util.concurrent.TimeUnit;
 39 
 40 
 41 /**
 42  * Benchmark class for simple lock unlock tests. Nothing big should ever go into this class.
 43  */
 44 @BenchmarkMode(Mode.AverageTime)
 45 @OutputTimeUnit(TimeUnit.NANOSECONDS)
 46 @State(Scope.Benchmark)
 47 @Warmup(iterations = 4, time = 2)
 48 @Measurement(iterations = 4, time = 2)
 49 @Fork(value = 3)
 50 public class LockUnlock {
 51 
 52     @Param("100")
 53     private int innerCount;
 54 
 55     public Object lockObject1;
 56     public Object lockObject2;
 57     public volatile Object lockObject3Inflated;
 58     public volatile Object lockObject4Inflated;
 59     public int factorial;
 60     public int dummyInt1;
 61     public int dummyInt2;
 62 
 63     @Setup
 64     public void setup() {
 65         lockObject1 = new Object();
 66         lockObject2 = new Object();
 67         lockObject3Inflated = new Object();
 68         lockObject4Inflated = new Object();
 69 
 70         // Inflate the lock to use an ObjectMonitor
 71         try {
 72           synchronized (lockObject3Inflated) {
 73             lockObject3Inflated.wait(1);
 74           }
 75           synchronized (lockObject4Inflated) {
 76             lockObject4Inflated.wait(1);
 77           }
 78         } catch (InterruptedException e) {
 79           throw new RuntimeException(e);
 80         }
 81 
 82         dummyInt1 = 47;
 83         dummyInt2 = 11; // anything
 84     }
 85 
 86     /** Perform a synchronized on a local object within a loop. */
 87     @Benchmark
 88     public void testBasicSimpleLockUnlockLocal() {
 89         Object localObject = lockObject1;
 90         for (int i = 0; i < innerCount; i++) {
 91             synchronized (localObject) {
 92                 dummyInt1++;
 93                 dummyInt2++;
 94             }
 95         }
 96     }
 97 
 98     /** Perform a synchronized on an object within a loop. */
 99     @Benchmark
100     public void testBasicSimpleLockUnlock() {
101         for (int i = 0; i < innerCount; i++) {
102             synchronized (lockObject1) {
103                 dummyInt1++;
104                 dummyInt2++;
105             }
106         }
107     }
108 
109     /** Perform a synchronized on a local object within a loop. */
110     @Benchmark
111     public void testInflatedSimpleLockUnlockLocal() {
112         Object localObject = lockObject3Inflated;
113         for (int i = 0; i < innerCount; i++) {
114             synchronized (localObject) {
115                 dummyInt1++;
116                 dummyInt2++;
117             }
118         }
119     }
120 
121     /** Perform a synchronized on an object within a loop. */
122     @Benchmark
123     public void testInflatedSimpleLockUnlock() {
124         for (int i = 0; i < innerCount; i++) {
125             synchronized (lockObject3Inflated) {
126                 dummyInt1++;
127                 dummyInt2++;
128             }
129         }
130     }
131 
132     /** Perform a recursive synchronized on a local object within a loop. */
133     @Benchmark
134     public void testBasicRecursiveLockUnlockLocal() {
135         Object localObject = lockObject1;
136         for (int i = 0; i < innerCount; i++) {
137             synchronized (localObject) {
138                 synchronized (localObject) {
139                     dummyInt1++;
140                     dummyInt2++;
141                 }
142             }
143         }
144     }
145 
146     /** Perform a recursive synchronized on an object within a loop. */
147     @Benchmark
148     public void testBasicRecursiveLockUnlock() {
149         for (int i = 0; i < innerCount; i++) {
150             synchronized (lockObject1) {
151                 synchronized (lockObject1) {
152                     dummyInt1++;
153                     dummyInt2++;
154                 }
155             }
156         }
157     }
158 
159     /** Perform two synchronized after each other on the same local object. */
160     @Benchmark
161     public void testBasicSerialLockUnlockLocal() {
162         Object localObject = lockObject1;
163         for (int i = 0; i < innerCount; i++) {
164             synchronized (localObject) {
165                 dummyInt1++;
166             }
167             synchronized (localObject) {
168                 dummyInt2++;
169             }
170         }
171     }
172 
173   /** Perform two synchronized after each other on the same object. */
174     @Benchmark
175     public void testBasicSerialLockUnlock() {
176         for (int i = 0; i < innerCount; i++) {
177             synchronized (lockObject1) {
178                 dummyInt1++;
179             }
180             synchronized (lockObject1) {
181                 dummyInt2++;
182             }
183         }
184     }
185 
186     /** Perform two synchronized after each other on the same local object. */
187     @Benchmark
188     public void testInflatedSerialLockUnlockLocal() {
189         Object localObject = lockObject3Inflated;
190         for (int i = 0; i < innerCount; i++) {
191             synchronized (localObject) {
192                 dummyInt1++;
193             }
194             synchronized (localObject) {
195                 dummyInt2++;
196             }
197         }
198     }
199 
200   /** Perform two synchronized after each other on the same object. */
201     @Benchmark
202     public void testInflatedSerialLockUnlock() {
203         for (int i = 0; i < innerCount; i++) {
204             synchronized (lockObject3Inflated) {
205                 dummyInt1++;
206             }
207             synchronized (lockObject3Inflated) {
208                 dummyInt2++;
209             }
210         }
211     }
212 
213     /** Perform two synchronized after each other on the same object. */
214     @Benchmark
215     public void testInflatedMultipleSerialLockUnlock() {
216         for (int i = 0; i < innerCount; i++) {
217             synchronized (lockObject3Inflated) {
218                 dummyInt1++;
219             }
220             synchronized (lockObject4Inflated) {
221                 dummyInt2++;
222             }
223         }
224     }
225 
226     /** Perform two synchronized after each other on the same object. */
227     @Benchmark
228     public void testInflatedMultipleRecursiveLockUnlock() {
229         for (int i = 0; i < innerCount; i++) {
230             synchronized (lockObject3Inflated) {
231                 dummyInt1++;
232                 synchronized (lockObject4Inflated) {
233                     dummyInt2++;
234                 }
235             }
236         }
237     }
238 
239       /** Perform a recursive-only synchronized on a local object within a loop. */
240     @Benchmark
241     public void testInflatedRecursiveOnlyLockUnlockLocal() {
242         Object localObject = lockObject3Inflated;
243         synchronized (localObject) {
244             for (int i = 0; i < innerCount; i++) {
245                 synchronized (localObject) {
246                     dummyInt1++;
247                     dummyInt2++;
248                 }
249             }
250         }
251     }
252 
253     /** Perform a recursive-only synchronized on an object within a loop. */
254     @Benchmark
255     public void testInflatedRecursiveOnlyLockUnlock() {
256         synchronized (lockObject3Inflated) {
257             for (int i = 0; i < innerCount; i++) {
258                 synchronized (lockObject3Inflated) {
259                     dummyInt1++;
260                     dummyInt2++;
261                 }
262             }
263         }
264     }
265 
266     /** Perform a recursive-only synchronized on a local object within a loop. */
267     @Benchmark
268     public void testInflatedRecursiveLockUnlockLocal() {
269         Object localObject = lockObject3Inflated;
270         for (int i = 0; i < innerCount; i++) {
271             synchronized (localObject) {
272                 synchronized (localObject) {
273                     dummyInt1++;
274                     dummyInt2++;
275                 }
276             }
277         }
278     }
279 
280     /** Perform a recursive-only synchronized on an object within a loop. */
281     @Benchmark
282     public void testInflatedRecursiveLockUnlock() {
283         for (int i = 0; i < innerCount; i++) {
284             synchronized (lockObject3Inflated) {
285                 synchronized (lockObject3Inflated) {
286                     dummyInt1++;
287                     dummyInt2++;
288                 }
289             }
290         }
291     }
292 
293     /**
294      * Performs recursive synchronizations on the same local object.
295      * <p/>
296      * Result is 3628800
297      */
298     @Benchmark
299     public void testRecursiveSynchronization() {
300         factorial = fact(10);
301     }
302 
303     private synchronized int fact(int n) {
304         if (n == 0) {
305             return 1;
306         } else {
307             return fact(n - 1) * n;
308         }
309     }
310 
311     /**
312      * With two threads lockObject1 will be contended so should be
313      * inflated.
314      */
315     @Threads(2)
316     @Benchmark
317     public void testContendedLock() {
318         synchronized (lockObject1) {
319             dummyInt1++;
320         }
321     }
322 }