9

更新:私の13.0.1がこのdiffedCharMatcherからコードを呼び出しているようです。

http://code.google.com/p/guava-libraries/source/diff?spec=svn69ad96b719d7cd3d872a948d7454f17b816a21c2&r=464b0cfab7c3b6713c35e6f3ae7426542668c77b&format=side&path=/guava/src/com/google/common

GuavaのCharmatcherに問題があるようです。私は現在いくつかのJUnitテストを書いていますが、最初のテストには少し時間がかかる(15秒以上)ことに気づいていますが、将来のテストはすべてほぼ同じ(.3秒)で、テストの大部分は同じもので実行されますコード。

コードを分析したところ、GuavaのライブラリにあるCharmatcherが原因のようであることがわかりました。CharMatcherには静的な初期化コードが少しあるようですが、これが時間がかかる本当の理由かもしれません。この動作を無効化または最適化する方法はありますか?ウィキページやヘルプファイルに欠けているものはありますか?

Guavaバージョン13.0.1、システム:Linux 64、Eclipse 3.6.1

編集:次のコードでテストアプリを作成しました:

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");
    }
}

これにより、次の出力が得られました。

took 15945 ms
2nd took 0 ms

私はこれをEclipseからJUnitフレームワークを除いて実行し、Googleのguavaライブラリだけを実行しました。また、実行可能charをパッケージ化して、同様の結果を受け取りました。プロファイラーを実行した後、2回目の編集で戻ってきます。

助けてくれてありがとう。

編集2:プロファイリングの結果:

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
4

4 に答える 4

10

更新:これはGuava14で修正されています。

u21、およびおそらく以前のバージョンに存在するある種のJITバグに遭遇していますが、少なくともいくつかの新しいJDKバージョンには遭遇していません。u21でのテストプログラムの-XX:+PrintCompilation出力は次のとおりです。

  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

u34の同じ出力は次のとおりです。

 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)

あなたが見ることができるように、それはu34ではるかに正気の地獄です。u21で起こっていることは、OSRslowGetChars大きなループがあるためメソッドに影響を与える)と再帰的なメガモーフィック呼び出し(再帰チェーンの最後で呼び出される-の影響CharMatcher$Orおよび他のサブクラス)のいくつかの組み合わせが完全なものを生成することです。 JITの最適化解除とその後の再コンパイルの嵐。これは、u34で解決されています。CharMatcherCharMatcher$Or

それでも、問題のマッチャーを使用したことがない場合でも、静的init中に65k要素のLUTを作成することで、Guavaの人たちは少し虐待していると思います。これは、JITが正常に動作しているときに約50msかかります。グアバに対してバグを報告しました。メンテナが同意するかどうか見てみましょう:)。更新:バグは私がこれを提出してから数日以内に修正されました。修正はGuava 14で行われます。それは私がクイックターンアラウンドと呼んでいるものです!

元の投稿は次のとおりです。

私はまったく同じ振る舞いをしていて、解決策を探してこの投稿に出くわしました。

コードを見ると、65k要素(各要素は1ビットを取る)ルックアップテーブルを作成し、すべての文字が一致するかどうかをチェックしているようです。これには、マッチャーの定義に流暢なスタイルが使用されているため、多くのネストされた関数呼び出しが必要です。

  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();

これが長い静的初期化をトリガーするコードであり、私の高速ボックスでは約7秒かかります。これが私のボックスでのアプリの出力です。

took 6814 ms
2nd took 0 ms

私はグアバのバグを提出しています。

于 2012-11-06T01:57:05.167 に答える
2

クイックヘルプとして、ソースリポジトリから最新バージョンに切り替えてみてください。そこには変更があります。たとえば、メソッドslowGetCharsなくなりました。以前は少し遅かったのですが、あなたに起こっていることにはほど遠いです。

他のすべての人にとって、それは数百倍速く実行され、それを再現することができなければ、助けるのは難しいです。

于 2012-10-30T20:51:44.253 に答える
1

でテストしたばかり:

@Test
public void testCharMatcherSlow() throws Exception {
    System.out.println(CharMatcher.JAVA_DIGIT.matches('1'));
}

実行には0.06秒かかりました。CharMatcherコードも調べましたが、遭遇する動作が遅いことを説明できるものは何もありません。CharMatcherをモックに置き換えて、問題がないことを確認し、プロファイラーを使用して原因を特定する必要があります。

于 2012-10-30T18:15:18.920 に答える
0

私はあなたが提供した正確なベンチマークを実行し、

74ミリ秒かかりました

2番目は0ミリ秒かかりました

...おそらく問題はEclipse側にありますか?デバッグモードで実行していますか?

于 2012-10-30T19:13:11.003 に答える