Chrome のコードをパーティショニングして Android での起動時間を短縮する

この記事は Chrome ソフトウェア エンジニア、Clark Duvall による Chromium Blog の記事 “Partitioning Chrome’s Code for Faster Launch Times on Android” を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。

通常、モバイル デバイスは、ノートパソコンやデスクトップよりもリソースが限られています。モバイル ユーザーが Chrome を高速に使えるようにするには、Chrome のリソース使用の最適化が欠かせません。Android 版の Chrome に機能を追加するにつれて、アプリにパッケージ化される Java コードの量は増え続けています。今回の速さと好奇心の投稿では、Isolated Splits によって Android 版 Chrome のスピードとメモリ使用量をどのように改善したのかについて説明します。この改善により、Android 版 Chrome のメモリ使用量が 5-7% 減少し、起動とページ読み込みの速度もさらに向上しました。

問題

Android アプリ(Android 版 Chrome も含む)では、コンパイルされた Java コードが .dex ファイルに格納されます。Android 版 Chrome にはマルチプロセス アーキテクチャが採用されているため、そのユーザー エクスペリエンスが .dex サイズの増加に特に影響されやすくなります。通常、Android の Chrome では、ブラウザ プロセス、GPU プロセス、1 つ以上のレンダラ プロセスという 3 つ以上のプロセスが常に実行されています。Chrome の Java コードの大半はブラウザ プロセスでのみ使われます。しかし、そのコードを読み込むためのパフォーマンスとメモリのコストは、すべてのプロセスが支払うことになります。

 

バンドルと機能モジュール

プロセスを実行するために必要な最小チャンクの Java を読み込むことができれば理想的です。Android App Bundle を使ってコードを機能モジュールに分割することで、それに近づくことができます。機能モジュールを使うと、コードやリソース、アセットを個別の APK に分割し、オンデマンドでもアプリのインストール時でも、ベース APK とともにインストールできます。

ということは、まさに必要としているものが手に入りそうです。つまり、ブラウザ プロセスのコード用機能モジュールを作り、必要なときにそれを読み込むことができるかもしれません。しかし、Android はそのようにして機能モジュールを読み込むわけではありません。デフォルトで、すべてのインストールされている機能モジュールは起動時に読み込まれます。ベース モジュールと 3 つの機能モジュール “a”、”b”、”c” があるアプリなら、Android の Context と、次のような ClassLoader が得られます。

状況によっては、インストールするモジュールを最低限にとどめ、起動時にこれらのモジュールすべてを即座に読み込むという方法が役立つこともあります。たとえば、一部のユーザーしか必要としない大きな機能がある場合、必要のないユーザーはそれをまったくインストールしないようにします。しかし、一般的に使われる機能の場合、実行時に機能をダウンロードしなければならないと、ユーザーは不便を感じる可能性があります。たとえば、動作が遅くなったり、モバイルデータが利用できないときに問題になったりします。理想的な方法は、標準モジュールをすべて事前にインストールしておいて、実際に必要になったときのみ読み込むことです。

解決策は Isolated Splits

数日間 Android ソースコードを探し続けた結果、android:isolatedSplits という属性が見つかりました。これを “true” に設定すると、インストールされた分割 APK が起動時に読み込まれなくなり、明示的な読み込みが必要になります。これこそ、プロセスのリソース使用量を減らすために必要としていたものです。これにより、先ほどの ClassLoader は次のようになります。

Chrome では、レンダラーや GPU プロセスに必要な少量のコードを引き続きベース モジュールに配置し、ブラウザなどの高価な機能のコードは機能モジュールに分割し、必要なときに読み込みます。この方法を使うことで、子プロセスに読み込まれる .dex サイズを 75% 減らし、最大 2.5 MB にすることができました。その結果、起動が速くなり、メモリ使用量も減りました。

このアーキテクチャによって、ブラウザ プロセスの最適化も可能になります。アプリケーションの初期化中にブラウザ プロセスのコードの大部分をバックグラウンド スレッドでプリロードした場合も起動時間を短縮でき、読み込み時間が 7.6% 高速になりました。ブラウザのコードが必要なアクティビティなどのコンポーネントが起動するときには、すでに読み込みが終わっています。機能モジュールへの機能の割り当てを最適化すると、オンデマンドで機能を読み込むことができます。これにより、機能が実際に使われるまで、メモリや読み込みのコストを節約できます。

結果

