On 11/07/2013 02:20 AM, John Rose wrote:
On Nov 6, 2013, at 11:30 AM, Peter Levart <peter.lev...@gmail.com <mailto:peter.lev...@gmail.com>> wrote:

Well, indexOf(char) or lastIndexOf(char) searches for a single char. We can do better searching backwards for two chars at the same time.

If the "name" of VM-anonymous class is always ending with pattern: "slash followed by some decimal digits" then the following would be even faster:

Although this reasoning is plausible, it is not a reliable conclusion, and should not drive edits of Java code without careful measurement. The reasoning assumes a performance model based on the interpreter and bytecode count. But performance depends on native code produced by the JIT.

I agree. I should have measured it...


An optimizing JIT will usually transform the code deeply. For string scanning, for example, HotSpot has an intrinsic for String.indexOf(String) that uses totally different code from a user-coded loop. (It is not currently so for String.indexOf(int), but String.indexOf("/") is potentially very fast.)

Also, with your example code, the combined loop may often be faster than two back-to-back loops, but simpler loops can sometimes be vectorized more robustly, to the point where back-to-back simple loops, if vectorized, may be competitive with a hand-fused loop.

So loop complexity and method intrinsics can create surprises for those who rely on simple performance modesl

Some day we will get to a world where loops are specified stream-wise, and robustly optimized without this sort of manual intervention. In the mean time, be careful about advising hand-optimizations of Java code. They can backfire, by confusing the JIT and preventing optimizations that would apply to simpler code.

— John

So I did measure it. I took two classes with the following names:

com.test.pkg.PerfTest$Classic$1
com.test.pkg.PerfTest$$Lambda$1/925858445

Typically package names will be even relatively longer than in this example.

I measured the following implementations:

    public static boolean isVMAnonymousClass(Class<?> cls) {
        return cls.getSimpleName().contains("/");
    }

    public static boolean isVMAnonymousClass_FAST1(Class<?> cls) {
        String name = cls.getName();
        for (int i = name.length() - 1; i >= 0; i--) {
            char c = name.charAt(i);
            if (c == '.') return false;
            if (c == '/') return true;
        }
        return false;
    }

    public static boolean isVMAnonymousClass_FAST2(Class<?> cls) {
        String name = cls.getName();
        for (int i = name.length() - 1; i >= 0; i--) {
            char c = name.charAt(i);
            if (c == '/') return true;
            if (c < '0' || c > '9') return false;
        }
        return false;
    }

    public static boolean isVMAnonymousClass_indexOf(Class<?> cls) {
        return cls.getName().indexOf("/") > -1;
    }


I also tried String.lastIndexOf(String) and it is a little faster for true return, since it only scans backwards until the "/" is found, but it is slower than String.indexOf(String) for "false" return. Is it not intrinsified?

Here are the results:

http://cr.openjdk.java.net/~plevart/jdk8-tl/isVmAnonymousClass/results.txt

I think that any of the above implementations that doesn't use Class.getSimpleName() is good. The FAST2 variant is favourable for false return since it typically decides after examining a single character at end of class name and is still among the fastest for true return...

Here's the code I used for testing:

http://cr.openjdk.java.net/~plevart/jdk8-tl/isVmAnonymousClass/com/test/pkg/PerfTest.java
http://cr.openjdk.java.net/~plevart/jdk8-tl/isVmAnonymousClass/si/pele/microbench/TestRunner.java


Regards, Peter

Reply via email to