web-dev-qa-db-ja.com

DalvikとAndroidツールチェーンからどのような最適化が期待できますか?

私は高性能のAndroidアプリケーション(ゲーム)に取り組んでいます。最初は読みやすさのためにコーディングしようとしていますが、何であるかを心に留めておきたいと思います。 C++を使用して、コンパイラーが実行することと実行しないことについて、かなり良い直感を身に付けました。Java/ Androidでも同じことをしようとしています。

したがって、この質問。私はこのトピックについてウェブ上でほとんど見つけることができませんでした。 Javaコンパイラ、Dalvikコンバータ(dx)、および/またはJITter(Android 2.2+))は、次のような最適化を実行しますか?

  • メソッドのインライン化。どのような条件下で? privateメソッドは常に安全にインライン化できます。これは行われますか? public finalメソッドはどうですか?他のクラスのオブジェクトのメソッド? staticメソッド?オブジェクトの実行時型がコンパイラーによって簡単に推測できる場合はどうなりますか?可能な限り、メソッドをfinalまたはstaticとして宣言する必要がありますか?

  • 一般的な部分式除去。たとえば、someObject.someFieldに2回アクセスした場合、ルックアップは1回だけ実行されますか?ゲッターへの呼び出しの場合はどうなりますか?算術式を2回使用するとどうなりますか。一度だけ評価されますか?値が変更されないことがわかっている式の結果をforループの上限として使用するとどうなりますか?

  • 配列ルックアップの境界チェック。ツールチェーンは、典型的なforループなどの特定の条件でこれを排除しますか?

  • 値のインライン化。一部のpublic static final intへのアクセスは常にインライン化されますか?彼らが別のクラスにいても?別のパッケージに入っていても?

  • 分岐予測。これもどれほど大きな問題ですか?典型的なAndroidデバイスで大きなパフォーマンスヒットを分岐していますか?

  • 単純な算術。 someInt * 2someInt << 1に置き換えられますか?

エトセトラ...

67
Thomas

JIT @Googleで働いているエンジニアの1人であるベンです。ビルと私がこのプロジェクトを開始したときの目標は、リソースの競合(メモリフットプリント、コンパイラスレッドによってハイジャックされたCPUなど)への影響を最小限に抑えて、動作するJITをできるだけ早く提供し、ローエンドデバイスで実行できるようにすることでした。上手。したがって、非常に原始的なトレースベースのモデルを使用しました。つまり、JITコンパイラに渡されるコンパイルエンティティは基本ブロックであり、1つの命令と同じくらい短い場合もあります。このようなトレースは、インタプリタとコードキャッシュのルックアップが頻繁に呼び出されないように、チェーンと呼ばれる手法によって実行時につなぎ合わされます。ある程度のスピードアップの主な原因は、頻繁に実行されるコードパスで繰り返されるインタープリターの解析オーバーヘッドを排除することです。

とはいえ、FroyoJITではかなりの数のローカル最適化が実装されています。

  • レジスタ割り当て(JITがThumbコードを生成するためv5teターゲット用に8レジスタ/ v7用に16レジスタ)
  • スケジューリング(例:Dalvikレジスターの冗長なld/st除去、ロードホイスト、ストアシンク)
  • 冗長ヌルチェックの排除(そのような冗長性が基本ブロックにある場合)。
  • 単純なカウントループのループ形成と最適化(つまり、ループ本体に側出口がない)。このようなループの場合、拡張帰納変数に基づく配列アクセスが最適化されるため、ヌルチェックと範囲チェックはループプロローグでのみ実行されます。
  • 実行時に動的パッチを適用する仮想コールサイトごとに1つのエントリインラインキャッシュ。
  • Mul/divのリテラルオペランドの電力削減などののぞき穴最適化。

Gingerbreadでは、ゲッター/セッター用の単純なインライン化を追加しました。基盤となるJITフロントエンドは依然として単純なトレースベースであるため、呼び出し先にブランチがある場合、インライン化されません。ただし、インラインキャッシュメカニズムは、仮想ゲッター/セッターを問題なくインライン化できるように実装されています。

現在、コンパイルスコープを単純なトレースを超えて拡大し、コンパイラがコード分析と最適化のためのより大きなウィンドウを持つように取り組んでいます。乞うご期待。

104
Ben

私の答えがあなたのすべての質問に答えるわけではないと確信していますが、1つでも答えればそれは勝利だと思います。

あなたはその主題について深い知識を持っているようで、あなたが何を望んでいるかを知っているので、あなたは以下をしたいかもしれません。調査したい側面を含むサンプルアプリケーションを作成します。

取得したAPKを取得し、 APK Tool を実行します。独自のコードをリバースエンジニアリングして、意図したとおりに実行することは、私たちが知っているようにまったく問題ありません。

APKツールはリソースを抽出してデコードし、.dexファイルを.smaliファイルにリバースエンジニアリングします。 smali プロジェクトも調べて、.smaliファイルの読み取り方法とその制限に関する詳細情報を入手することをお勧めします。

繰り返しになりますが、これですべての質問に答えられるわけではないと確信していますが、良いスタートになるかもしれません。

10

まず、私はdalvikの専門家ではないので、私の回答の一部が間違っている可能性があると言って、この前置きをさせてください。しかし、私はdalvikのJITコードを掘り下げており、dalvikが実行するバイトコードについてはよく知っています。

  1. メソッドのインライン化-私が知る限り、これは決して起こりません。バイトコードレベルでは発生しないと私はほぼ確信しています。現在、JITレベルでは発生しないと思いますが、将来的には発生する可能性があります。

  2. 一般的な部分式除去-これは、非最終変数/フィールドを使用しない部分式に対してのみ行われると思います。それでもそうなるとしたら、私は完全に前向きではありません。それが行われる場合、おそらくJITレベルではなく、バイトコードレベルで行われることを期待します。

  3. 配列ルックアップの境界チェック-手がかりなし

  4. 値のインライン化-私が知る限り、はい-これらすべてのシナリオでインライン化されます。

  5. 分岐予測-わからない

  6. 単純な算術-私が知る限りではない

また、別のアプローチ方法についても触れておきたいと思います。dxとdalvikはどちらもオープンソースなので、好きなように掘り下げることができます。それらは明らかに小さなコードベースではないので、そのレベルでそれらを掘り下げるにはかなりの努力が必要です

5
JesusFreke