パフォーマンス低下を調査したらChromeのWebGL環境が原因だった話

はじめに

こんにちは!エンジニアの古家です。 この記事はGoodpatch アドベントカレンダーの11日目の記事です。

私たちのチームではPixiJSを通じてWebGLを利用した「Strap」というオンラインコラボレーションツールを開発しています。 StrapはWebベースのサービスで、ボード上でさまざまな図形やアイコン、画像を利用した作図や文書作成、振り返りなどのワークショップを複数人で行うことができます。

product.strap.app

今年、そんなStrapでChromeの特定バージョンにおいてパフォーマンスに関する問題が発生しました。 本記事では、その問題の調査と解決(?)に至るまでのプロセスを紹介します。

なんか最近Strapがめっちゃ重いんですが・・

2023年10月ごろ、一部のユーザーからボード操作のレスポンスが悪化したとの報告がありました。

ユーザーへのヒアリングから、特にスクロールやズームなどの操作で顕著で、ボード上の要素の量には影響されていない様子でした。

Strapにとって、ボードのパフォーマンスは使用感に直結する重要な指標なため、ただちに調査をを行うことにしました。

調査!

最初に、報告された問題を再現するためのテスト環境を設定しました。

報告された環境はApple Siliconを搭載するMacbook Proであり、明らかに高性能な端末でした。 また、10月上旬ごろと、ある程度時期が定まっていたため、それを起点に調査内容を検討することにしました。

検討した環境差分:

  • コードベースの変更
    • 主要な機能実装(変更)の時期
    • Reactバージョン
      • (問題の少し前にv17からv18へ移行を行っていたため)
  • ブラウザー(Chrome)バージョン
    • v118は10月10日ごろのリリース
  • OS
    • macOS v14は9/26リリース

また、ボード内のどんな要素が操作性に悪影響を与えているかを知るため、Strapが使える図形とその表示設定(枠線などの表示スタイル)、いくつかの図形の組み合わせごとに100個配置されたボードを用意しました。

付箋を100個貼り付けた様子

これらの要素の組み合わせで、ボードのフレームレートを計測することで原因を割り出せるのではないかと考えました。

フレームレートの計測には、フレームレートが常時表示できる拡張機能を利用しました。ここは開発者ツールを利用してもいいかもしれないですね。

私たちの仮説では、コードベースの変更が直近のパフォーマンス低下の原因であることを疑っていたため、先に検討した環境差分をもとにまずは以下の環境差分での調査から始めました。

  • Reactバージョンアップ前後
  • Chromeバージョン
    • ※ 検証時点でv117は用意できなかったため、v119(beta)との比較を実施

ぶんぶん振り回していくっ!

ChromeのANGLEバックエンドが影響していた・・?

フレームレートの計測結果は興味深いものでした。

予想に反して、コードベースの変更はパフォーマンスに影響を与えていませんでした。

しかし、PixiJSのlineStyleを適用したCircleやシェイプの組み合わせでフレームレートが顕著に低下することが判明しました。

<CircleSymbol
  width={size}
  height={size}
  lineStyle={{ // lineStyleがあるだけで10FPS程度まで低下
    width: LINK_STYLE.border,
    color: Color(LINK_STYLE.borderColor).rgbNumber(),
    alignment: 1,
    alpha: 1,
  }}
/>

割と基本的な組み合わせでもフレームレートが20FPS程度まで低下

次に、問題が起きる図形の組み合わせをChrome v119で検証したところ問題が改善していることを確認できました。 このことから、Chrome v118での何らかの問題であることが判明しました。

組み合わせを変えてぶんぶん振り回した結果(赤や黄色がやばいところ)

ブラウザバージョンだけが問題であれば、もっと多くのユーザーで問題が発生しそうなものですが、一部のユーザーからの報告に留まっていたため、あらためて報告されたユーザーの利用環境を確認しました。

すると、WebGLの描画に利用されるANGLEのバックエンドがMetalであるという共通点に気づきました。 そこで自身の検証環境を確認したところ、同様にMetalが利用されていたことが確認できました。

developer.apple.com

改めてOpenGLがバックエンドのANGLEで検証したところv118でも問題ないことが確認され、またv119とMetalの組み合わせでも問題は改善していました。

以上のことから、以下の組み合わせでの問題であることが推察されました。

