{ "cells": [ { "cell_type": "markdown", "metadata": { "heading_collapsed": true, "slideshow": { "slide_type": "slide" } }, "source": [ "# ChromeDevToolで計測する\n", "\n", "- 2018/10/3 勉強会\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# アジェンダ\n", "\n", "1. 大まかなレンダリングの流れ\n", "2. RAILというパフォーマンスの指標\n", "3. Chrome Developer Toolで計測" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# 大まかなレンダリングの流れ\n", "\n", "- ChromeのPerformanceのページの円グラフの項目の通り\n", "- この一連の処理を「クリティカルレンダリングパス」と呼ぶ\n", "\n", "![](https://github.com/mrsekut/slides/blob/master/img/rendering_flow.png?raw=true)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## ざっくり概説\n", "\n", "### Loading\n", "\n", "- DNSの名前解決、TCPの接続確立、HTTPによる通信\n", "- プログラム、画像などのリソースの読み込み\n", "- DOM,CSSOMツリーの作成\n", "\n", "### Scripting\n", "- JavaScriptの字句解析、構文解析\n", "- コンパイル\n", "- 実行\n", "\n", "### Rendering\n", "- Styleの計算\n", "- RenderTreeの作成\n", "\n", "### Painting\n", "- レイヤーごとにピクセル描画\n", "- レイヤーの合成" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# パーフォマンスの指標\n", "\n", "- RAIL\n", " - 「ハイパフォーマンスブラウザネットワーキング」の著者のGoogleのおじさんが提唱\n", "- Response: 100ms\n", "- Animation: 16ms\n", "- Idle: 50ms\n", "- Load: 1,000ms\n", "\n", "------\n", "- 【参考】[RAIL モデルでパフォーマンスを計測する  |  Web  |  Google Developers](https://developers.google.com/web/fundamentals/performance/rail?hl=ja)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Chrome Developer Toolで計測する\n", "\n", "\n", "- Network\n", "- Performance\n", "- Memory\n", "- Rendering\n", "- Audits\n", "\n", "とりあえず、`cmd-alt-i` で開いてみましょう\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Networkパネル\n", "\n", "- リソース取得のタイムラインとリソースの詳細\n", "- `Disable cache`にチェックでキャッシュなしでリロード\n", "- `Offline`にチェックでネット切断\n", "- 青い線はDOMContentLoadedイベントの発生点\n", " - これが遅いとスクリプトによる読み込みブロックが起きている\n", "- 赤い線はLoadイベントの発生点\n", " - これが遅いとリソースが大きすぎる\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 詳細のTimingを見てみる\n", "\n", "- 適当にリソースを選択すると、右側で詳細が見れる\n", "- 今回見るのは「Timing」の欄\n", "![](https://github.com/mrsekut/slides/blob/master/img/devtool_timing.png?raw=true)\n", "\n", "#### Resource Scheduling\n", "\n", "- HTTPよりも低レイヤであるTCP, TLSなどの接続確立の時間など\n", "\n", "#### Request/Response\n", "\n", "- Waiting(TTFB)\n", " - リクエスト送信後から、最初のデータを受信するまでの時間\n", " - これが長いと、サーバーでの処理に時間がかかっている\n", " - [200ms以下が望ましい](https://developers.google.com/speed/docs/insights/Server)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 実践\n", "\n", "- imgにチェックしてみるとか\n", "- `size`でソートしてみるとか" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- ログイン済みのときもアプリ詳細の画像を取ってきてる" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "### Network\n", " \n", "### TTFBを減らす\n", "\n", "- 速度の遅いアプリケーションロジック\n", "- 遅いデータベースクエリ\n", "- 遅いルーティング\n", "- フレームワーク\n", "- ライブラリ\n", "- リソースによるCPU の消費\n", "- メモリ不足\n", "\n", "- PageSpeed Insightsのルールより。\n", " - https://developers.google.com/speed/docs/insights/Server" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Performanceパネル\n", "\n", "- ページの読み込み、操作に関する全てのイベントを分析\n", "- 左上の丸マークかリロードマークで計測\n", "- ボトルネックににっているものには右上赤三角が表示されている\n", "- 【参考】[中部チャートの項目の概説](https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/performance-reference)\n", "---\n", "- 画面上部の緑のグラフはFPS\n", " - 頂上が60FPS\n", " - その上部が赤くなっているところは、60FPSを切ったフレーム(フレーム落ち)\n", " - 赤がなく、緑の面積が大きいほどいい\n", " - [サイボウズのブログ 計測とその具体的な対処法が紹介されている](https://myakura.hatenablog.com/entry/2016/05/12/083000)\n", "----\n", "- Bottole-Upなどに重い処理の呼び出し元の関数名も表示されている\n", " - webpackのせいかわかりにくい" ] }, { "cell_type": "markdown", "metadata": { "heading_collapsed": true, "slideshow": { "slide_type": "subslide" } }, "source": [ "### GC\n", "\n", "- `cmd-f`などで「GC」と検索すればタイミングを見れる\n", "- アニメーション時などに起きると画面がもたつくので対策が必要\n", "- 左上のゴミ箱マークをクリックするとGCを発動" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 実践\n", "\n", "- 右上赤三角を見てみよう\n", "- メモリのグラフを見てGCが起きている部分を見てみよう\n", " - 「GC」と検索すればその前後に見つかるはず\n", "- 重い処理\n", " - 通知のページ\n", " - 投稿のアイテム追加の検索のページ\n", " - my pageに来たとき" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "\n", "### Performanceパネル\n", "- ページの読み込み、操作に関するすべてのイベントを分析\n", "\n", "- ドキュメント\n", " - https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/performance-reference\n", " \n", "- 中部のやつのことを「フレームチャート」、下部のことを「詳細パネル」と呼ぶ\n", "\n", "- ボトルネックになっているものにはフレームチャート上の右上に赤くなって示してくれている\n", "\n", "- 黄色がJavaScript\n", "\n", "\n", "#### 詳細ペインのタブ\n", "- summaryタブ\n", " - 処理の実行時間、関数名など\n", "- bottom-upタブ\n", " - パフォーマンスに影響を与えている関数とそれがどこから呼び出されれているかなどの情報\n", "- Call Tree\n", " - 関数の呼び出し元からツリー状に呼び出しの全体像をたどる\n", " - Reactではむずい?\n", "- Event Log\n", " - 開始からの処理のログ\n", "\n", "\n", "#### GC\n", "\n", "- cmd-fで「GC」で検索するとGCしてる部分が確認できる\n", "\n", "- Minor GC\n", "- Major GC\n", "- DOM GC\n", "などが確認できた\n", "\n", "- アニメーション処理中にGCが起こると描画がもたつくので避けるべき\n", " - アニメーション時に新たなオブジェクトを生成しない\n", " - もしくはアニメーション処理より前にオブジェクトを確保し、処理中は計算のみ行わせる(確保したときにGCを起こるなら起こさせる)\n", " \n", "- GCの原因を探る\n", " - 録画して検索してGCの場所を特定\n", " - そのGCの引き金になった関数などを特定\n", " - その関数部分をコメントアウトし、再実行\n", " - GCが行われないかを確認する\n", " \n", "- Performanceタブの左上のゴミ箱マーククリックでGCできる\n", " - 録画中の最後の方にクリックするとGC発動していることが確認できる\n", " \n", "#### メモリリーク\n", "\n", "- メモリが開放されずに使わないのにメモリを確保し続けること\n", "\n", "- MMU\n", "- メモリの保護\n", " - 他のプロセスのメモリを読まない\n", "- メモリスワッピング\n", " - 仮想メモリを補助記憶装置も使う\n", " - そこにアクセスするときは補助記憶装置からメモリに復帰させてから読むので遅くなる(スワップイン、スワップアウト)\n", " - モバイルOSだとメモリスワッピングが弱いのでクラッシュする可能性もある\n", " \n", "- console.logなどはGCの対象にならないのでメモリリークを引き起こす可能性がある\n", "#### Memoryにチェックをつける\n", "\n", "- 正常な場合、鋸歯のようになる Wp159の図参照\n", "\n", "\n", "\n", "##### 線\n", "それぞれ何? \n", "\n", "- JS Heap\n", "- Documents\n", "- Nodes\n", " - DOM数のこと(?)\n", "- Listeners\n", " - GPU Memory" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Memoryパネル\n", "\n", "- メモリの利用状況\n", "- メモリリークの検知やメモリの使いすぎを把握\n", "- 「Record Allocation Timeline」でメモリリークが起きている箇所を見つける" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Record Allocation Timeline\n", "\n", "- 50ms毎にヒープのスナップショットを取得し、記録終了時に最後のスナップショットを取得\n", "- 見方\n", " - 縦線の高さ: オブジェクトのサイズ\n", " - 青: タイムラインの終了時まで存在しているオブジェクト\n", " - 灰: タイムライン中にGCが行われたオブジェクト\n", " - @の数字はオブジェクトID\n", "- GCが行われなかったということは、どこかで参照されているから\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "### Memory\n", "\n", "- heap snapshot\n", " - JSのオブジェクトとそれに付随したDOMノード間のメモリ配分を見る\n", " - https://developers.google.com/web/tools/chrome-devtools/memory-problems/heap-snapshots?hl=ja\n", " - [三点観測](http://www.techscore.com/blog/2017/12/24/%E3%83%95%E3%83%AD%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%83%89%E3%81%AE%E3%83%91%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%B3%E3%82%B9%E6%94%B9%E5%96%84%E3%81%A8%E3%83%A1%E3%83%A2%E3%83%AA%E3%83%AA/)\n", "- record allocation profile\n", " - js各関数のメモリの割り当てを見る\n", "- record allocation timeline\n", " - メモリリークがどこで起きているのかを見る\n", " - [参考](https://developers.google.com/web/tools/chrome-devtools/memory-problems/allocation-profiler?hl=ja)\n", " - shallow size\n", " - オブジェクト自体が保持しているメモリのサイズ\n", " - Retained Size\n", " - オブジェクト自体とその依存オブジェクトが削除されると解法されるメモリのサイズ\n", " \n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Rendering\n", "\n", "- 右上の点が縦に3つ並ぶメニューから「Rendering」を選択\n", "- 「Paint flashing」にチェックを付けると、再レンダリングされたところが緑になる\n", "- 【参考】[Chrome DevTools の「Enable paint flashing」を使う - kitak's blog](https://kitak.hatenablog.jp/entry/2015/11/01/152102)\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 実践\n", "\n", "- 「Paint flashing」にチェックを付けよう\n", "- スクロールやページ遷移をして無駄な再描画がないか確認しよう" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "### Rendering\n", "#### その他の項目\n", "- Paint Flashing\n", "- Layer borders\n", " - Compositing Layerとtileを表示する\n", " - https://www.html5rocks.com/ja/tutorials/speed/layers/\n", "- FPS Meter\n", " - 現在のFrame RateとGPUラスタライズの有効状況、GPUメモリの状況を表示する\n", "- Scrolling Perfomrmance Issues\n", " - スクロールのレスポンスを阻害するようなEvent Listenerやスクロールの度に再描画される要素があれば画面内に表示する\n", "- Emulate CSS Media\n", " - CSSのMediaタイプをprint/screenと切り替える\n", "\n", "\n", "\n", "https://qiita.com/damele0n/items/363d6e30b92ed0c75b02#%E9%A0%85%E7%9B%AE" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Auditsパネル\n", "\n", "- パフォーマンス診断ツール\n", " - PageSpeed Insightsみたいなやつ\n", "- カテゴリー別の課題とその深刻度を表示\n", "- クリックするとその解決法を教えてくれる\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# 所感\n", "\n", "- これまで気にしてなかったが調べてみたら関連記事が山ほど出てきた\n", "- 問題は見つけられても解決できなければ意味がない\n", "- Reactの場合\n", " - Reactの内部構造を知る必要がある\n", " - 差分描画の仕組みとか\n", " - やるしかない\n", " - ReactはReactで便利な解析ツールがありそう\n", " - react-perf-devtoolとか" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "## chrome://tracing\n", "\n", "- 公式ドキュメント\n", " - https://www.chromium.org/developers/how-tos/trace-event-profiling-tool" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "## 他にもJS APIがいっぱいある\n", "\n", "- パフォーマンス計測\n", "\n", "## パフォーマンス診断ツール\n", "- PageSpeed Insightsなど\n", "\n", "## 継続的パーフォマンス監視\n", "\n", "- New Relic Browser" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# 参考\n", "\n", "- [dev tool 公式](https://developers.google.com/web/tools/chrome-devtools/)\n", "- https://webtan.impress.co.jp/e/2017/02/20/24816\n", "- https://qiita.com/y_fujieda/items/a0a69151cf7307039f74\n", "- https://www.slideshare.net/yoshikawa_t/chrome-developer-tools-17787728\n", "\n", "# 関連(もっかい読む)\n", "- [dev toolを使ったReactのチューニング AbemaTV](https://1000ch.net/posts/2016/abematv-runtime-perf-audit.html)" ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.1" }, "toc": { "nav_menu": {}, "number_sections": false, "sideBar": true, "skip_h1_title": false, "toc_cell": false, "toc_position": {}, "toc_section_display": "block", "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 2 }