changeset 102:62e726a16873

Backed out changeset 8046f2c4fce7
author shade
date Fri, 19 Jul 2013 23:44:06 +0400
parents 8046f2c4fce7
children 158f5aae72ce
files jmh-core-benchmarks/src/main/java/org/openjdk/jmh/benchmarks/BlackholeBench.java jmh-core/src/main/java/org/openjdk/jmh/logic/BlackHole.java jmh-core/src/test/java/org/openjdk/jmh/logic/BlackholeTest.java
diffstat 3 files changed, 84 insertions(+), 193 deletions(-) [+]
line wrap: on
line diff
--- a/jmh-core-benchmarks/src/main/java/org/openjdk/jmh/benchmarks/BlackholeBench.java	Wed Jul 17 15:14:00 2013 +0400
+++ b/jmh-core-benchmarks/src/main/java/org/openjdk/jmh/benchmarks/BlackholeBench.java	Fri Jul 19 23:44:06 2013 +0400
@@ -65,9 +65,6 @@
     public Object o;
     public Object[] os;
 
-    public boolean trueBoolean = true;
-    public boolean falseBoolean = false;
-
     @GenerateMicroBenchmark
     public void baseline() {
         // do nothing
@@ -84,26 +81,6 @@
     }
 
     @GenerateMicroBenchmark
-    public boolean implicit_testBoolean_true() {
-        return true;
-    }
-
-    @GenerateMicroBenchmark
-    public boolean implicit_testBoolean_false() {
-        return false;
-    }
-
-    @GenerateMicroBenchmark
-    public boolean implicit_testBoolean_trueF() {
-        return trueBoolean;
-    }
-
-    @GenerateMicroBenchmark
-    public boolean implicit_testBoolean_falseF() {
-        return falseBoolean;
-    }
-
-    @GenerateMicroBenchmark
     public char implicit_testChar() {
         return c;
     }
