0


Android Camera性能优化概述

背景

做camera性能优化方面的工作有几年了,想写一篇文章简单介绍一下其中涉及到的具体技术,这篇文章会大概介绍一下涉及到的技术。

一、性能优化关键点众览

** 性能优化分析方向:**给了多少资源和做了多少事。

  • 给多少资源主要是硬件方面资源,比如CPU频率、GPU频率、NPU频率、外设IO总线的clock、memory大小等,需要重点关注分配给当前task的资源,尤其是CPU时间片。在平衡功耗、内存和稳定性后应当最大化供给;
  • 做多少事主要是从软件角度触发,聚焦于业务逻辑的优化,以及整个系统的优化,不执行冗余代码,尽可能不阻塞关键路径和抢占其资源。
  • 达成目标:快且流畅,减少迟滞、波动(时快时慢)和不连贯(丢帧)给用户带来的心理落差。总结三个字就是:快、稳、省。
  • 优化建议:有全局观,抓主要矛盾,综合取舍。

二、性能关键技术

1. CPU调度

1.1 调度单位

线程是Linux的最小调度单位,而资源是以进程为单位进行分配和管理,包括程序(program text)、数据(data )、文件(open file)等,这些资源由同一进程下的线程共享。

1.2 线程状态

分析性能问题时,主要关注下面几种状态:

  • Running(R): 线程在正常执行代码逻辑
  • Runnable(R): 可执行状态,等待调度,如果长时间调度不到,说明CPU繁忙
  • Sleeping(S): 休眠,一般是在等待事件驱动
  • Uninterruptible Sleep(D): 不可中断的休眠,需要看Args的描述来确定当时的状态
  • Uninterruptible Sleep - Block I/O(D): IO阻塞

1.3 线程优先级

Linux线程优先级

Linux线程优先级的范围是 0 ~ 139,值越小,优先级越高。userspace线程优先级的范围是 100 ~ 139,默认创建的线程优先级是120,对应的nice值是0,nice值的范围是 -20 ~ 19,对应的优先级是 100 ~ 139。只有内核线程才支持低于100的优先级,优先级低于100的线程称为RT级线程。

前面值的定义可以从如下链接 https://cs.android.com/android/kernel/superproject/+/common-android-mainline:common/include/linux/sched/prio.h?q=linux%2Fsched%2Fprio.h 获取。

Android的Process类封装了线程优先级设置接口,范围是 -20 ~ 19,跟Linux的nice值一致。Android预定义了一些优先级给系统使用。代码详细见如下:

https://cs.android.com/android/platform/superproject/+/android14-qpr3-release:frameworks/base/core/java/android/os/Process.java?q=java%2Fandroid%2Fos%2FProcess.java
线程优先级nice值解释THREAD_PRIORITY_LOWEST19最低优先级THREAD_PRIORITY_BACKGROUND10后台THREAD_PRIORITY_LESS_FAVORABLE1比默认略低THREAD_PRIORITY_DEFAULT0默认THREAD_PRIORITY_MORE_FAVORABLE-1比默认略高THREAD_PRIORITY_FOREGROUND-2前台THREAD_PRIORITY_DISPLAY-4显示相关THREAD_PRIORITY_URGENT_DISPLAY-8显示(更为重要),input事件THREAD_PRIORITY_AUDIO-16音频相关THREAD_PRIORITY_URGENT_AUDIO-19音频(更为重要)
Java线程优先级

Java标准接口是通过Thread类设置优先级,范围为1 ~ 10。代码详细见如下所示:

https://cs.android.com/android/platform/superproject/main/+/main:libcore/openjdk_java_files.bp;l=250?q=main%2Fjava%2Fjava%2Flang%2FThread.java

Java优先级最终也要通过系统调用来设置进程的NICE值来调整进程的优先级的。代码如下所示:

