浏览内核CPU不收敛问题定位和分析

  问题发现

     浏览内核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. 场景更加贴近用户使用;

测试结果:

     使用新测试方案完成测试后,发现如下几个问题:

问题一   页面切换至不可见窗口场景:测试中心、CSSH5GIF 等多个页面不收敛;

问题二   APP 切后台场景:测试中心页面不收敛;

  初步分析

问题一通过对测试结果的分析,当用户创建空白页面,使测试页面切换至不可见窗口的场景时,包含GIF 图、CSS 动态元素的页面CPU 仍然有波动,而没有收敛至0 这里可以猜测出可能当页面不可见时,页面的绘制没有进行pause,内核判断页面动态元素有更新,因此还在不断的进行绘制,导致CPU 不为0

问题二测试中心页面不收敛,该页面是测试平台的导航页面,本身没有动态元素,但是仍有不收敛现象。QA通过绘制工具systrace分析页面加载过程的数据,发现切换切换后台后,内核的main(scheduler)/thread_proxy(cc)在工作,还在绘制内容。推测有两个可能:1.APP切后台,没有pause当前的webview2.测试中心首页的某些逻辑导致内核没被pause

  业务和代码分析

内核加载过程——浏览内核加载页面的网络部分向网络发起请求并把网页资源下载给Loader,之后 HTML Parser HTML Script 解析成 DOM 树,再结合 CSS 层叠样式表生成对应的 Render 树。Render 树上就包含了每个元素的各种属性字体、颜色、屏幕上面的坐标、长、宽等。Render 树进一步生成 Graphics Context 交给平台相关的图形库把页面展示在屏幕上。大体过程是如下图这样,实际上内核是边加载边绘制的。

浏览内核CPU不收敛问题定位和分析              

内核绘制过程——浏览内核为了减少不必要的绘制,保证页面的绘制速度和页面滑动的流畅度,对Render Tree 进行了分层,可以更方便的进行页面的局部更新。有更新的layer 将更新数据经过合成composite阶段,将真正的需要绘制区域数据给GL 进行draw,最终完成图像的显示。整个过程是多线程的,通过消息来驱动这个流程。

 浏览内核CPU不收敛问题定位和分析

     动态元素由于更新频率高,通常会划分为单独的layer,如果这个layer 的更新消息没有暂停,就会导致这个消息驱动layer 的合成,进行更新区域的计算,调用drawGL 进行图像的draw。因此CPU 会一直被占用。

真相大白

问题一

     页面动态元素不收敛,通过将页面中动态元素删除后,测试结果为收敛,由此可以证明确实是动态元素导致。动态元素有频繁的更新消息,使得不断对包含动态元素的layer 进行合成和绘制,导致CPU 不收敛。首先需要查看该webview 是否是否被pausewebview 被切换至不可见状态时,策略上应该暂停一切页面的处理,节约更多的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 3536都是不收敛,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是业界领先的移动应用测试服务平台,为广大开发者在移动应用测试中面临的成本、技术和效率问题提供解决方案。同时分享行业领先的百度技术,作者来自百度员工和业界领袖等。

>>如有问题,欢迎与我沟通

原创文章,作者:3628473679,如若转载,请注明出处:https://blog.ytso.com/193597.html

(0)
上一篇 2021年11月15日
下一篇 2021年11月15日

相关推荐

发表回复

登录后才能评论