--- a/jmh-core/src/main/java/org/openjdk/jmh/logic/BlackHole.java	Wed Jul 17 15:14:00 2013 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/logic/BlackHole.java	Fri Jul 19 23:44:06 2013 +0400
@@ -42,18 +42,19 @@
 }
 
 class BlackHoleL2 extends BlackholeL1 {
-    public byte b1;
-    public boolean bool1;
-    public char c1;
-    public short s1;
-    public int i1;
-    public long l1;
-    public float f1;
-    public double d1;
-    public Object obj1;
-    public Object[] objs1;
-    public int tlr = (int)System.nanoTime(); // randomize
-    public int tlrMask = 1;
+    public volatile byte b1 = 1, b2 = 2;
+    public volatile boolean bool1 = false, bool2 = true;
+    public volatile char c1 = 'A', c2 = 'B';
+    public volatile short s1 = 1, s2 = 2;
+    public volatile int i1 = 1, i2 = 2;
+    public volatile long l1 = 1, l2 = 2;
+    public volatile float f1 = 1.0f, f2 = 2.0f;
+    public volatile double d1 = 1.0d, d2 = 2.0d;
+    public volatile Object obj1 = new Object();
+    public volatile Object[] objs1 = new Object[]{new Object()};
+    public volatile BlackHoleL2 nullBait = null;
+    public long tlr = System.nanoTime();
+    public long tlrMask = 1;
 }
 
 class BlackHoleL3 extends BlackHoleL2 {
@@ -111,21 +112,33 @@
      * We also pad with "int"-s so that dense layout in superclass does not
      * have the gap where runtime can fit the subclass field.
      * <p/>
-     * We fight the dead-code elimination by storing the result on the heap.
-     * Since heap writes are expensive (notably for objects which entail
-     * store barrier), we are using the inlined PRNG to store only every once
-     * in a while. The compilers can eliminate the slow path until it was hit,
-     * and move more computation under the branch in consume(), so we need
-     * to warm up the slow-path branch. To do that, we gradually increase the
-     * range over which we find the collision with zero for the PRNG.
+     * 2. Compilers are unable to predict the value of the volatile read.
+     * While the compilers can speculatively optimize until the relevant
+     * volatile write happens, it is unlikely to be practical to be able to stop
+     * all the threads the instant that write had happened.
      * <p/>
-     * Note that using PRNG still induces the heap writes, but those writes
-     * are consistent for every consumed data type. We use also the linear
-     * congruential generator with the glibc/gcc constants, which yields
-     * enough randomicity in minor bits to tolerate increasing bit masks
-     * (which is similar to increasing modulo), and operates on 32-bit values
-     * (which decreases the register pressure on 32-bit VMs).
+     * This allows us to compare the incoming values against the relevant
+     * volatile fields. The values in those volatile fields are never changing,
+     * but due to (2), we should re-read the values again and again.
+     * <p/>
+     * Primitives are a bit hard, because we can't predict what values we
+     * will be fed. But we can compare the incoming value with *two* distinct
+     * known values, and both checks will never be true at the same time.
+     * Note the bitwise AND in all the predicates: both to spare additional
+     * branch, and also to provide more uniformity in the performance.
+     * <p/>
+     * Objects should normally abide the Java's referential semantics, i.e. the
+     * incoming objects will never be equal to the distinct object we have, and
+     * volatile read will break the speculation about what we compare with.
+     * However, smart compilers may deduce that the distinct non-escaped object
+     * on the other side is not equal to anything we have, and fold the comparison
+     * to "false". We do inlined thread-local random to get those objects escaped
+     * with infinitesimal probability. Then again, smart compilers may skip from
+     * generating the slow path, and apply the previous logic to constant-fold
+     * the condition to "false". We are warming up the slow-path in the beginning
+     * to evade that effect.
      */
+
     private static Unsafe U;
 
     static {
@@ -145,13 +158,21 @@
     static void consistencyCheck() {
         // checking the fields are not reordered
         check("b1");
+        check("b2");
         check("bool1");
+        check("bool2");
         check("c1");
+        check("c2");
         check("s1");
+        check("s2");
         check("i1");
+        check("i2");
         check("l1");
+        check("l2");
         check("f1");
+        check("f2");
         check("d1");
+        check("d2");
         check("obj1");
         check("objs1");
     }
@@ -181,13 +202,13 @@
      */
     public final void consume(Object obj) {
         // let's play the optimizing compiler, dude!
-        int tlr = this.tlr;
-        int tlrMask = this.tlrMask;
+        long tlr = this.tlr;
+        long tlrMask = this.tlrMask;
 
-        this.tlr = (tlr * 1103515245 + 12345) & tlrMask;
-        if (tlr == 0) {
+        this.tlr = (tlr * 0x5DEECE66DL + 0xBL) & (0xFFFFFFFFFFFFL);
+        if ((tlr & tlrMask) == 0) {
             // SHOULD ALMOST NEVER HAPPEN IN MEASUREMENT
-            if (tlrMask != 0x7FFFFFFF) {
+            if (tlrMask != 0x7FFFFFFFFFFFFFFFL) {
                 this.tlrMask = (tlrMask << 1) + 1;
             }
             this.obj1 = obj;
@@ -200,13 +221,14 @@
      * @param objs objects to consume.
      */
     public final void consume(Object[] objs) {
-        int tlr = this.tlr;
-        int tlrMask = this.tlrMask;
+        // let's play the optimizing compiler, dude!
+        long tlr = this.tlr;
+        long tlrMask = this.tlrMask;
 
-        this.tlr = (tlr * 1103515245 + 12345) & tlrMask;
-        if (tlr == 0) {
+        this.tlr = (tlr * 0x5DEECE66DL + 0xBL) & (0xFFFFFFFFFFFFL);
+        if ((tlr & tlrMask) == 0) {
             // SHOULD ALMOST NEVER HAPPEN IN MEASUREMENT
-            if (tlrMask != 0x7FFFFFFF) {
+            if (tlrMask != 0x7FFFFFFFFFFFFFFFL) {
                 this.tlrMask = (tlrMask << 1) + 1;
             }
             this.objs1 = objs;
@@ -219,16 +241,9 @@
      * @param b object to consume.
      */
     public final void consume(byte b) {
-        int tlr = this.tlr;
-        int tlrMask = this.tlrMask;
-
-        this.tlr = (tlr * 1103515245 + 12345) & tlrMask;
-        if (tlr == 0) {
-            // SHOULD ALMOST NEVER HAPPEN IN MEASUREMENT
-            if (tlrMask != 0x7FFFFFFF) {
-                this.tlrMask = (tlrMask << 1) + 1;
-            }
-            this.b1 = b;
+        if (b == b1 & b == b2) {
+            // SHOULD NEVER HAPPEN
+            nullBait.b1 = b; // implicit null pointer exception
         }
     }
 
@@ -238,16 +253,9 @@
      * @param bool object to consume.
      */
     public final void consume(boolean bool) {
-        int tlr = this.tlr;
-        int tlrMask = this.tlrMask;
-
-        this.tlr = (tlr * 1103515245 + 12345) & tlrMask;
-        if (tlr == 0) {
-            // SHOULD ALMOST NEVER HAPPEN IN MEASUREMENT
-            if (tlrMask != 0x7FFFFFFF) {
-                this.tlrMask = (tlrMask << 1) + 1;
-            }
-            this.bool1 = bool;
+        if (bool == bool1 & bool == bool2) {
+            // SHOULD NEVER HAPPEN
+            nullBait.bool1 = bool; // implicit null pointer exception
         }
     }
 
@@ -257,16 +265,9 @@
      * @param c object to consume.
      */
     public final void consume(char c) {
-        int tlr = this.tlr;
-        int tlrMask = this.tlrMask;
-
-        this.tlr = (tlr * 1103515245 + 12345) & tlrMask;
-        if (tlr == 0) {
-            // SHOULD ALMOST NEVER HAPPEN IN MEASUREMENT
-            if (tlrMask != 0x7FFFFFFF) {
-                this.tlrMask = (tlrMask << 1) + 1;
-            }
-            this.c1 = c;
+        if (c == c1 & c == c2) {
+            // SHOULD NEVER HAPPEN
+            nullBait.c1 = c; // implicit null pointer exception
         }
     }
 
@@ -276,16 +277,9 @@
      * @param s object to consume.
      */
     public final void consume(short s) {
-        int tlr = this.tlr;
-        int tlrMask = this.tlrMask;
-
-        this.tlr = (tlr * 1103515245 + 12345) & tlrMask;
-        if (tlr == 0) {
-            // SHOULD ALMOST NEVER HAPPEN IN MEASUREMENT
-            if (tlrMask != 0x7FFFFFFF) {
-                this.tlrMask = (tlrMask << 1) + 1;
-            }
-            this.s1 = s;
+        if (s == s1 & s == s2) {
+            // SHOULD NEVER HAPPEN
+            nullBait.s1 = s; // implicit null pointer exception
         }
     }
 
@@ -295,16 +289,9 @@
      * @param i object to consume.
      */
     public final void consume(int i) {
-        int tlr = this.tlr;
-        int tlrMask = this.tlrMask;
-
-        this.tlr = (tlr * 1103515245 + 12345) & tlrMask;
-        if (tlr == 0) {
-            // SHOULD ALMOST NEVER HAPPEN IN MEASUREMENT
-            if (tlrMask != 0x7FFFFFFF) {
-                this.tlrMask = (tlrMask << 1) + 1;
-            }
-            this.i1 = i;
+        if (i == i1 & i == i2) {
+            // SHOULD NEVER HAPPEN
+            nullBait.i1 = i; // implicit null pointer exception
         }
     }
 
@@ -314,16 +301,9 @@
      * @param l object to consume.
      */
     public final void consume(long l) {
-        int tlr = this.tlr;
-        int tlrMask = this.tlrMask;
-
-        this.tlr = (tlr * 1103515245 + 12345) & tlrMask;
-        if (tlr == 0) {
-            // SHOULD ALMOST NEVER HAPPEN IN MEASUREMENT
-            if (tlrMask != 0x7FFFFFFF) {
-                this.tlrMask = (tlrMask << 1) + 1;
-            }
-            this.l1 = l;
+        if (l == l1 & l == l2) {
+            // SHOULD NEVER HAPPEN
+            nullBait.l1 = l; // implicit null pointer exception
         }
     }
 
@@ -333,16 +313,9 @@
      * @param f object to consume.
      */
     public final void consume(float f) {
-        int tlr = this.tlr;
-        int tlrMask = this.tlrMask;
-
-        this.tlr = (tlr * 1103515245 + 12345) & tlrMask;
-        if (tlr == 0) {
-            // SHOULD ALMOST NEVER HAPPEN IN MEASUREMENT
-            if (tlrMask != 0x7FFFFFFF) {
-                this.tlrMask = (tlrMask << 1) + 1;
-            }
-            this.f1 = f;
+        if (f == f1 & f == f2) {
+            // SHOULD NEVER HAPPEN
+            nullBait.f1 = f; // implicit null pointer exception
         }
     }
 
@@ -352,20 +325,13 @@
      * @param d object to consume.
      */
     public final void consume(double d) {
-        int tlr = this.tlr;
-        int tlrMask = this.tlrMask;
-
-        this.tlr = (tlr * 1103515245 + 12345) & tlrMask;
-        if (tlr == 0) {
-            // SHOULD ALMOST NEVER HAPPEN IN MEASUREMENT
-            if (tlrMask != 0x7FFFFFFF) {
-                this.tlrMask = (tlrMask << 1) + 1;
-            }
-            this.d1 = d;
+        if (d == d1 & d == d2) {
+            // SHOULD NEVER HAPPEN
+            nullBait.d1 = d; // implicit null pointer exception
         }
     }
 
-    public static volatile int consumedCPU = 42;
+    public static volatile long consumedCPU = 42;
 
     /**
      * Consume some amount of time tokens.
@@ -377,10 +343,10 @@
      */
     public static void consumeCPU(long tokens) {
         // randomize start so that JIT could not memoize;
-        int t = consumedCPU;
+        long t = consumedCPU;
 
         for (long i = 0; i < tokens; i++) {
-            t += (t * 1103515245 + 12345);
+            t += (t * 0x5DEECE66DL + 0xBL) & (0xFFFFFFFFFFFFL);
         }
 
         // need to guarantee side-effect on the result,
--- a/jmh-core/src/test/java/org/openjdk/jmh/logic/BlackholeTest.java	Wed Jul 17 15:14:00 2013 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.openjdk.jmh.logic;
-
-import junit.framework.Assert;
-import org.junit.Test;
-
-public class BlackholeTest {
-
-    @Test
-    public void generatorTest() {
-        int tlr = (int) System.nanoTime();
-        int tlrMask = 0;
-
-        int flips = 0;
-
-        for (int i = 0; i < Integer.MAX_VALUE; i++) {
-            tlr = (tlr * 1103515245 + 12345) & tlrMask;
-            if (tlr == 0) {
-                if (tlrMask != 0x7FFFFFFF) {
-                    tlrMask = (tlrMask << 1) + 1;
-                }
-                flips++;
-            }
-        }
-
-        Assert.assertEquals(31, flips); // flipped for every tlrMask
-    }
-
-}