https://cs.android.com/android/platform/superproject/+/android14-qpr3-release:art/runtime/thread.cc?q=art%2Fruntime%2Fthread.cc

static const int kNiceValues[art::palette::kNumManagedThreadPriorities] = {
        ANDROID_PRIORITY_LOWEST,  // 1 (MIN_PRIORITY)
        ANDROID_PRIORITY_BACKGROUND + 6,
        ANDROID_PRIORITY_BACKGROUND + 3,
        ANDROID_PRIORITY_BACKGROUND,
        ANDROID_PRIORITY_NORMAL,  // 5 (NORM_PRIORITY)
        ANDROID_PRIORITY_NORMAL - 2,
        ANDROID_PRIORITY_NORMAL - 4,
        ANDROID_PRIORITY_URGENT_DISPLAY + 3,
        ANDROID_PRIORITY_URGENT_DISPLAY + 2,
        ANDROID_PRIORITY_URGENT_DISPLAY  // 10 (MAX_PRIORITY)
};

palette_status_t PaletteSchedSetPriority(int32_t tid, int32_t managed_priority) {
    if (managed_priority < art::palette::kMinManagedThreadPriority ||
        managed_priority > art::palette::kMaxManagedThreadPriority) {
        return PALETTE_STATUS_INVALID_ARGUMENT;
    }
    int new_nice = kNiceValues[managed_priority - art::palette::kMinManagedThreadPriority];
    int curr_nice = getpriority(PRIO_PROCESS, tid);

    if (curr_nice == new_nice) {
        return PALETTE_STATUS_OK;
    }

    if (new_nice >= ANDROID_PRIORITY_BACKGROUND) {
        SetTaskProfiles(tid, {"SCHED_SP_BACKGROUND"}, true);
    } else if (curr_nice >= ANDROID_PRIORITY_BACKGROUND) {
        SchedPolicy policy;
        // Change to the sched policy group of the process.
        if (get_sched_policy(getpid(), &policy) != 0) {
            policy = SP_FOREGROUND;
        }
        SetTaskProfiles(tid, {get_sched_policy_profile_name(policy)}, true);
    }

    if (setpriority(PRIO_PROCESS, tid, new_nice) != 0) {
        return PALETTE_STATUS_CHECK_ERRNO;
    }
    return PALETTE_STATUS_OK;
}
  • MAX_PRIORITY相当于android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY,值为10;
  • MIN_PRIORITY相当于android.os.Process.THREAD_PRIORITY_LOWEST,值为0;
  • NORM_PRIORITY相当于android.os.Process.THREAD_PRIORITY_DEFAULT,值为5。

1.4 CPU调度策略

1.4.1 调度器

高通从Kernel 4.9之后使用EAS (Energy Aware Scheduling)作为CPU调度器。EAS针对异构 CPU 架构(Arm big.LITTLE)设计,其调度算法基于 CFS 任务唤醒平衡代码,当时引入能量模型( EM)在调度任务时选择节能目标CPU,在保证性能的前提下尽可能地降低功耗。

1.4.2 CPUFreq Governor

跟EAS配合动态调整CPU频点。对性能影响较大,需要了解governor提供的参数配置进行tune来达到较佳效果。

  • Walt

  • Schedutil

1.4.3 CGroup

CGroups是control groups的缩写,是Linux内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物理资源(cpu,memory,IO等等)的机制。CGroups提供了以下功能:

  • 限制进程组可以使用的资源数量(Resource limiting )。比如:memory子系统可以为进程组设定一个memory使用上限,一旦进程组使用的内存达到限额再申请内存,就会出发OOM(out of memory)。
  • 进程组的优先级控制(Prioritization )。比如:可以使用cpu子系统为某个进程组分配特定cpu share。
  • 记录进程组使用的资源数量(Accounting )。比如:可以使用cpuacct子系统记录某个进程组使用的cpu时间
  • 进程组隔离(Isolation)。比如:使用ns子系统可以使不同的进程组使用不同的namespace,以达到隔离的目的,不同的进程组有各自的进程、网络、文件系统挂载空间。
  • 进程组控制(Control)。比如:使用freezer子系统可以将进程组挂起和恢复。

