HarmonyOS 手机系统升级后ui变得卡顿?

如题:HarmonyOS 手机系统升级后ui变得卡顿?

阅读 825
1 个回答
  1. 背景介绍

1.1 问题描述

  • 问题一:手机系统更新为最新的api12整体推理速度变慢,在人脸识别界面点击关闭按钮,要等3秒后才会响应点击事件,ui线程卡顿。
  • 问题二:手机系统升级到26之后,ui变得卡顿,影响场景在应用人脸识别界面有个20s倒计时,正常的情况倒计时数字每秒要变化一次,卡顿导致倒计时数字会出现隔几秒才变化,严重影响正常业务。

1.2 初步分析结论

  • 问题一:receiver接收相机预览流的帧数据,从ArkTS传到native,在native里接收receiver,然后获取arraybuffer做计算,就导致性能变差,c++侧算法耗时18版本是20ms,25版本大概400ms,相差20倍,系统变更导致纯c++计算性能裂化。
  • 问题二:receiver.on('imageArrival')接收相机预览流的帧数据,从ArkTS侧获取arraybuffer,传到native侧做人脸识别算法,对比分析运行trace的调用栈,发现人脸识别算法中的nativeTrack函数耗时差异明显。

<p id="p17941112631715">手机版本</p> <p id="p194192631715">nativeTrack耗时</p>
<p id="p159415260176">总耗时</p> <p id="p5941182641715">自身函数耗时</p> <p id="p19941192615171">libpaddle_light_api_shared.so</p>
<p id="p79411826161710">3.0.018</p> <p id="p109421263171">33ms</p> <p id="p5942192681720">22ms</p> <p id="p794222651711">总耗时10ms 调用8次 最大耗时3.5ms</p>
<p id="p1094211266179">3.0.0.31</p> <p id="p16942112616173">67ms</p> <p id="p109421826151718">50ms</p> <p id="p17942226161710">总耗时17ms 调用13次 最大耗时4.5ms</p>
  1. 定位定界方法

2.1 排查问题

step1 分析trace,对比差异

对比分析trace,调用栈发现耗时差异在so,需要看so的具体实现,找出可疑的部分。

step2 联合定位

日志打点,缩小范围,定位一个纯c++的函数在两个版本差异明显,锁定代码行数30+。

void CBankCardProcessYolo::decodeYUV420SP(MImage &imgColor, unsigned char* yuv420sp, int width, int height)
{
  //OH_LOG_INFO(LOG_APP, "RecognizeNV21 decodeYUV420SP start");
  int frameSize = width * height;
  int i = 0, y = 0;
  int uvp = 0, u = 0, v = 0;
  int y1192 = 0, r = 0, g = 0, b = 0;
  for (int j = 0, yp = 0; j < height; j++) {
  uvp = frameSize + (j >> 1) * width;
  unsigned char *src = imgColor.m_lpLine[j];
  u = 0;
  v = 0;
  for (i = 0; i < width; i++, yp++) {
    if (y < 0)
      y = 0;

    y = (0xff & ((int)yuv420sp[yp])) - 16;
    if (y < 0)
      y = 0;

    if ((i & 1) == 0) {
      v = (0xff & yuv420sp[uvp++]) - 128;
      u = (0xff & yuv420sp[uvp++]) - 128;
    }
    y1192 = 1192 * y;
    r = (y1192 + 1634 * v);
    g = (y1192 - 833 * v - 400 * u);
    b = (y1192 + 2066 * u);

    if (r < 0)
      r = 0;
    else if (r > 262143)
      r = 262143;
    if (g < 0)
      g = 0;
    else if (g > 262143)
      g = 262143;
    if (b < 0)
      b = 0;
    else if (b > 262143)
      b = 262143;
    src[i * 3 + 2] = (r >> 10);
    src[i * 3 + 1] = (g >> 10);
    src[i * 3] = (b >> 10);
  }
}
}

step3 内部写demo复现

按照业务流程,写demo,加上可疑代码,本地稳定复现,采用最笨的方法,给每行代码前后加日志打点,确认是yuv420sp[yp]这句代码在25版本耗时长;规避方案将yuv420sp复制一份,然后用复制后的char*参与计算;长期方案提单跟踪。

step1 分析trace,对比差异

  • 性能问题第一考虑抓frame trace分析,分别抓取不同手机版本的运行trace,重点看主进程泳道和ArkTS Callstack泳道。
  • 以人脸识别SDK为例,通过ArkTS Callstack对比分析发现,有大量的nativeTrack方法在主线程执行且是阻塞的,导致vsync信号没有机会上屏,也就无法刷新ui,31版本最长看到间隔7秒才有一个vsync信号,对比分析18版本在1s内至少有一次vsync信号,连续的耗时任务导致cpu没有空闲处理ui刷新。

  • 都是连续的耗时任务,继续对比分析调用栈,发现nativeTrack函数在不同的版本耗时有差异,31版本耗时更大,可能就是这个函数耗时大导致ui线程阻塞,这个函数内部有多个其它函数会调用libpaddle\_light\_api\_shared.so,汇总信息nativeTrack函数耗时主要有两部分内部自身耗时+libpaddle\_light\_api\_shared.so耗时,其中libpaddle\_light\_api\_shared.so耗时差异不大,耗时大头在内部自身代码。

  • 看代码是纯c/c++编写,没有使用到系统接口,看不出来是哪行代码导致性能裂化,想着在可疑的地方加上日志打点逐句排查,这条路试过没走通;

step2 联合定位

重点看nativeTrack函数,影响代码行数1000+,逐行加打点这条路走不通,没办法找出劣化的具体点。

step3 内部写demo复现

代码1000+行,没办法写demo验证。

2.2 问题根因

问题一:手机系统18升级到25后ArrayBuffer取值性能变差,经开发确认是没有使能cache,surfaceBuffer数据是由相机创建填入的,buffer创建时需要填入usage信息,这个会影响buffer获取效率。

问题二:未找到根因,可以明确的是系统版本升级确实导致一段c++代码性能劣化,1s内onImageArrival会回调28次,平均30ms左右会触发一次,如果每次回调函数处理耗时50ms以上就会出现倒计时卡顿,代码太多没有办法找到劣化点。

2.3 解决方案

提供规避方案适配,计算完一帧数据才去处理下一帧。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进