# Day28 X Runtime Performance Debugging ### 如何使用 Chrome 開發人員工具效能面板來分析執行階段效能 ![image](https://hackmd.io/_uploads/Sk6ZpgKJye.png) Chrome DevTools 的 Performance 面板記錄程式執行階段的所有行為,是解決程式效能問題的最佳方案。由四個子面板構成: 1. 控制台(Controls): 開啟記錄,停止記錄,配置記錄期間需要記錄的內容 2. 概括(Overviews): 頁面表現(行為)的一個概述 - CPU(CPU Resources) - NET 3. 火焰圖(Flame Chart): 可視覺化 CPU 堆疊(stack)的資訊記錄 4. 詳細資訊(Detail): 當有具體事件被選擇時,該面板展示這個事件的更多詳細資訊 - Summary Tab - Bottom-Up Tab - Call Tree Tab - Event Log Tab ## RAIL 模型 - RAIL is a user-centric performance model - RAIL stands for four distinct aspects of web app life cycle: response, animation, idle, and load. (回應、動畫、閒置和載入) ![image](https://hackmd.io/_uploads/HkL-VFJJye.png) **User perception of performance delays** | delay time(Frame update rate) | user response | | -------- | -------- | | 0 to 16 ms | users perceive animations as smooth so long as 60 new frames are rendered every second | | 16 to 100 ms | users feel like the result is immediate ; any longer, and the connection breaks | | 100 to 1000 ms | users feel part of a natural and continuous progression of tasks | | 1000 ms or more | users lose focus on the task | | 10000 ms or more | users are frustrated and are likely to abandon tasks | **Guidelines:** - Response: process events in under 50 ms - Animation: produce a frame in 10 ms(1000 ms / 60 frames per second ≈ 16 ms) - browsers need about 6 ms to render each frame, hence the result is 10 ms ![截圖 2024-10-14 上午9.47.07](https://hackmd.io/_uploads/rJYXOeqk1e.png) - Idle: maximize idle time to increase the odds that the page responds to user input within 50 ms - Load: deliver content and become interactive in under 5 seconds in first loads (for subsequent loads, under 2 seconds) ## 實作 ![image](https://hackmd.io/_uploads/ry5Jgb2RC.png) 左上角會有兩個按鈕(紅色框框區塊) 1. 第一個按鈕:「Start recording」 - 用途:記錄執行階段效能,專注於網頁在運作過程中的性能表現 - 功能:當按下後瀏覽器會立即開始效能記錄 - 使用範例:適合監控網頁運行中的特定行為 ex: 分析用戶點擊某個按鈕後,相關事件處理或渲染過程的效能 2. 第二個按鈕:「Start profiling and reload page」 - 用途:記錄負載效能(Load Performance),專注於頁面加載時的性能表現 - 功能:當按下後會自動先跳轉到 about:blank 頁面,清除任何剩餘的螢幕截圖和追蹤記錄,再者瀏覽器會重新載入當前頁面,並同時開始效能分析。當瀏覽器認為頁面已經完全載入並且互動告一段落時,它會自動停止記錄 - 使用範例:分析頁面載入時間、資源加載順序、初次渲染時間等 :::success Start recording 按鈕適合監控網頁運行中特定行為的效能 Start profiling and reload page 按鈕針對網頁載入效能進行分析 ::: ## 前提 1. 使用無痕視窗 - 以確保 chrome 是運行在「clean state」下 - extensions 可能會在效能評估中造成雜訊 2. 模擬 Mobile Devices 的 CPU - 模擬在性能低的設備運作的狀況 - 測試其他網頁時,如要確保網頁在低階行動裝置上都能正常運作,請調整 CPU 節流功能 ![image](https://hackmd.io/_uploads/BynOTe3RR.png) ## 分析 Profiling 結果 - 概括(Overview) 1. 查看「CPU」圖表 ![截圖 2024-10-18 上午9.37.59](https://hackmd.io/_uploads/HkLlaVkeyg.png) - CPU 圖表的顏色對應於「效能」面板底部的「Summary」分頁標籤中的顏色 - 灰色 (System) — 瀏覽器內部的工作 (被歸類在這的任務參考 [stackoverflow](https://stackoverflow.com/questions/36460614/what-does-the-system-category-of-records-mean-in-chrome-timeline-profiling-too)) - 白色 (Idle) — Idle Time - 黃色 (Scripting) — 執行 JavaScript 與事件處理 - 綠色 (Painting) — 圖像處理、畫面繪製 - 紫色 (Rendering) — 頁面的樣式計算 - 藍色 (Loading) — 載入與處理 HTML(若在頁面載入後才開始 profiling,則不顯示這個階段) - 不代表 CPU 長時間都在運作就是不好的,視需求而定 ex: [無限輪迴的動畫](https://asana.com/zh-tw?utm_campaign=Brand--CN--CN--Core--Exact&utm_source=google&utm_medium=pd_cpc_br&gclid=CjwKCAjwtfqKBhBoEiwAZuesiHzSnFqyC_eLUFRYbX8aQwBTrkMD_Hd6T3RTYu3gemzc8y5IWcBNdxoCMhAQAvD_BwE&gclsrc=aw.ds) 2. 查看「NET」圖表 ![image](https://hackmd.io/_uploads/HJfxc4FJ1x.png) - 顯示網頁在不同階段進行的各種網絡請求,深藍色和淺藍色分別表示網絡請求的不同階段 - 深藍區域:代表請求的等待時間(Waiting / Queueing Time) - 這段時間是從瀏覽器開始排隊處理該網絡請求到實際開始發送該請求之間的等待時間。 - 淺藍區域:代表請求的接收時間(Receiving / Download Time) - 這段時間是從請求開始接收響應數據(通常是從服務器)到完成下載的時間。 ## 分析 Profiling 結果 - 火焰圖(Flame Chart) ### Main Section(CPU Flame Chart) ![image](https://hackmd.io/_uploads/Skor8hy11g.png) - 呈現的是 Main Thread 的 CPU task - X 軸代表隨時間變化的記錄,y 軸代表呼叫堆疊 - 使用倒轉的火焰圖(flame chart)呈現,意思是在下面的 function 或 task 是由上一層的 task 所觸發的 - Task 的右上角出現紅色的三角形,代表這是一個 long task 警告,而超過 50 毫秒的部分則會以紅色顯示 - 點選紅色三角形後,有時候它會指出這個 task 在程式碼中的位置(會直接切換到 Sources Tab 並顯示對應的行數),幫助快速的 debug ![image](https://hackmd.io/_uploads/ry_gD31J1g.png) ### Frame Section - 顯示了頁面中每一次 UI update 的 Screenshot - 顯示特定影格的確切所需時間 - 四種顏色的影格代表: - 白色: 無變更的閒置框架 - 綠色: 可如預期的及時成功轉譯 - 黃色: 至少部分視覺更新 - 紅色: Chrome 無法在合理的時間內顯示頁框 ![image](https://hackmd.io/_uploads/HkFyTflk1l.png) :::success 開啟 FPS 計量器 - FPS(frame per second, Frame Rate): 每秒顯示影格數,Frame Rate 達到 60 FPS,使用者看到的動畫才不易產生卡頓 - FPS 計量器 : 可在頁面執行時即時預估每秒影格數 - 如何開啟:Devtool - more tools - Rendering - Frame Randering Stats ![截圖 2024-10-18 上午10.03.25](https://hackmd.io/_uploads/rJc-zSylJl.png) - 以圖表時間軸形式包含三種影格類型(顏色對應 Frame Section): 1. 成功轉譯影格 (藍線) 2. 部分呈現的影格 (黃線) 3. 捨棄的影格 (紅線) ::: ### Timing Section ![image](https://hackmd.io/_uploads/ByDCDxKkJl.png) - 呈現網頁載入效能一些重要指標發生的時間線 - DCL (DOM Content Loaded): HTML 被載入且解析(Parse)完畢的時間點。 - FP(First Paint) : 任何一個 pixel 被瀏覽器繪製到頁面上的時間。 - FCP (First Contentful Paint):「首次內容繪製」,指瀏覽器第一次顯示文字或圖片的時間。 - LCP (Largest Contentful Paint): 是計算網頁可視區 (viewport) 中最大元件的載入時間。 - L (onload) : 代表解析 HTML 後請求的資源都載入完成的時間點 - 在 Summary 中可以看到 Total Blocking Time (TBT),代表在 Profiling 的過程中,瀏覽器 Main Thread 被阻塞的時間總和。 ![image](https://hackmd.io/_uploads/B1ll2tUF1Jg.png) ### Memory Section ![image](https://hackmd.io/_uploads/HkgLC8vJJe.png) - 顯示這段 profiling 期間網頁的記憶體用量 - 圖表中的彩色線條會對應到圖表上方的彩色核取方塊 - 垃圾桶可以強制瀏覽器做 GC (Garbage Collection) - 藍色 JS Heap 使用量的變化: - 網頁有沒有 Memory Leak - 哪些操作會導致記憶體用量飆升 - ex: 在執行某個函式後就強制 GC,如果記憶體使用量還是在高點甚至越來越高,也許就是遇到 Memory Leak 的狀況了。 ![image](https://hackmd.io/_uploads/HJux4Pvyyg.png) - 若 GC 高頻率被觸發: - 解決 Memory Leak 的問題 - 網站記憶體的用量過多 :::info GC 有一個特性是「Stop The World」,且因為 GC 同樣是在 Main Thread 執行,太過頻繁觸發可能會導致網站效能出現瓶頸 ::: ### Network Section ![image](https://hackmd.io/_uploads/B1qGu_vyyl.png) - 按照順序顯示抓取各個資源花費的時間和資源間的依賴關係,如果點擊任一資源可以在下方 summary tab 看到更詳細的資料,例如 URL、Duration、Priority、Mime Type、Encoded Data 大小、Decoded Body 大小 - 若在右上角標有紅色三角形代表 Render blocking requests - 最右側箭頭處 hover:A breakdown of request timings(Duration) - 左線 (|–) Request Sent 之前 - 長條的淺色部分 Request sent 和 Waiting for server response - 長條的深色部分 Content download - 右線 (–|) 是等待主執行緒所花費的時間 - 最左側藍色方框處:瀏覽器自身會動態(資源需求變化、用戶交互行為、網絡狀況、Fetch Priority API )調整資源優先級 - Initial Priority: 瀏覽器在第一次發送請求時,為該資源分配的優先級 - (final) Priority: 請求完成時的最終優先級 :::info Chrome 如何排定大多數資源的優先順序及排序: - Early CSS (like CSS in the <head>) is highest by default and blocks layout - Late CSS (like CSS in the middle of the <body>), doesn't block the initial layout - Non-matching CSS (like media="print" stylesheets when the page is loading on a screen, not being printed) are loaded with the lowest priority ::: ### Fetch Priority API - 指出資源對瀏覽器的相對優先順序。這可以實現最佳載入效能,並改善 Core Web Vitals - **fetchpriority 屬性**: 開發者可以用來顯式指定某個資源的擷取優先順序。fetchpriority 的優先級可以是 low、auto、或 high,這些值決定了資源在網頁渲染過程中的緊急程度 1. 提高 LCP ```html= <img src="/images/important.svg" fetchpriority="high" alt="I'm an important image!"> ``` 2. 降低不需捲動位置圖片的優先順序 ```html= <ul class="carousel"> <img src="img/carousel-1.jpg" fetchpriority="high"> <img src="img/carousel-2.jpg" fetchpriority="low"> <img src="img/carousel-3.jpg" fetchpriority="low"> <img src="img/carousel-4.jpg" fetchpriority="low"> </ul> ``` 3.降低預先載入資源的優先順序: preload + fetchpriority="low" ```js= <link rel="preload" href="secondary-image.jpg" as="image" fetchpriority="low"> ``` 4. 調整指令碼的優先順序: async + fetchpriority="high" ```js= <script src="async_but_important.js" async fetchpriority="high"></script> ``` 5. 降低非重要資料擷取作業的優先順序 ```js= <script> fetch('https://example.com/', {priority: 'low'}) .then(data => { // Trigger a low priority fetch // Less important content data (suggested low) }); </script> ``` :::info Loading v.s. fetchpriority 概念比較 - Loading : WHEN to fetch resources. - fetchpriority: HOW (important) to fetch resources. | 特性 | fetchpriority = "high" | Preloading | | -------- | -------- | -------- | | 作用機制 |資源會在初始加載時按高優先級別下載 | 提前下載即時需要但尚未被請求的資源| | 資源加載時間 | 初始時間 | 空閒時間 | | 應用場景 | 初次渲染或 LCP 圖片 | 未來頁面會使用到的資源 | | 目標 | 加快當前頁面關鍵資源的加載速度 | 減少未來頁面的加載延遲 | | 特性 | fetchpriority = "low" | Lazy Loading | | -------- | -------- | -------- | | 作用機制 | 資源會在初始加載時按低優先級別下載 | 資源會延遲加載直到用戶需要才下載 | | 資源加載時間 | 初始時間 | 當用戶滾動或接近資源可視區域時 | | 應用場景 | 非關鍵但仍須初始加載的資源 |非關鍵且不會立即顯示的資源 | | 目標 | 減少關鍵資源的等待時間 | 減少初始資源加載的數量,提升頁面初次渲染速度 | ::: ## 分析 Profiling 結果 - 詳細資訊(Detail) ### Call Tree - 查看哪些根活動(root activities)造成最多工作 :::info root activities 是指瀏覽器開始執行一個流程的起點,通常是由某個用戶操作或系統事件觸發的。瀏覽器會觸發一個「事件活動」(Event activity)作為根活動。該事件可能會導致一個處理程序(handler)被執行。 ::: ![image](https://hackmd.io/_uploads/B1t8qoOJ1e.png) ![image](https://hackmd.io/_uploads/rJ7Emhdkkx.png) 點擊後出現 Heaviest Stack 表格,顯示所選項目的子項執行活動的所需時間最長 ![截圖 2024-10-21 上午9.25.34](https://hackmd.io/_uploads/SyO1RQmg1l.png) ### Bottom-Up - 是一種從最基礎的活動向上追蹤的視角,專注於哪些活動最耗費時間或資源 ![image](https://hackmd.io/_uploads/H1eJa7hu1kx.png) - 在 Bottom-Up 標籤中的頂層活動是 wait。在火焰圖中,wait 調用下方的黃色部分實際上是數千次的 Minor GC(垃圾回收)調用。 ### Event Log 展示所有階段包含 loading、javascripting、rendering、painting 中各事件的耗時情況,並提供了 filter 快速過濾功能。 ![image](https://hackmd.io/_uploads/B1ED8lKyye.png) :::success 這三種分析方式各自強調的視角不同,適用於不同的性能問題調查需求: Bottom-Up:按執行時間重點分析耗時最長的函數,從底層熱點開始查找問題。 Call Tree:自上而下顯示函數調用鏈,查看整個程序的執行邏輯與調用層級。 Event Log:按時間順序記錄事件,分析事件的觸發順序和持續時間。 ::: ### 參考資料 - https://developer.chrome.com/docs/devtools/performance/overview?hl=zh-tw - https://developers.google.com/?hl=zh-tw