- Chrome 118.0.5993.117
- chrome://gpu のDriver Information(検証環境からの抜粋)
    - Display type: ANGLE_METAL
    - GL_VENDOR: Google Inc. (Apple)
    - GL_RENDERER: ANGLE (Apple, ANGLE Metal Renderer: Apple M1 Pro, Version 13.6.1 (Build 22G313))
    - GL_VERSION: OpenGL ES 2.0.0 (ANGLE 2.1.21845 git hash: 05f45adc1473)

ANGLEについて

ANGLE ( Almost Native Graphics Layer Engine ) は、Googleが開発したオープンソースのクロスプラットフォーム グラフィックス エンジン 抽象化レイヤーです。ANGLE は、OpenGL ES 2/3 呼び出しを DirectX 9、11、OpenGL、または Vulkan API 呼び出しに変換します。これは OpenGL のポータブル バージョンですが、OpenGL ES標準の制限があります。 ANGLE (software) - Wikipediaより引用

ANGLEは、WebGLのAPI呼び出しをOSが利用可能なグラフィックエンジンのインターフェイスに変換しているソフトウェアです。 Chromeの他にもFirefoxやWebKitでも採用されているようです。 macOS版ChromeではANGLEの標準バックエンドとしてOpenGLが採用されていましたが、そのMetal版も開発されています。

Metal backendは長らく実験的な機能となっていますが、一部の環境に提供されだしたことで問題が顕在化したことが推察されました。 自身を含め、一部のユーザーについては、この設定がDefaultの場合にMetalが割り当たることがあるようです。

実際の提供状況に関する情報はChrome Platform Statusなどでも見つけられませんでしたが、もしかしたらApple Silicon搭載などある程度性能に余裕のある端末から提供を始めているのかもしれません。

Metal backendの状況はchrome://flags/#use-angleからも確認できます。

なお、調査時点のv118とv119のANGLEの差分はこちらです。

https://github.com/google/angle/compare/05f45adc147393562b518ca1f82a3ccba7ee40f7...2eea91f8f0b2979ba810aedd9c5a43e65c58c1d9

Metalに関する変更もいくつか入っており、これらの変更の何かが影響しているはずですが今回は特定までは辿り着けていません。

消極的な解決策

リリースサイクルではv119安定版のリリースが控えていたため、最初の解決策としてはリリースを待つことにしました。

また一時的な回避策として、chrome://flags#use-angleを使って、ANGLEのバックエンドをOpenGLに固定する方法をユーザーに案内しました。

v119リリース後

Chrome v119が安定版としてリリースされた後、同様の問題は報告されていません。

chrome://flagsから確認できるMetal backendの説明にもあるように、Metalを利用したANGLEは、最終的にはOpenGLよりも高速になる想定であるようですが、細かな描画図形の組み合わせでは依然としてパフォーマンスが落ちることを確認しており、状況は追っていく必要がありそうです。

振り返り

網羅的に計測を実施することで原因を早期に絞り込むことができたのは良かった点でした。

ANGLEのバックエンドとしてMetalとOpenGLの両方が存在する現状では、macOSでの確認には注意が必要だということが教訓にもなりました。

今回はブラウザに依存する問題でしたが、機能追加による問題も今後発生する可能性があり、ユーザー数の増加に伴って影響度も大きくなっていく問題であるため、クライアント側のフレームレートの低下を早期に検出する仕組みを検討したいと考えています。

まとめ

  • Metal backendが一般提供されだしたことで、想定していなかった問題に遭遇しました。
  • 影響しうる条件を事前に洗い出して調査したことで効率的に原因の特定ができました。
  • 今後もMetal backendの安定化やWebGPUの利用などクライアント側の状況は変わっていくことが予想されるため、状況を注視していきたいです。
    • 現在開発中のPixiJS v8ではWebGPUを利用できるようになる見込みでとっても楽しみです。

補足資料

なお

この記事の大半はChatGPTを使って文章を起こしてみました。 せっかくなのでこのやりとりも大公開。 https://chat.openai.com/share/29affec5-c4d7-4181-af3c-9a7e53c10895

さいごに

Goodpatchではデザイン好きなエンジニアの仲間を募集しています。 少しでもご興味を持たれた方は、ぜひ一度カジュアルにお話ししましょう!