根据谷歌文档(https://source.android.com/devices/tech/perf/cgroups), Android 9 及更低版本,只能通过init.rc初始化脚本创建及挂载cgroup,而Android 10 及更高版在early-init阶段挂载,在cgroups.json文件中配置cgroup组及挂载路径属性等。

cgroups其挂载也可以用下面命令查看。

thor:/ # mount -t cgroup
none on /dev/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
none on /dev/cpuctl type cgroup (rw,nosuid,nodev,noexec,relatime,cpu)
none on /dev/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset,noprefix,release_agent=/sbin/cpuset_release_agent)
none on /dev/memcg type cgroup (rw,nosuid,nodev,noexec,relatime,memory)

查看进程的cgroup配置,如camera provider:

thor:/ # cat /proc/$(pidof [email protected]_64)/cgroup
4:memory:/camera/provider
3:cpuset:/camera-daemon
2:cpu:/foreground
1:blkio:/
0::/uid_1047/pid_1197
  • cpuset

文件节点

作用

tasks

列举绑定到某个 cgroup的所有线程程ID,将线程ID写入此文件会将线程移至该cgroup。

cgroup通用

cgroup.procs

cgroup中的进程ID的列表,将进程ID写入此文件会将进程移至该cgroup。

cgroup通用

notify_on_release

flag 文件: :填 0 或 1,表示是否在 cgroup 中最后一个 task 退出时通知运行release agent,默认情况下是 0,表示不运行

cgroup通用

release_agent

指定 release agent 执行脚本的文件路径(此文件仅在顶级cgroup中存在),在这个脚本通常用于自动化umount无用的 cgroup

cgroup通用

cgroup.clone_children

该标志仅影响cpuset控制器。 如果在cgroup中启用了 clone_children 标志(1),则新的cpuset cgroup将在初始化期间从父级复制其配置。

cpuset特有

cpuset.cpus

限制一组进程所能使用的cpu, 供用户进行设置

cpuset.cpu_exclusive

flag:设置为1时,说明独占指定cpus,默认为0

独占cpu的意思是,如果某个cpuset是独占的,那么该cpuset中的cpu是不能被该cpuset的兄弟cpuset共享的,当然该cpuset中的cpu是能够和该cpuset的祖先cpuset和子孙cpuset共享的。

注意:设置exclusive时,需要其父节点也为exclusive。否则会设置失败。所以,最终还是说明cpuset的独占,就是从根节点开始,就已经独占了。

cpuset.effective_cpus

显示实际进程可以使用的cpu

sched_load_balance

flag

:默认为值

1

,表示进程会在该

cpuset

中允许的

cpu

上进行负载均衡

sched_relax_domain_level

可设置的值为

-1

到一个较小的整数值,只有

sched_load_balance

1

时生效,值越大,表示负载均衡时查找的

cpu

范围越大

-1 : no request. use system default or follow request of others.

0 : no search.

1 : search siblings (hyperthreads in a core).

2 : search cores in a package.

3 : search cpus in a node [= system wide on non-NUMA system]

4 : search nodes in a chunk of node [on NUMA system]

5 : search system wide [on NUMA system]

mems相关节点

android只有一个内存节点,用不到

  • cpuctl

文件节点

作用

tasks

列举绑定到某个 cgroup的所有线程程ID,将线程ID写入此文件会将线程移至该cgroup

cgroup.clone_children

cgroup.procs

cpu.shares

限制cgroup的cpu相对使用比例,值越大拿到的CPU资源越多

cpu.uclamp.latency_sensitive

cpu.uclamp.max

cpu.uclamp.min

notify_on_release

  • 任务配置文件(Task profiles file)

Android 10之后使用task_profiles.json(https://source.n.xiaomi.com/opengrok-s/xref/pangu_8450-s-combine/system/core/libprocessgroup/profiles/task_profiles.json)作为任务配置文件,提供了一种抽象概念将必需的功能与该功能的实现详情分离。Android 框架使用 SetTaskProfiles 和 SetProcessProfiles API,按照 task_profiles.json 文件中的描述将任务配置文件应用于进程或线程(这些 API 是 Android 11 及更高版本所独有的)。为了实现向后兼容,旧版函数 set_cpuset_policy、set_sched_policy 和 get_sched_policy 提供相同的 API 和功能,但其实现已修改为使用任务配置文件。对于新的用例,AOSP 建议使用新的任务配置文件 API,而不是旧版 set_sched_policy 函数。

  • 组优先级

组优先级Process.java

优先级策略 SchedPolicy

对应cpuset group级别 sched_policy.cpp

THREAD_GROUP_BACKGROUND 0

SP_BACKGROUND

/dev/cpuset/background/tasks

THREAD_GROUP_FOREGROUND 1

THREAD_GROUP_AUDIO_APP 3

THREAD_GROUP_AUDIO_SYS 4

SP_FOREGROUND

SP_AUDIO_APP

SP_AUDIO_SYS

/dev/cpuset/foreground/tasks

THREAD_GROUP_TOP_APP 5

SP_TOP_APP

/dev/cpuset/top-app/tasks

THREAD_GROUP_SYSTEM 2

SP_SYSTEM

/dev/cpuset/system-background/tasks

THREAD_GROUP_RESTRICTED 7

SP_RESTRICTED

/dev/cpuset/restricted/tasks

THREAD_GROUP_RT_APP 6

SP_RT_APP

N/A

AMS在调度过程根据优先级进行分组,同时,进程也可以使用api设置资源使用优先级以及分组。如果有权限,还可以把task id写入cpuset中。常见的是APP使用AsyncTask类,在doInBackground中执行优先级较低的代码,其实就是把该task分到BACKGROUND的组

可以利用cgroup机制,改善了provider进程出现长时间runnable的问题。

总的来时,CPU调度的优化最终会影响task的vruntime(虚拟运行时间),vruntime记录了一个task到当前时刻为止执行的总时间(需要以task总数n进行归一化,并且根据task的优先级进行加权)。vruntime越大,说明该进程运行的越久,所以被调度的可能性就越小。

1.5 PerfLock

//后续有文章进行详细介绍

1.6 进程冻结

//后续有文章进行详细介绍

1.7 LMKD

1.7.1 水线
  • 水线配置

可以使用下面命令查看内存水线设置。

thor:/ # getprop sys.lmk.minfree_levels

18432:0,23040:100,27648:200,32256:250,55296:900,80640:950
  • 双水线

相机切换到前台时会更新水线设置,适当降低内存回收力度。

1.7.2 ADJ

ADJ值范围为-1000 - 1000,通过cat /proc/[pid]/oom_score_adj查看。系统在剩余内存低于水线阈值时,为了维护正在运行的进程,杀掉优先级比较低(adj值比较高)的其他进程。
ADJ级别取值含义NATIVE_ADJ-1000native进程SYSTEM_ADJ-900仅指system_server进程PERSISTENT_PROC_ADJ-800系统persistent进程PERSISTENT_SERVICE_ADJ-700关联着系统或persistent进程FOREGROUND_APP_ADJ0前台进程VISIBLE_APP_ADJ100可见进程PERCEPTIBLE_APP_ADJ200可感知进程,比如后台音乐播放BACKUP_APP_ADJ300备份进程HEAVY_WEIGHT_APP_ADJ400重量级进程SERVICE_ADJ500服务进程(A list中的service)HOME_APP_ADJ600Home进程PREVIOUS_APP_ADJ700上一个进程SERVICE_B_ADJ800B List中的ServiceCACHED_APP_MIN_ADJ900不可见进程的adj最小值CACHED_APP_MAX_ADJ906不可见进程或不含任何活动的应用组件的empty进程的adj最大值

1.8 温控

1.8.1 温控配置和策略

1.8.2 thermald

//后续有时间详细介绍

2. IO调度

IO调度策略、IO block和IO优化(prefetch等),这块内容比较多,后续有空会详细介绍。

3. 内存分配

3.1 内存分配器

mallopt(M_DECAY_TIME, 1)和mallopt(M_PURGE, 0),其中mallopt(M_PURGE, 0)耗时长问题。

3.2 内存压缩和回收

  • ZRAM
  • 内存回收机制
  • 内存碎片整理

https://blog.csdn.net/buhui912/article/details/115895277

3.3 Camera内存

  • imagebuffer
  • metadata pool
  • ion/no-ion
  • HALBufferManager

https://source.android.com/devices/camera/buffer-management-api: Android对HALBufferManager的定义

Camera HAL3 Buffer Management详解

Camera Service buffer与HAL交互

CameraService Buffer如何与HAL交互

高通StreamBufferManager学习

4. 锁机制

  • Java锁
  • pthread mutex、condition
  • futex
  • FileLock

5. IPC

  • binder/aidl/hidl:线程优先级继承、oneway
  • broadcast的性能问题
  • local socket

6. Graphics Framework

https://blog.csdn.net/u012365926/article/details/114921456

  • SurfaceFlinger: composer、vsync
  • BufferQueue: producer、consumer、fence、Gralloc
  • GLRender

界定方法

7. HW Performance

  • GPU/DDR/DSP/HTP/ISP/NCS sensor/videoEncoder(OMX)/BUS(CCI&MIPI):clock、loading、usage
  • sensor node (ois,actuator、otp)、IPE、IFE
  1. sensor打分:
  2. OIS带flash:M3的OIS带有flash,启动速度可以从L1的120ms优化到5ms
  3. I2C总线合理挂载slave:避免同时使用的硬件发生抢占,提高camera工作是多给CCI总线能做到并行传输,以此提高性能

三、性能分析工具

1. Perfetto/Systrace/Atrace

https://perfetto.dev/docs/#/?id=perfetto-performance-instrumentation-and-tracing

https://perfetto.dev/docs/data-sources/memory-counters

https://perfetto.dev/docs/quickstart/android-tracing

2. Simpleperf & 火焰图

  • simpleperf指令:record和report等;
  • android源码丰富的解析脚本.
  • FlameGraph和红蓝火焰图

3. Android Profiler

https://developer.android.com/studio/profile/android-profiler

  • 集成在AndroidStudio中;
  • 需要有APP的源码;
  • 可以抓java和native调用堆栈。

4. ftrace

5. Linux perf工具

https://blog.csdn.net/yiyeguzhou100/article/details/102809576

6. eBPF

Android中的eBPF程序简介-CSDN博客

四、Camera场景性能分析

1.启动

1.1 冷启动

1.1.1 关键路径

//关键流程分析

1.1.2 流程分析

1.1.2.1 APP进程保活

  • 保活机制FastRestart
  • 相机被kill掉后3秒多能被保活机制拉起
02-04 20:17:03.192  4312  4312 D RecentsContainer: removeTask: [id=105 stackId=0 windowingMode=1 user=0 lastActiveTime=318591997, component=ComponentInfo{com.a
ndroid.camera/com.android.camera.Camera}] 相机
02-04 20:17:03.214  2226  5341 D WindowProcessUtils: remove task: Task{9fdb79 #105 type=standard A=10089:com.android.camera U=0 visible=false mode=fullscreen t
ranslucent=true sz=1}
02-04 20:17:03.215  2226  5341 I SplashScreenServiceDelegate: None for com.android.camera
02-04 20:17:03.241  2226  5341 I ProcessManager: OneKeyClean: kill com.android.camera Adj=900 State=16
02-04 20:17:03.241  2226  5341 I ActivityManager: Killing 23899:com.android.camera/u0a89 (adj 900): OneKeyClean
02-04 20:17:03.242  2226  5341 D PerfImpl: perfProcessKillBoost: com.android.camera, 23899, 0
02-04 20:17:03.533  2226  2260 W UsageStatsService: Unexpected activity event reported! (com.android.camera/com.android.camera.Camera event : 23 instanceId : 2
31437437)
02-04 20:17:05.554  2226  2298 D Boost   : hostingType=FastRestart, hostingName=com.android.camera, callerPackage=android, isSystem=true, isBoostNeeded=false.
02-04 20:17:05.554  2226  2298 I ActivityManager: Start proc 27596:com.android.camera/u0a89 for FastRestart com.android.camera caller=android
02-04 20:17:05.596  5231 11184 W MQSService: CallerName:com.android.camera,calling Uid:10089
02-04 20:17:05.596  5231 11184 D MQSService: registerApplicationScoutThread pid = 27596, packageName = com.android.camera
02-04 20:17:05.709 27596 27596 V GraphicsEnvironment: ANGLE Developer option for 'com.android.camera' set to: 'default'
02-04 20:17:05.712 27596 27596 I ForceDarkHelperStubImpl: initialize for com.android.camera , ForceDarkOrigin
02-04 20:17:05.800 27596 27596 D CAM_BoostFrameworkImpl: stopBoost: com.android.camera.CameraAppImpl.attachBaseContext:42
02-04 20:17:05.838 27596 27596 D CAM_BoostFrameworkImpl: stopBoost: com.android.camera.CameraAppImpl.onCreate:12
02-04 20:17:05.845 27596 27596 D MiCameraAlgo: init: application file path to algorithm lib: /data/user/0/com.android.camera/files
02-04 20:17:05.860 27596 27596 D CAM_AlgoConnector: onServiceConnected: ComponentInfo{com.android.camera/com.android.camera.LocalParallelService}, binder = com
  • Application启动

大致流程:ZygoteInit->ActivityThreadMain->bindApplication->serviceCreate->serviceBind

1.1.2.2 启动Trace分析

  • 关键trace点 - iq- startActivityInner- activityStart/activityResume ...

HAL3: RequestTrace/HAL3ProcessCapture/ProcessRequest [request id]/ProcessRequestIdDone/HAL3ProcessCaptureResult ...

1.1.3 关键点
  • CPU频率设置
  • 关键线程runnable和sleep情况

1)running使用trace跟火焰图分析

2)sleep开hal的sync

3)runnable看trace中CPU的抢占

  • APP关键操作的衔接
  • HAL pipeline

1.2 热启动

1.2.1 关键路径

1.2.2 流程分析

1.2.3 关键点

1.2 预览卡顿

生产者和消费者

2. 模式切换

3. Lens切换

4. 拍照

5. 录像

五、优化点

1. 异步化

2. 提前和延后

避免集中化

3. IO

  • pin
  • 预加载

4. 调度优化

 google相关内容

5. 业务逻辑优化

  • 线程优先级
  • 绑核
  • 调度参数调优
  • vruntime补偿
  • EarlyPCR
  • 提前active pipeline
  • offline feature延后create
  • 等等

小结

以上简单总结了一下camera性能优化基础的关键点内容,最重要的其实就是2大类知识。

1.熟练掌握 Linux/Android系统 进程调度,内存管理,文件系统,网络通信等知识点

2.熟练掌握camera系统业务知识,要非常熟悉camera业务关键流程(open/configure/request/result/close等等)。


本文转载自: https://blog.csdn.net/weixin_42136255/article/details/142734095
版权归原作者 repinkply 所有, 如有侵权,请联系我们删除。

“Android Camera性能优化概述”的评论:

还没有评论