瀏覽內(nèi)核CPU 占用問題是影響用戶使用的關(guān)鍵因素,會引起操作卡頓、手機(jī)耗電以及應(yīng)用
創(chuàng)新互聯(lián)是一家專業(yè)提供固鎮(zhèn)企業(yè)網(wǎng)站建設(shè),專注與網(wǎng)站制作、成都網(wǎng)站制作、H5頁面制作、小程序制作等業(yè)務(wù)。10年已為固鎮(zhèn)眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站建設(shè)公司優(yōu)惠進(jìn)行中。
崩潰等問題。CPU 占用由于受到頁面、機(jī)型、應(yīng)用框架的影響,較難進(jìn)行定位和優(yōu)化。在瀏覽內(nèi)核性能測試中發(fā)現(xiàn)CPU 占用高于之前版本,通過分析CPU 曲線,發(fā)現(xiàn)可能是部分場景CPU 沒有收斂導(dǎo)致的,因此對CPU 收斂做了專項(xiàng)測試。
老測試方案——內(nèi)核之前針對CPU 收斂的測試是通過加載用戶訪問Top 100 的頁面,應(yīng)用放后臺通過TOP 命令觀察CPU 收斂情況。
缺點(diǎn): 1.測試工作量非常大;2.Top頁面結(jié)構(gòu)復(fù)雜很難分析是頁面中的那個(gè)元素引起的不收斂現(xiàn)象;3.頁面經(jīng)常變化,收斂狀態(tài)難以穩(wěn)定復(fù)現(xiàn);
新測試方案——通過對頁面的整理分析和與RD 的溝通,引起CPU 不收斂的問題主要是頁面中的動態(tài)元素,如CSS動畫、 視頻播放、 Timer 定時(shí)器、 js 加載、 gif動圖等,并由QA自己開發(fā)動態(tài)元素的測試頁面進(jìn)行測試,在測試場景上選擇了應(yīng)用切后臺和頁面切換至不可見窗口兩種。
優(yōu)點(diǎn):1.測試工作量小,針對性強(qiáng);2.頁面固定、元素簡單,易于復(fù)現(xiàn);3. 場景更加貼近用戶使用;
測試結(jié)果:
使用新測試方案完成測試后,發(fā)現(xiàn)如下幾個(gè)問題:
問題一 頁面切換至不可見窗口場景:測試中心、CSS、H5、GIF 等多個(gè)頁面不收斂;
問題二 APP 切后臺場景:測試中心頁面不收斂;
問題一通過對測試結(jié)果的分析,當(dāng)用戶創(chuàng)建空白頁面,使測試頁面切換至不可見窗口的場景時(shí),包含GIF 圖、CSS 動態(tài)元素的頁面CPU 仍然有波動,而沒有收斂至0, 這里可以猜測出可能當(dāng)頁面不可見時(shí),頁面的繪制沒有進(jìn)行pause,內(nèi)核判斷頁面動態(tài)元素有更新,因此還在不斷的進(jìn)行繪制,導(dǎo)致CPU 不為0。
問題二測試中心頁面不收斂,該頁面是測試平臺的導(dǎo)航頁面,本身沒有動態(tài)元素,但是仍有不收斂現(xiàn)象。QA通過繪制工具systrace分析頁面加載過程的數(shù)據(jù),發(fā)現(xiàn)切換切換后臺后,內(nèi)核的main(scheduler)/thread_proxy(cc)在工作,還在繪制內(nèi)容。推測有兩個(gè)可能:1.APP切后臺,沒有pause當(dāng)前的webview;2.測試中心首頁的某些邏輯導(dǎo)致內(nèi)核沒被pause。
內(nèi)核加載過程——瀏覽內(nèi)核加載頁面的網(wǎng)絡(luò)部分向網(wǎng)絡(luò)發(fā)起請求并把網(wǎng)頁資源下載給Loader,之后 HTML Parser 將 HTML 和 Script 解析成 DOM 樹,再結(jié)合 CSS 層疊樣式表生成對應(yīng)的 Render 樹。Render 樹上就包含了每個(gè)元素的各種屬性字體、顏色、屏幕上面的坐標(biāo)、長、寬等。Render 樹進(jìn)一步生成 Graphics Context 交給平臺相關(guān)的圖形庫把頁面展示在屏幕上。大體過程是如下圖這樣,實(shí)際上內(nèi)核是邊加載邊繪制的。
內(nèi)核繪制過程——瀏覽內(nèi)核為了減少不必要的繪制,保證頁面的繪制速度和頁面滑動的流暢度,對Render Tree 進(jìn)行了分層,可以更方便的進(jìn)行頁面的局部更新。有更新的layer 將更新數(shù)據(jù)經(jīng)過合成composite階段,將真正的需要繪制區(qū)域數(shù)據(jù)給GL 進(jìn)行draw,最終完成圖像的顯示。整個(gè)過程是多線程的,通過消息來驅(qū)動這個(gè)流程。
動態(tài)元素由于更新頻率高,通常會劃分為單獨(dú)的layer,如果這個(gè)layer 的更新消息沒有暫停,就會導(dǎo)致這個(gè)消息驅(qū)動layer 的合成,進(jìn)行更新區(qū)域的計(jì)算,調(diào)用drawGL 進(jìn)行圖像的draw。因此CPU 會一直被占用。
問題一
頁面動態(tài)元素不收斂,通過將頁面中動態(tài)元素刪除后,測試結(jié)果為收斂,由此可以證明確實(shí)是動態(tài)元素導(dǎo)致。動態(tài)元素有頻繁的更新消息,使得不斷對包含動態(tài)元素的layer 進(jìn)行合成和繪制,導(dǎo)致CPU 不收斂。首先需要查看該webview 是否是否被pause,webview 被切換至不可見狀態(tài)時(shí),策略上應(yīng)該暫停一切頁面的處理,節(jié)約更多的CPU和內(nèi)存資源保證當(dāng)前活動窗口的處理。
// webview onPause 的處理 public void onPause() { if (mIsPaused || mNativeAwContents == 0) return; mIsPaused = true; nativeSetIsPaused(mNativeAwContents, mIsPaused); }
內(nèi)核沒有對文檔解析、js 加載、動圖進(jìn)行暫停。
解決方案:
// 網(wǎng)絡(luò)加載暫停 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(); }
問題二
測試中心頁面不能收斂,此頁面并沒有動態(tài)元素,因此用上面的方法分析是不奏效的,需要找其他的方法。百度瀏覽內(nèi)核是基于Blink 35版本再次開發(fā)的版本,因此想要驗(yàn)證下原生內(nèi)核是否有問題,于是驗(yàn)證了Blink 35、36都是不收斂,blink 37 版本可以收斂,因此可以斷定是Blink 內(nèi)核自己的bug,通過對繪制過程相關(guān)代碼的查找,發(fā)現(xiàn)google 工程師對此問題的一個(gè)注釋。
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 有更新進(jìn)行合成過程中,會引入臟數(shù)據(jù)導(dǎo)致layer 一直更新,并進(jìn)行后面的數(shù)據(jù)處理和繪制,導(dǎo)致CPU 不收斂,通過增加打印Log 也可以證明,不收斂的頁面確實(shí)在不斷進(jìn)行該函數(shù)的調(diào)用。
通過對Blink 37 修復(fù)的patch 進(jìn)行研究,內(nèi)核對判斷Layer 更新的狀態(tài)進(jìn)行了修改,調(diào)整了更新判斷的結(jié)構(gòu),刪除了scheduleAnimationIfNeeded 方法,通過其他狀態(tài)判斷是否需要更新layer,并進(jìn)行數(shù)據(jù)的合成進(jìn)行繪制,通過將37 patch 合入測試發(fā)現(xiàn)可以有效解決不收斂問題。
解決方案:
增加了CompositingReasonFinder::requiresCompositingForPosition方法判斷是否需要進(jìn)行合成。
臟數(shù)據(jù)的問題還是沒有根本解決,只是增加了判斷,不會出現(xiàn)之前的循環(huán)處理。
void RenderLayerCompositor::assertNoUnresolvedDirtyBits() { ASSERT(!compositingLayersNeedRebuild()); ASSERT(!m_needsUpdateCompositingRequirementsState); ASSERT(m_pendingUpdateType == CompositingUpdateNone); ASSERT(!m_rootShouldAlwaysCompositeDirty); ASSERT(!m_needsToRecomputeCompositingRequirements); }
CPU 收斂在CPU 性能測試中是一個(gè)非常重要的項(xiàng)目,對于用戶體驗(yàn)的影響也是非常大。這個(gè)案例首先在CPU 收斂的測試方案上有很大的突破,通過較小的成本發(fā)現(xiàn)了不收斂的場景;其次,通過測試頁面和弱網(wǎng)環(huán)境穩(wěn)定復(fù)現(xiàn)bug,幫助RD定位問題,最后通過查閱blink 內(nèi)核的官方文檔、代碼記錄和bug 系統(tǒng),最終找到了解決方案, 提升了整體產(chǎn)品的體驗(yàn)。
百度MTC是業(yè)界領(lǐng)先的移動應(yīng)用測試服務(wù)平臺,為廣大開發(fā)者在移動應(yīng)用測試中面臨的成本、技術(shù)和效率問題提供解決方案。同時(shí)分享行業(yè)領(lǐng)先的百度技術(shù),作者來自百度員工和業(yè)界領(lǐng)袖等。
>>如有問題,歡迎與我溝通