您好,登錄后才能下訂單哦!
瀏覽內核CPU 占用問題是影響用戶使用的關鍵因素,會引起操作卡頓、手機耗電以及應用
崩潰等問題。CPU 占用由于受到頁面、機型、應用框架的影響,較難進行定位和優化。在瀏覽內核性能測試中發現CPU 占用高于之前版本,通過分析CPU 曲線,發現可能是部分場景CPU 沒有收斂導致的,因此對CPU 收斂做了專項測試。
老測試方案——內核之前針對CPU 收斂的測試是通過加載用戶訪問Top 100 的頁面,應用放后臺通過TOP 命令觀察CPU 收斂情況。
缺點: 1.測試工作量非常大;2.Top頁面結構復雜很難分析是頁面中的那個元素引起的不收斂現象;3.頁面經常變化,收斂狀態難以穩定復現;
新測試方案——通過對頁面的整理分析和與RD 的溝通,引起CPU 不收斂的問題主要是頁面中的動態元素,如CSS動畫、 視頻播放、 Timer 定時器、 js 加載、 gif動圖等,并由QA自己開發動態元素的測試頁面進行測試,在測試場景上選擇了應用切后臺和頁面切換至不可見窗口兩種。
優點:1.測試工作量小,針對性強;2.頁面固定、元素簡單,易于復現;3. 場景更加貼近用戶使用;
測試結果:
使用新測試方案完成測試后,發現如下幾個問題:
問題一 頁面切換至不可見窗口場景:測試中心、CSS、H5、GIF 等多個頁面不收斂;
問題二 APP 切后臺場景:測試中心頁面不收斂;
問題一通過對測試結果的分析,當用戶創建空白頁面,使測試頁面切換至不可見窗口的場景時,包含GIF 圖、CSS 動態元素的頁面CPU 仍然有波動,而沒有收斂至0, 這里可以猜測出可能當頁面不可見時,頁面的繪制沒有進行pause,內核判斷頁面動態元素有更新,因此還在不斷的進行繪制,導致CPU 不為0。
問題二測試中心頁面不收斂,該頁面是測試平臺的導航頁面,本身沒有動態元素,但是仍有不收斂現象。QA通過繪制工具systrace分析頁面加載過程的數據,發現切換切換后臺后,內核的main(scheduler)/thread_proxy(cc)在工作,還在繪制內容。推測有兩個可能:1.APP切后臺,沒有pause當前的webview;2.測試中心首頁的某些邏輯導致內核沒被pause。
內核加載過程——瀏覽內核加載頁面的網絡部分向網絡發起請求并把網頁資源下載給Loader,之后 HTML Parser 將 HTML 和 Script 解析成 DOM 樹,再結合 CSS 層疊樣式表生成對應的 Render 樹。Render 樹上就包含了每個元素的各種屬性字體、顏色、屏幕上面的坐標、長、寬等。Render 樹進一步生成 Graphics Context 交給平臺相關的圖形庫把頁面展示在屏幕上。大體過程是如下圖這樣,實際上內核是邊加載邊繪制的。
內核繪制過程——瀏覽內核為了減少不必要的繪制,保證頁面的繪制速度和頁面滑動的流暢度,對Render Tree 進行了分層,可以更方便的進行頁面的局部更新。有更新的layer 將更新數據經過合成composite階段,將真正的需要繪制區域數據給GL 進行draw,最終完成圖像的顯示。整個過程是多線程的,通過消息來驅動這個流程。
動態元素由于更新頻率高,通常會劃分為單獨的layer,如果這個layer 的更新消息沒有暫停,就會導致這個消息驅動layer 的合成,進行更新區域的計算,調用drawGL 進行圖像的draw。因此CPU 會一直被占用。
問題一
頁面動態元素不收斂,通過將頁面中動態元素刪除后,測試結果為收斂,由此可以證明確實是動態元素導致。動態元素有頻繁的更新消息,使得不斷對包含動態元素的layer 進行合成和繪制,導致CPU 不收斂。首先需要查看該webview 是否是否被pause,webview 被切換至不可見狀態時,策略上應該暫停一切頁面的處理,節約更多的CPU和內存資源保證當前活動窗口的處理。
// webview onPause 的處理 public void onPause() { if (mIsPaused || mNativeAwContents == 0) return; mIsPaused = true; nativeSetIsPaused(mNativeAwContents, mIsPaused); }
內核沒有對文檔解析、js 加載、動圖進行暫停。
解決方案:
// 網絡加載暫停 void ContentViewCoreImpl::SetIsPaused(JNIEnv* env, jobject obj, bool paused) { GetWebContents()->Send(new ViewMsg_SetIsPaused( GetWebContents()->GetRoutingID(), paused)); } // 繪制暫停 void RenderViewImpl::OnSetIsPaused(bool paused) { if (!webview()) return; webview()->setIsPaused(paused); } // 文檔解析暫停 void WebViewImpl::setIsPaused(bool paused) { Document* document = page()->mainFrame()->document(); if (!document) return; if (paused) document->suspendScheduledTasks(); else document->resumeScheduledTasks(); }
問題二
測試中心頁面不能收斂,此頁面并沒有動態元素,因此用上面的方法分析是不奏效的,需要找其他的方法。百度瀏覽內核是基于Blink 35版本再次開發的版本,因此想要驗證下原生內核是否有問題,于是驗證了Blink 35、36都是不收斂,blink 37 版本可以收斂,因此可以斷定是Blink 內核自己的bug,通過對繪制過程相關代碼的查找,發現google 工程師對此問題的一個注釋。
if (RenderView* view = renderView()) { ASSERT(!view->needsLayout()); view->compositor()->updateCompositingLayers(); // FIXME: we should not have any dirty bits left at this point. Unfortunately, this is not yet the case because // the code in updateCompositingLayers sometimes creates new dirty bits when updating direct compositing reasons. // See crbug.com/354100. view->compositor()->scheduleAnimationIfNeeded(); }
通過上面的注釋可以看出,在layer 有更新進行合成過程中,會引入臟數據導致layer 一直更新,并進行后面的數據處理和繪制,導致CPU 不收斂,通過增加打印Log 也可以證明,不收斂的頁面確實在不斷進行該函數的調用。
通過對Blink 37 修復的patch 進行研究,內核對判斷Layer 更新的狀態進行了修改,調整了更新判斷的結構,刪除了scheduleAnimationIfNeeded 方法,通過其他狀態判斷是否需要更新layer,并進行數據的合成進行繪制,通過將37 patch 合入測試發現可以有效解決不收斂問題。
解決方案:
增加了CompositingReasonFinder::requiresCompositingForPosition 方法判斷是否需要進行合成。
臟數據的問題還是沒有根本解決,只是增加了判斷,不會出現之前的循環處理。
void RenderLayerCompositor::assertNoUnresolvedDirtyBits() { ASSERT(!compositingLayersNeedRebuild()); ASSERT(!m_needsUpdateCompositingRequirementsState); ASSERT(m_pendingUpdateType == CompositingUpdateNone); ASSERT(!m_rootShouldAlwaysCompositeDirty); ASSERT(!m_needsToRecomputeCompositingRequirements); }
CPU 收斂在CPU 性能測試中是一個非常重要的項目,對于用戶體驗的影響也是非常大。這個案例首先在CPU 收斂的測試方案上有很大的突破,通過較小的成本發現了不收斂的場景;其次,通過測試頁面和弱網環境穩定復現bug,幫助RD定位問題,最后通過查閱blink 內核的官方文檔、代碼記錄和bug 系統,最終找到了解決方案, 提升了整體產品的體驗。
百度MTC是業界領先的移動應用測試服務平臺,為廣大開發者在移動應用測試中面臨的成本、技術和效率問題提供解決方案。同時分享行業領先的百度技術,作者來自百度員工和業界領袖等。
>>如有問題,歡迎與我溝通
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。