On Jul 9, 2014, at 8:04 PM, John Rose <john.r.r...@oracle.com> wrote:
> On Jul 9, 2014, at 3:14 AM, Paul Sandoz <paul.san...@oracle.com> wrote: > >> >> I quickly verified the fold up does as you expect. Also, if i do the >> following the null check goes away: >> >> ... >> >> void testLoop() { >> for (int i = 0; i < 1000000; i++) { >> testLoopOne(a); >> testLoopOne(snull); >> } >> } > > Good observation. So rather than missing a null-case fold-up (good it's > not!), the optimizer is speculating not-nullness (based on profile) and > adding a test. (Either the test is being used for a downstream optimization, > or else the test is not being detected as useless and removed—which would be > bad!.) > I guess it's the pesky null check in the class cast causing issues: public T cast(Object obj) { if (obj != null && !isInstance(obj)) throw new ClassCastException(cannotCastMsg(obj)); return (T) obj; } >> I am probably obsessing too much over some micro/nano-benchmarks, > > (Hi, I'm John and I'm a micro-obsess-aholic.) > :-) >> but i am wondering if this could cause some unwanted de-opt/recompilation >> effects when all is good with no null values then suddenly a null triggers >> de-optimization. > > Besides jumping after the micro-benchmark and chewing on the optimizer until > the code shrinks, there are two other things we can do: > > 1. Mentally file the issue and watch real benchmarks for evidence of the > problem. (This works pretty well, provided enough time and focus, and > provided enough people have some consciousness of the optimizer's workings.) > > 2. Create a self-test and check it into the test base. It could be either a > unit test of assertion. In this case, I don't see an easy way to do it, but > creating clever permanent tests almost always pays off much better than > cleverly pounding on the micro-benchmark of the moment. > How about the a variant of following? public class NullCheckDroppingsTest { volatile String svalue = "A"; volatile String snull = null; String ssink; public static void main(String[] args) { NullCheckDroppingsTest t = new NullCheckDroppingsTest(); t.testLoop(); } void testLoop() { // Ensure testLoopOne is compiled and does not // see a null value for (int i = 0; i < 1000000; i++) { testLoopOne(svalue); // Uncomment the following and the call outside // the loop should not result in any deoptimization // testLoopOne(snull); } // Sleep just to create delay in the compilation log try { Thread.currentThread().sleep(1000); } catch (Exception e) {} // This should cause a de-optimisation // if testLoopOne is compiled with a null-check testLoopOne(snull); } void testLoopOne(String s) { try { ssink = String.class.cast(s); } catch (Throwable t) { throw new Error(t); } } } $ java -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation NullCheckDroppingsTest 64 1 java.lang.String::hashCode (55 bytes) 69 2 java.lang.String::indexOf (70 bytes) 81 3 ! NullCheckDroppingsTest::testLoopOne (27 bytes) 81 5 n java.lang.Class::isInstance (native) 81 4 java.lang.Class::cast (27 bytes) 82 6 % ! NullCheckDroppingsTest::testLoop @ 2 (45 bytes) 85 6 % ! NullCheckDroppingsTest::testLoop @ -2 (45 bytes) made not entrant 1086 3 ! NullCheckDroppingsTest::testLoopOne (27 bytes) made not entrant The log can be searched to see of a deopt ("made not entrant") occurred or not. Paul.
signature.asc
Description: Message signed with OpenPGP using GPGMail
_______________________________________________ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev