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

HarmonyOS
1天前
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
FengTianYa
  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函数耗时差异明显。

<a name="table159221726141716"></a> <table><tbody><tr id="row10941152661719"><td class="cellrowborder" rowspan="2" valign="top"><p id="p17941112631715"><a name="p17941112631715"></a><a name="p17941112631715"></a>手机版本</p> </td> <td class="cellrowborder" colspan="3" valign="top"><p id="p194192631715"><a name="p194192631715"></a><a name="p194192631715"></a>nativeTrack耗时</p> </td> </tr> <tr id="row20941122616170"><td class="cellrowborder" valign="top"><p id="p159415260176"><a name="p159415260176"></a><a name="p159415260176"></a>总耗时</p> </td> <td class="cellrowborder" valign="top"><p id="p5941182641715"><a name="p5941182641715"></a><a name="p5941182641715"></a>自身函数耗时</p> </td> <td class="cellrowborder" valign="top"><p id="p19941192615171"><a name="p19941192615171"></a><a name="p19941192615171"></a>libpaddle_light_api_shared.so</p> </td> </tr> <tr id="row11941202619175"><td class="cellrowborder" valign="top" width="25%"><p id="p79411826161710"><a name="p79411826161710"></a><a name="p79411826161710"></a>3.0.018</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="p109421263171"><a name="p109421263171"></a><a name="p109421263171"></a>33ms</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="p5942192681720"><a name="p5942192681720"></a><a name="p5942192681720"></a>22ms</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="p794222651711"><a name="p794222651711"></a><a name="p794222651711"></a>总耗时10ms 调用8次 最大耗时3.5ms</p> </td> </tr> <tr id="row494212265179"><td class="cellrowborder" valign="top" width="25%"><p id="p1094211266179"><a name="p1094211266179"></a><a name="p1094211266179"></a>3.0.0.31</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="p16942112616173"><a name="p16942112616173"></a><a name="p16942112616173"></a>67ms</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="p109421826151718"><a name="p109421826151718"></a><a name="p109421826151718"></a>50ms</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="p17942226161710"><a name="p17942226161710"></a><a name="p17942226161710"></a>总耗时17ms 调用13次 最大耗时4.5ms</p> </td> </tr> </tbody> </table>

  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 解决方案

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

分享
微博
QQ
微信
回复
1天前
相关问题
系统升级HarmonyOS系统app签名问题
1084浏览 • 1回复 待解决
HarmonyOS 页面滑动
223浏览 • 1回复 待解决
HarmonyOS 横竖屏翻转
28浏览 • 1回复 待解决
HarmonyOS List嵌套waterflow滑动
455浏览 • 1回复 待解决
HarmonyOS 页面嵌套滑动时
18浏览 • 1回复 待解决
关于鸿蒙系统升级正式版都有啥机形
9665浏览 • 1回复 待解决
HarmonyOS WebView加载H5
258浏览 • 1回复 待解决
HarmonyOS LazyForEach多层级数据性能
195浏览 • 1回复 待解决
Web嵌套滑动怎么办?
362浏览 • 1回复 待解决
关于启动慢问题首帧分析
585浏览 • 1回复 待解决
不是华为手机可以升级鸿蒙系统
11132浏览 • 3回复 待解决