燭台vsロリポップ

Google Playのユニットが「ブレーキ」のために注ぎ始めた新しい2015年の祝賀の後、 Android開発チームには落ち着いた時間がありませんでした。 ユニットは、Nexus 5、6、7などの強力なデバイスのユーザーから注がれました。それらを結合したのは、オペレーティングシステムであるAndroid 5(Lollipop)だけでした。



ご存知のように、新年の少し前に、GoogleはAndroidモバイルオペレーティングシステムのアップデートをリリースしました。 その際立った機能には、古いDalvik仮想マシンではなく、まったく新しいARTランタイム(Android RunTimeの略)への移行がありました。 実際、これはARTとDalvikの違いです。新しいランタイムは仮想マシンではなくなりました。 代わりに、インストール中にアプリケーションをコンパイルするため、作業が大幅にスピードアップします。



「ブレーキ」はどこから来たのですか? まず、それらを再現することにしました。 このために、2つの同一のNexus 5を使用しました。1つは最新のAndroid 5ファームウェア、もう1つはAndroid 4.4(KitKat)です。 保存したゲームの同一のファイルをダウンロードし、両方のアプリケーションにアクセスして、保存したゲームを起動しました。 Androidの最新バージョンを搭載したデバイスの進行状況インジケーターはほとんど半分になりませんが、KitKatデバイスは既にいくつかの動きをしています。 確かに、ブレーキがあります。



Googleは、開発者向けのオプションとしてARTをAndroid 4.4で一般に公開し、Dalvikをデフォルトのままにしました。 Nexus 5をAndroid 4.4からARTに切り替えて、同じ保存ゲームを試しました。 驚いたことに、この動きの計算は、以前と同じDalvikでの速度で行われました。



これらすべてについて説明が必要ですか? Android SDKに付属の標準プロファイリングを試しました。 しかし、驚いたことに、彼は計算の速度に大きな違いを示さなかった。



おそらくARTは未加工であり、ARTでコンパイルされたコードはDalvik JITコンパイラーで生成されたコードよりも遅いのでしょうか? それを提案できます。 しかし、KitKatのARTは、Dalvikほどコードを実行しませんでした。 私たちと他の人々のパフォーマンス測定器の両方が、ART全体がDalvikよりも速いことを示しました。 しかし、私たちの好みでは、Lollipopで何倍も遅く実行される単体テストがありました。 コードを詳しく調べて、この動作の考えられる理由を探すことにしました。



コードの分析中に、ユニットテストの1つの機能に気付きました。これは、Googleの最新のアプリケーションランタイムでははるかに低速でした。 コード自体はプリミティブなビット操作で構成されていたため、疑いを抱くことはありませんでした。 特異性は、彼らが呼ばれた方法でした。



コードは次のように編成されました。いくつかの子孫を持つ抽象LookOver基本クラスです。 このクラス内には、LookOver自体と後続バージョンの両方で計算に使用される静的なfinalメソッドがあります。 したがって、静的メソッドは、スコープを拡張しないように保護されていると宣言されました。



public class LookOver { protected static final long newCount(final int w, final int index) { return ((long) (w & 0xFF) << (index << 3)); } protected static final byte extractW0(final long count) { return (byte) count; } protected static final byte extractW1(final long count) { return (byte) (count >>> 8); } protected static final byte extractW2(final long count) { return (byte) (count >>> 16); } protected static final byte extractWin(final long count) { return (byte) (count >>> 24); } }
      
      







これは、このクラスのおおよその子孫のようです:



 public class LookOverTest extends LookOver { public void performCalculations() { final int min = 0; final int max = 50; for (int b1 = min; b1 <= max; b1++) { for (int b2 = min; b2 <= max; b2++) { for (int b3 = min; b3 <= max; b3++) { for (int b4 = min; b4 <= max; b4++) { final long value = newCount(b1, 0) | newCount(b2, 1) | newCount(b3, 2) | newCount(b4, 3); if (!(b1 == extractW0(value) && b2 == extractW1(value) && b3 == extractW2(value) && b4 == extractWin(value))) { throw new RuntimeException("Should not happen"); } } } } } } }
      
      







Javaバイトコードでは、これらの静的呼び出しはINVOKESTATIC LookOverTest.methodName()として表されます。



同時に、LookOverクラスの継承者からではなく呼び出した場合、呼び出しはINVOKESTATIC LookOver.methodName()のようになります。



この仮説を試してみました:拡張を削除し、追加しました



 import static com.example.benchmark.LookOver.*;
      
      







そして、彼らは立ち上げました。 変更前に上記のコードがLollipopで36秒間実行された場合、その後はわずか0.8秒です! 問題が見つかりました! 私たちは、好みの同様のコードをすべて、静的メソッドのみで構成される個別の実用的なクラスに取りました。 そして、これにより、ゲーム内のコースの計算がキットカットで以前よりもさらに高速になりました-ARTランタイムのおかげです。



もちろん、Googleの開発者の1人が、このようなリグレッションの燭台で脅かすことはありません。 しかし、最も重要なこと-私たちの問題は解決され、更新されたリリースが既にGoogle Playに投稿されています。 そして、研究をHabrと共有できることを嬉しく思います。



UPD: datacompboyがリンクを送信しました: android-review.googlesource.com / # / c / 125900エラーが修正され、レビューに合格しました。



All Articles