M89 で Chrome に Isolated Splits が搭載されて以来、数か月にわたる実際のデータが蓄積されており、Android Oreo 以降を実行しているすべての Android ユーザーの Chrome で、メモリ使用量、起動時間、ページ読み込みのスピード、安定性が大きく改善されたことがわかりました。

  • 合計メモリ使用量の中央値が 5.2% 改善
  • レンダラー プロセスのメモリ使用量の中央値が 7.9% 改善
  • GPU プロセスのメモリ使用量の中央値が 7.6% 改善
  • ブラウザ プロセスのメモリ使用量の中央値が 1.2% 改善
  • 起動時間の 95 パーセンタイルが 7.6% 改善
  • ページ読み込みスピードの 95 パーセンタイルが 2.3% 改善
  • ブラウザのクラッシュ率とレンダラーのハング率の両方が大幅に改善

すべての統計情報の出典 : Chrome クライアントから匿名で集計した実データ

Reviewed by Eiji Kitamura – Developer Relations Team<!—->

Chrome の検索、ブラウズ、シャットダウン時のパフォーマンスを改善

この記事は Chrome ブラウザ、プロダクト マネージャー、Yana Yushkina による Chromium Blog の記事 “Searching, browsing, and shutdown Chrome performance improvements” を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。

Chrome では、さまざまなプロジェクトを通じて、パフォーマンスを改善するための長期的な取り組みが行われています。今回の速さと好奇心シリーズの投稿では、スピード、メモリ、意図しないハングに関する改善について紹介します。現在、検索の 6 回に 1 回は一瞬で終わり、PartitionAlloc に関する作業によって Chrome OS でのブラウジングで最大 20% のメモリが削減され、Chrome OS と Windows のシャットダウン操作に関する厄介な問題も解消されています。

アドレスバー

Chrome のアドレスバーを使ってウェブを検索すると、文字を入力するのに合わせて検索語句の候補が表示されることに気づくはずです(Chrome の設定で [ 検索語句や URL をオートコンプリートする ] 機能をオンにしている場合)。これにより、検索語句すべてを入力する必要がなくなるので、情報の検索が迅速かつ簡単になります。求めている検索語句が提案されるまでテキストを入力すれば、すぐにそれを選択できます。

Chrome で検索すれば、さらに高速になります。提案された検索語句が選ばれる可能性が高い場合、検索結果がプリフェッチされるようになったからです。つまり、皆さんが検索語句を選択する前にウェブサーバーから結果を取得するので、検索結果が表示されるまでの時間がさらに短縮されます。実際に実験を行ったところ、検索結果が 500 ミリ秒以内に表示される可能性が 4 倍になったことがわかりました。

現在、この処理が行われるのは、Google 検索がデフォルトの検索エンジンになっている場合だけです。しかし、こちらの記事で説明しているように、提案する検索語句をサーバーから Chrome に送信する際に情報を追加することで、他の検索プロバイダもこの機能をトリガーできます。

Chrome OS の PartitionAlloc

Chrome の新しいメモリ アロケータである PartitionAlloc は、M89 で Android と Windows にロールアウトされました。その結果、メモリ使用量を「最大 22% 節約」でき、パフォーマンスについては「応答性が最大 9% 向上」しました。それ以降も、Linux には M92 で、Chrome OS には M93 で PartitionAlloc を導入しました。うれしいことに、Chrome OS の M93 のフィールド データから、合計メモリ フットプリントが 15%、ブラウザ プロセスのメモリが 20% 減少し、単一タブ、複数タブの両方で Chromebook のブラウジング体験が向上したことがわかりました。

シャットダウン時に最も頻繁に発生するハングを解消

パフォーマンスを改善するため、ソフトウェア エンジニアがシステムにキャッシュを追加するのはよくあることです。しかし、キャッシュの副作用として他の問題(コードの複雑化、安定性、メモリ消費、データの整合性)が発生することも多く、逆にパフォーマンスが悪化する可能性すらあります。今回の事例では、起動時間を短縮するため、数年前に Chrome の履歴システムにローカル キャッシュを追加していました。当時の前提は、Chrome の内部メモリに履歴インデックスをキャッシュする方が、起動のたびに履歴のインデックスを再作成するよりも速いというもので、ラボ環境でのテストでもそれが実証されていたようです。

しかし、クラッシュ データと匿名のパフォーマンス指標から実世界でのパフォーマンスを体系的に調査し続けた結果、このキャッシュによってコードが複雑になり、メモリ使用量が不必要に増加しているだけでなく、シャットダウン時にブラウザがハングする問題の一番の要因にもなっていることがわかりました。その原因は、システムの別の場所で他の I/O が起こり続けている間、バックグラウンド優先スレッドの I/O 枯渇状態が延々と続く OS があることです。さらに、フィールド データの解析結果によれば、パフォーマンス面でユーザーが受けるメリットはほとんどありませんでした。現在は、このキャッシュを削除することで、シャットダウン時に最も頻繁に発生していたハングを解消しています。これは、キャッシュは必ずしも正解ではないという原則を示す好例となりました。

今後もさまざまなパフォーマンスの改善についてお知らせしますので、ご期待ください。

すべての統計情報の出典 : Chrome クライアントから匿名で集計した実データ 

