Java – guava charmatcher static initialization slow
Update: looks like my 13.0 1 is the calling code from this diffed charmatcher
http://code.google.com/p/guava-libraries/source/diff?spec=svn69ad96b719d7cd3d872a948d7454f17b816a21c2&r=464b0cfab7c3b6713c35e6f3ae7426542668c77b&format=side&path=/guava/src/com/google/common/base/CharMatcher.java
I seem to have a problem with guava's charmatcher I'm writing some JUnit tests. I noticed that the first test takes a little time (15 seconds), but the future tests are roughly the same (. 3 seconds). Most of the tests run in the same code
My analysis of the code points out that charmatcher in guava's Library seems to be the culprit It seems that charmatcher has some static initialization code, which may be the real reason Is there any way to disable or optimize this behavior? Is there anything missing from Wiki pages or help files?
Guava version 13.0 1. System: Linux 64, eclipse 3.6 one
Edit: I built a test application using the following code:
import com.google.common.base.CharMatcher; public class Main { public static void main(String[] args) { // Using system instead of stopwatch to isolate library. long startTime = System.currentTimeMillis(); CharMatcher.is(' '); long endTime = System.currentTimeMillis(); System.out.println("took " + String.valueOf(endTime-startTime) + " ms"); startTime = System.currentTimeMillis(); CharMatcher.is('d'); endTime = System.currentTimeMillis(); System.out.println("2nd took " + String.valueOf(endTime-startTime) + " ms"); } }
This results in the following outputs:
took 15945 ms 2nd took 0 ms
I run the JUnit framework in eclipse, just Google's guava library In addition, I packaged an executable char and got similar results After I run the analyzer through it, I will edit it again
Thank you for any help
Edit 2: analysis results:
Main.main(String[]) 22,556 ms com.google.common.base.CharMatcher.<clinit>() 22.556 ms com.google.common.base.CharMatcher.precomputed() 22,550 ms com.google.common.base.Platform.precomputeCharMatcher(CharMatcher) 22,550 ms com.google.common.base.CharMatcher.precomputedInternal() 22,550 ms com.google.common.base.CharMatcher.slowGetChars() 13,638 ms com.google.common.base.CharMatcher.setBits(CharMatcher$LookupTable) 8,911 ms
Solution
Update: This is fixed in guava 14
You are experiencing some kind of JIT error in U21, which may be an earlier version, but at least in some JDK versions This is the - XX: printcompilation output of the program you tested in U21:
1 java.util.Arrays::binarySearch0 (72 bytes) 2 com.google.common.base.CharMatcher$Or::matches (28 bytes) 3 com.google.common.base.CharMatcher$12::matches (22 bytes) 2 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 4 com.google.common.base.CharMatcher$11::matches (17 bytes) 5 java.util.Arrays::binarySearch (9 bytes) 6 com.google.common.base.CharMatcher$Or::matches (28 bytes) 1% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 6 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 7 com.google.common.base.CharMatcher$Or::matches (28 bytes) 7 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 1% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 2% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 8 com.google.common.base.CharMatcher$Or::matches (28 bytes) 8 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 2% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 3% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 9 com.google.common.base.CharMatcher$Or::matches (28 bytes) 9 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 3% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 4% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 10 com.google.common.base.CharMatcher$Or::matches (28 bytes) 10 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 4% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 11 com.google.common.base.CharMatcher$Or::matches (28 bytes) 5% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 11 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 12 com.google.common.base.CharMatcher$Or::matches (28 bytes) 5% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 12 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 6% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 13 com.google.common.base.CharMatcher$Or::matches (28 bytes) 13 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 6% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 7% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 14 com.google.common.base.CharMatcher$Or::matches (28 bytes) 15 com.google.common.base.CharMatcher::slowGetChars (52 bytes) 14 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 7% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 16 com.google.common.base.CharMatcher$Or::matches (28 bytes) 16 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 17 com.google.common.base.CharMatcher$Or::matches (28 bytes) 17 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 8% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 18 com.google.common.base.CharMatcher$Or::matches (28 bytes) 18 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 19 com.google.common.base.CharMatcher$Or::matches (28 bytes) 19 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 20 com.google.common.base.CharMatcher$Or::matches (28 bytes) 8% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 20 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 21 com.google.common.base.CharMatcher$Or::matches (28 bytes) 21 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 22 com.google.common.base.CharMatcher$Or::matches (28 bytes) 9% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 22 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 23 com.google.common.base.CharMatcher$Or::matches (28 bytes) 23 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 24 com.google.common.base.CharMatcher$Or::matches (28 bytes) 24 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 9% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 25 com.google.common.base.CharMatcher$Or::matches (28 bytes) 25 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 26 com.google.common.base.CharMatcher$Or::matches (28 bytes) 26 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 10% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 27 com.google.common.base.CharMatcher$Or::matches (28 bytes) 27 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 28 com.google.common.base.CharMatcher$Or::matches (28 bytes) 28 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 10% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 29 com.google.common.base.CharMatcher$Or::matches (28 bytes) 29 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 30 com.google.common.base.CharMatcher$Or::matches (28 bytes) 30 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 11% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 31 com.google.common.base.CharMatcher$Or::matches (28 bytes) 31 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 32 com.google.common.base.CharMatcher$Or::matches (28 bytes) 32 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 11% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 33 com.google.common.base.CharMatcher$Or::matches (28 bytes) 33 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 34 com.google.common.base.CharMatcher$Or::matches (28 bytes) 34 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 35 com.google.common.base.CharMatcher$Or::matches (28 bytes) 12% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 35 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 36 com.google.common.base.CharMatcher$Or::matches (28 bytes) 36 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 37 com.google.common.base.CharMatcher$Or::matches (28 bytes) 37 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 12% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 38 com.google.common.base.CharMatcher$Or::matches (28 bytes) 38 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 39 com.google.common.base.CharMatcher$Or::matches (28 bytes) 39 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 13% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 40 com.google.common.base.CharMatcher$Or::matches (28 bytes) 40 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 41 com.google.common.base.CharMatcher$Or::matches (28 bytes) 41 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 13% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 42 com.google.common.base.CharMatcher$Or::matches (28 bytes) 42 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 43 com.google.common.base.CharMatcher$Or::matches (28 bytes) 43 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 44 com.google.common.base.CharMatcher$Or::matches (28 bytes) 14% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 44 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 45 com.google.common.base.CharMatcher$Or::matches (28 bytes) 45 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 46 com.google.common.base.CharMatcher$Or::matches (28 bytes) 46 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 14% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 47 com.google.common.base.CharMatcher$Or::matches (28 bytes) 47 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 48 com.google.common.base.CharMatcher$Or::matches (28 bytes) 48 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 15% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 49 com.google.common.base.CharMatcher$Or::matches (28 bytes) 49 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 50 com.google.common.base.CharMatcher$Or::matches (28 bytes) 50 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 15% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 51 com.google.common.base.CharMatcher$Or::matches (28 bytes) 51 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 52 com.google.common.base.CharMatcher$Or::matches (28 bytes) 52 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 16% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 53 com.google.common.base.CharMatcher$Or::matches (28 bytes) 53 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 54 com.google.common.base.CharMatcher$Or::matches (28 bytes) 54 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 16% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 55 com.google.common.base.CharMatcher$Or::matches (28 bytes) 55 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 56 com.google.common.base.CharMatcher$Or::matches (28 bytes) 56 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 57 com.google.common.base.CharMatcher$Or::matches (28 bytes) 17% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 57 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 58 com.google.common.base.CharMatcher$Or::matches (28 bytes) 58 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 59 com.google.common.base.CharMatcher$Or::matches (28 bytes) 59 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 17% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 60 com.google.common.base.CharMatcher$Or::matches (28 bytes) 60 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 61 com.google.common.base.CharMatcher$Or::matches (28 bytes) 61 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 18% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 62 com.google.common.base.CharMatcher$Or::matches (28 bytes) 62 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 63 com.google.common.base.CharMatcher$Or::matches (28 bytes) 63 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 18% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 64 com.google.common.base.CharMatcher$Or::matches (28 bytes) 64 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 65 com.google.common.base.CharMatcher$Or::matches (28 bytes) 65 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 19% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 66 com.google.common.base.CharMatcher$Or::matches (28 bytes) <I omitted ~500 very similar lines here> 143% made not entrant com.google.common.base.CharMatcher::setBits @ -2 (30 bytes) 144% com.google.common.base.CharMatcher::setBits @ 2 (30 bytes) 144% made not entrant com.google.common.base.CharMatcher::setBits @ -2 (30 bytes) 145% com.google.common.base.CharMatcher::setBits @ 2 (30 bytes) 145% made not entrant com.google.common.base.CharMatcher::setBits @ -2 (30 bytes) took 7599 ms 2nd took 0 ms
The output of u34 is the same:
64 1 java.util.Arrays::binarySearch0 (72 bytes) 68 2 com.google.common.base.CharMatcher$Or::matches (28 bytes) 68 3 com.google.common.base.CharMatcher$12::matches (22 bytes) 70 4 com.google.common.base.CharMatcher$11::matches (17 bytes) 71 5 java.util.Arrays::binarySearch (9 bytes) 71 1% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 76 2 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 76 6 com.google.common.base.CharMatcher$Or::matches (28 bytes) 88 1% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 88 6 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 88 7 com.google.common.base.CharMatcher::slowGetChars (52 bytes) 89 8 com.google.common.base.CharMatcher$Or::matches (28 bytes) 91 9 com.google.common.base.CharMatcher$8::matches (14 bytes) 91 2% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 98 10 java.lang.String::indexOf (166 bytes) 98 11 java.lang.String::indexOf (151 bytes) 102 3% com.google.common.base.CharMatcher::setBits @ 2 (30 bytes) 113 12 com.google.common.base.CharMatcher::setBits (30 bytes) 113 13 com.google.common.base.CharMatcher$LookupTable::set (15 bytes)
As you can see, this is a very rational hell in u34 It looks like what happened in U21. Some combinations of OSR (affecting the slowgetchars method because it has a large loop) and recursive deformation calls (affecting charmatcher $or and other subclasses of charmatcher - called at the end of recursion) charmatcher $or chain produce a perfect storm JIT to optimize and then recompile, which is solved in u34
Nevertheless, I think that in the static initialization process, by creating a 65K element LUT, even if you do not use the matcher in question, guava users are still a little insulted. When the JIT works normally, it still takes about 50ms I submit a bug against guava. Let's see if the maintainer agrees:) Update: this bug was fixed in a few days. This fix will be in guava 14 This is what I call a quick turnaround!
Original text:
I have exactly the same behavior, encountered this post to find a solution
Looking at the code, it seems that they are making a 65K element (one bit per element) lookup table and checking whether each character matches. This requires many nested function calls, because the matcher is defined in a smooth style:
public static final CharMatcher INVISIBLE = inRange('\u0000','\u0020') .or(inRange('\u007f','\u00a0')) .or(is('\u00ad')) .or(inRange('\u0600','\u0604')) .or(anyOf("\u06dd\u070f\u1680\u180e")) .or(inRange('\u2000','\u200f')) .or(inRange('\u2028','\u202f')) .or(inRange('\u205f','\u2064')) .or(inRange('\u206a','\u206f')) .or(is('\u3000')) .or(inRange('\ud800','\uf8ff')) .or(anyOf("\ufeff\ufff9\ufffa\ufffb")) .withToString("CharMatcher.INVISIBLE") .precomputed();
This is the code that triggers long static init, which takes about 7 seconds in my quick box This is the output of your application on my box:
took 6814 ms 2nd took 0 ms
I'm submitting a guava bug