Java、ランタイム最適化を探しています

CとC ++の最適化オプション開発と実行速度は Cでは 達成できません コンパイル中の最適化の詳細。 このような最適化の主な条件は、コンパイル段階でのほとんどの変数の値の可用性です。 現実の世界では、残念ながら、これは必ずしもそうではありません。



同様のことをしようとしますが、すでにプログラムを実行中です。 これを行うには、ランタイムシステムが実行時にコードを最適化するjavaを使用します。 さらに、オンザフライでコードを作成できます。





したがって、問題の条件は似ています-フィルターを使用して構造体の配列を線形検索します。 C / C ++と同等のランタイムとメモリ消費量を取得したいと思います。



レコードを表すために、 longの配列と、それらを操作するのに便利なラッパークラスを使用します: CashAccountRow



他のすべてのメカニズムは、 CashAccountStoreクラスに集中しています。

コンストラクターで、テーブルに入力します。 CashAccountFinderはプリミティブなDSLを提供し、述語リストを生成します。 コードはその場でコードを生成せずに比較のために指定されるため、述語にはfieldGetter要素が含まれます。

compileList関数は、Mapを配列に変換し、選択性に従ってソートします。



コード生成なしの検索:

public final int find(final CashAccountFinder finder) { int rValue = 0; CashAccountRow c = new CashAccountRow(); finder.compileList(); for(int i = 0; i < ROW_COUNT; ++i) { if(finder.isMatched(c.setBitStorage(accountRows[i]))) { ++rValue; } } return rValue; }
      
      





その場でコードを生成するには、 Javassistを使用します。 find2関数は、生成されたクラスの名前を作成して検索します。

 public final int find2(final CashAccountFinder finder) throws Throwable{ finder.compileList(); StringBuilder cname = new StringBuilder(); for(CashAccountFinder.PredicateHolder p: finder.predicateHolderArray) { cname.append(p.field.toString()); }
      
      





このセットおよび述語の順序に対してクラスがすでに作成されているかどうかを確認します。

 if(classMapper.containsKey(cname.toString())) { matcherBase = classMapper.get(cname.toString()); }
      
      





そうでない場合は、新しいクラスを作成します。
 //     ClassPool classPool = ClassPool.getDefault(); //  classpath      // (     classloader', //      application ,   exec-maven-plugin ) classPool.insertClassPath(new ClassClassPath(this.getClass())); //    CtClass base = classPool.get("examples.data.GenMatcherBase"); //    CtClass gen = classPool.makeClass("examples.data.GenMatcher" + cname, base); //       StringBuilder sb = new StringBuilder("public boolean c(examples.data.CashAccountRow r){ return "); for(CashAccountFinder.PredicateHolder p: finder.predicateHolderArray) { switch (p.field) { case AGE: sb.append("r.getAge() >= " + p.minValue + " && r.getAge() <= " + p.maxValue + " && "); break; case AMOUNT: sb.append("r.getAmount() >= " + p.minValue + " && r.getAmount() <= " + p.maxValue + " && "); break; case CODE: sb.append("r.getCode() >= " + p.minValue + " && r.getCode() <= " + p.maxValue + " && "); break; case GENDER: sb.append("r.getGender() >= " + p.minValue + " && r.getGender() <= " + p.maxValue + " && "); break; case HEIGHT: sb.append("r.getHeight() >= " + p.minValue + " && r.getHeight() <= " + p.maxValue + " && "); break; } } sb.append("true; }"); //      gen.addMethod(CtMethod.make(sb.toString(), gen)); //      matcherBase = (GenMatcherBase) gen.toClass().newInstance(); classMapper.put(cname.toString(), matcherBase);
      
      





検索:

  CashAccountRow c = new CashAccountRow(); int rValue = 0; for(int i = 0; i < ROW_COUNT; ++i) { if(matcherBase.c(c.setBitStorage(accountRows[i]))) { ++rValue; } }
      
      





メインでは、検索を2回実行します。 最初の起動は、「ウォームアップ」するために必要です。そのため、jitとインライン化が機能します。

  System.out.println("Warming up..."); store.find2(finder); System.out.println("Running benchmark..."); long millis = System.currentTimeMillis(); int i = store.find2(finder); long endMillis = System.currentTimeMillis();
      
      





JVM:

 Javaバージョン "1.7.0_21"
 Java(TM)SEランタイム環境(ビルド1.7.0_21-b11)
 Java HotSpot(TM)64ビットサーバーVM(ビルド23.21-b01、混合モード)


Core I5-2500k 3.3GHzでの打ち上げの結果:

ウォームアップ...
生成されたコード:
 public boolean c(examples.data.CashAccountRow r){return r.getAmount()> = 0 && r.getAmount()<= 0 && r.getHeight()> = 0 && r.getHeight()<= 0 && r .getGender()> = 0 && r.getGender()<= 0 && true;  }
ベンチマークの実行...
一致したレコードの数:38
経過時間:18ms
使用メモリ:81MB


同じマシンでの最初の記事のプログラムの結果:

生成された行:10,000,000
 C ++-検索中...
 C ++-最適化された検索には0.039000秒かかりました。
見つかった行:38
 C検索...
 C-searchは0.053000秒かかりました。
 Cより高速なC ++:1.358974回
見つかった行:38


同じマシンでの2番目の記事のプログラムの結果:

生成された行:10,000,000
 C ++-検索中...
 C ++-最適化された検索には0.012000秒かかりました
見つかった行:38
 C検索...
 C-searchは0.051000秒かかりました。
 Cより高速なC ++:4.250000回
見つかった行:38


静的に最適化されたC ++バージョンでほぼフラッシュします。 コードはGitHub.comで入手できます。




All Articles