Reviewed by Eiji Kitamura – Developer Relations Team<!—->

Chrome 92 でのフィッシング検知の高速化と効率化

この記事は Chrome デベロッパー、Olivier Li Shing Tat-Dupuis による Chromium Blog の記事 “Faster and more efficient phishing detection in M92” を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。

ウェブをブラウジングする Chrome ユーザーの安全を確保することは、Chrome にとって非常に重要です。実際、セキュリティは 4 つの基本原則の 1 つであり続けています。ときに、セキュリティのためにパフォーマンスが犠牲になることがあります。パフォーマンスの探求シリーズの次の投稿では、オンラインのユーザーの安全を確保するフィッシング検知アルゴリズムをどのように改善したかについてお伝えします。ここで紹介する改善によって、現在のフィッシング検知は 50 倍高速になり、電池使用量も少なくなっています

フィッシング検知

Chrome は新しいページに移動するたびに、ページの一連のシグナルがフィッシング サイトのシグナルと一致するかどうかを評価します。これを行うため、アクセスしたページのカラー プロファイル(ページで表示される色の範囲と頻度)と、通常のページのカラー プロファイルを比較しています。たとえば以下のイメージでは、ほとんどがオレンジ色で、緑と少しばかりの紫が含まれていることがわかります。

サイトが既知のフィッシング サイトと一致した場合、Chrome は警告をし、個人情報を保護して認証情報が漏れることを防ぎます。

フィッシングの試みが検知された場合に表示される画面

プライバシーを守るため、Chrome のセーフ ブラウジング モードは、デフォルトでブラウザ外にイメージを送信することはありません。これはプライバシーにとってはよいことですが、マシンはイメージを分析する作業をすべて自力で行わなければならないことになります。

多くの場合、イメージ処理は重いワークロードになる可能性があります。イメージの分析には、一般的に「ピクセルループ」と呼ばれる処理をし、各ピクセルを評価する必要があるからです。最新のモニターの中には最大で 1400 万ピクセルを超えるものもあります。そのため、各ピクセルで単純な操作をするだけでも、積もり積もってかなりの CPU 使用量になります。フィッシング検知で各ピクセルに対してするのは、基本色を数える操作です。

この操作は、次のようになります。この数は、ハッシュマップと呼ばれる連想データ構造に格納されます。各ピクセルについて RGB のカラー値を抽出し、その数を色ごとに 1 つずつ、3 つの異なるハッシュマップのいずれかに格納します。

効率の改善

ハッシュマップに 1 つの項目を追加するのは高速ですが、この操作は何百万ものピクセルに対して行う必要があります。分析の質が損なわれないように、ピクセルの数を減らすことは避けますが、計算自体は改善できます。

次のようにパイプラインを改善します。

  • このコードでは、3 つのハッシュマップで RGB チャンネルを追跡するのではなく、ハッシュマップを 1 つだけ使って色ごとにインデックスを管理します。これで、数える回数が 3 分の 1 になります。
  • 連続したピクセルは、ハッシュマップで数える前に合計します。これにより、均一な背景色のサイトでは、ハッシュマップのオーバーヘッドがほぼゼロになります。

その結果、色を数える操作は次のようになります。ハッシュマップの操作が大幅に減っていることに注意してください。

高速化の成果

Chrome M92 以降のイメージベースのフィッシング分類は、50 パーセンタイルで最大 50 倍高速に、99 パーセンタイルで 2.5 倍高速に実行されます。平均で、ユーザーがフィッシング分類結果を取得するまでの時間は 1.8 秒から 100 ミリ秒に短縮されます。

これにより、Chrome を使ううえで 2 つのメリットがあります。1 つ目かつ最大のメリットは、同じ作業をするために消費する CPU 時間が減り、総合的なパフォーマンスが向上することです。CPU 時間が減れば、電池の消耗もファンが回る時間も少なくなります。
2 つ目は、結果を早く取得できるため、Chrome が警告を早く表示できることです。この最適化により、処理に 5 秒以上かかるリクエストの割合が 16.25% から 1.6% 未満に下がりました。この速度の改善により、特に悪意のあるサイトでパスワードの入力を防ぐという点で、セキュリティに大きな違いが生まれます。 

総じて、今回の変更により、Chrome のレンダラー プロセスとユーティリティ プロセスが使用する合計 CPU 時間を約 1.2% 削減できました。

Chrome の規模では、わずかなアルゴリズムの改善であっても、全体では膨大なエネルギー効率の向上になります。つまり、何世紀分にも相当する CPU 時間を節約できます。

今後もさまざまなパフォーマンスの改善についてお知らせしますので、ご期待ください。

すべての統計情報の出典 : Chrome クライアントから匿名で集計した実データ

Reviewed by Eiji Kitamura – Developer Relations Team<!—->