巩义网站优化,可以做天猫代码的网站,手机app制作费用,网站大气模板Android Dynamic Performance Framework(ADPF)是google推广的一套用于优化散热以及CPU性能的动态性能框架。本文主要介绍其中的performance hint的部分。 1、为何引入ADPF 我们都知道#xff0c;在大多数设备上#xff0c;Android 会动态调整CPU的频率和核心类型。如果work l… Android Dynamic Performance Framework(ADPF)是google推广的一套用于优化散热以及CPU性能的动态性能框架。本文主要介绍其中的performance hint的部分。 1、为何引入ADPF 我们都知道在大多数设备上Android 会动态调整CPU的频率和核心类型。如果work load使用的CPU资源较多那么提升CPU的频率工作负载最终会移至性能更强的CPU核心上。如果work load使用的CPU资源较少那么Android会减少资源分配。对于任务的负载主流的有两种算法: PELTPer-Entity Load Tracking和WALTWindow Assist Load Tracking). 但是不管是那种负载统计方法都需要采集过去一段时间内的线程运行情况都存在一定的时间滞后性。 图 1. 调节器可能需要大约 200 毫秒的时间来增加或降低 CPU 频率。 本文借鉴ADPF官网介绍文档里面的案例如上图1由于任务负载统计的累计需要一定的时间一个任务要经过200ms才能运行到最高频率。以我们当前屏幕的刷新率60HZ为例每一帧的完整绘制时间不超过33.3ms. 因此DCVS的这种的滞后性会导致我们调频不及时带来图形绘制上的卡顿。 图2CPU调频过慢导致的卡顿丢帧 上图2是我们在实际性能分析过程中遇到的一个经典案例我们可以看到QQ主线程在过去几帧的耗时并不长但是某一帧因为工作负载的原因出现了长时间运行CPU频率阶段性提升最终错误了vsync导致了丢帧卡顿。 2、ADPF API描述 借助ADPF应用或者游戏可以发送有关其性能和截止时间的额外信号。这个有助于系统更积极地磨合改善性能并降低在工作负载完成后迅速的调整时钟节省电量。在PerformanceHintManager.Session里面我们可以看到如下几个暴露的API: ADPF performance hint API描述closeEnds the current hint session.关闭当前的提示sessionreportActualWorkDuration(long actualDurationNanos)Reports the actual duration for the last cycle of work.上报上一次周期工作的的实际运行时长reportActualWorkDuration(WorkDuration workDuration)Reports the work duration for the last cycle of work.上报上一次周期工作的的实际运行时长setPreferPowerEfficiency(boolean enabled)This tells the session that these threads can be safely scheduled to prefer power efficiency over performance.现在主流移动处理器都是采用big-little架构此API用于告诉系统这些相关的线程更加倾向于放置到性能核心上还是放到能效核心上setThreads(int[] tids)Set a list of threads to the performance hint session.用于设置在当前session里面需要关注的关键线程updateTargetWorkDuration(long targetDurationNanos)Updates this sessions target total duration for each cycle of work.上报工作周期一般匹配vsync周期。 下面我们来跟踪一下这些API在android源码里面是怎么使用案例吧。 在frameworks/base/libs/hwui/renderthread/HintSessionWrapper.cpp的init函数中我们可以看到 通过createSessionInternal(manager, tids.data(), tids.size(), targetDurationNanos, SessionTag::HWUI)创建了一个session其中tids分别是mUiThreadId跟mRenderThreadId。也就是核心关键线程分别是ui主线程以及render线程。这个熟悉android性能分析或者绘制流程的同学都知道在hwui绘制里面应用主线程以及render渲染线程是整个绘制链路中的核心线程。 reportActualWorkDuration用于在实际的绘制过程中向ADPF上报每一帧的时机绘制耗时。这套framework框架最终依赖于平台对这些hint的最终反应才能最终达到优化 performance的效果。 3、应用开发者如何使用ADPF 在google的ADPF官方文档里面也提到了Cocos、Unity、Unreal等游戏引擎采用ADPF来给android发送性能相关的细节信息因为游戏的绘制跟游戏引擎具有很强的关联区别与android上传统的hwui的绘制。 以unity为例https://docs.unity3d.com/Packages/com.unity.adaptiveperformance.google.android1.2/manual/index.html 由于游戏引擎被众多的游戏应用所采用在游戏引擎中使用ADPF不失为一个好的推广途径。unity引擎通过createHintSession 来创建一个hint session通过reportActualWorkDuration来上报在实际一帧过程中所有相关参与到的线程的工作负载当然最终对于CPU核心的频率调节以及任务摆置到性能核心还是能效核心这些都需要vendor平台厂商或者android设备开发商对于这些hint进行操作系统层面的支持与优化。 由于游戏会有较高的工作负载以及发热的分享文档介绍了关于thermal以及游戏gameMode相关的内容不在本文的介绍范围之类不再赘述。 4、底层开发者如何支撑ADPF 那么设备开发商是如何支撑ADPF的呢其中MTK做相比晚上一些。本文以MT6989的内核开源代码为例展开研究忽略掉了从framework到kernel的中间native实现。在kernel/kernel_device_modules-6.1/drivers/misc/mediatek/performance/perf_ioctl/ioctl_powerhal.c文件中我们看到了一些跟ADPF上层API比较对应的功能实现函数。 从名字上看这些函数是跟ADPF的框架API基本一一对应的。powerhal_adpf_create_session_hint_fp我们可以知道对应着框架创建一个sessionpowerhal_adpf_report_actual_work_duration_fp 用于上报work duration powerhal_adpf_set_threads_fp 用于上报核心线程。 以powerhal_adpf_set_threads_fp为例其对应的实现为adpf_set_threads函数。调用了adpf_notify_callback(ADPF_SET_THREADS, sid);函数。最终调用通过adpf_register_callback注册进来的callback函数。我们看到有两个地方进行了callback的注册一个是sched另外一个是fpsgo adpf_register_callback(sched_adpf_callback); adpf_register_callback(fpsgo_notify_adpf_hint); 那么我们就想起看看sched以及fpsgoMTK的一套私有的基于追帧的任务摆核与调频方案针对powerhal_adpf_set_threads_fp的实现具体是什么。 先从scheduler开始。 在sched_adpf_callback函数中 我们可以看到sched的callback做了两件事情 1.通过set_task_basic_vip把上报的关键线程设置为VIP线程我们简单理解VIP为特权线程可以优先进行任务调度来优化调度延迟。对应高通walt调度器里面的MVP线程。针对VIP线程这里不对具体的技术细节展开描述。主要是为了降低线程的调度时延的。我们知道cfs调度类的进程是基于vruntime的公平调度在重载下并不能保障相应线程的runnable的调度时延。 2.__set_task_to_group也是MTK的私有函数通过将一些线程放到一个group里面去针对整个group进行负载的统计与调频。group的概念并不是非常陌生在高通的walt代码里面可以看到related_thread_group的概念在ios中也可以看到 thread group的概念。其实都是尽可能跳出linux原生调度器以task或者cpu为基础单位的负载统计而是以业务涉及到的线程组为单位进行负载的统计。 再回过头来看fpsgo针对线程上报的处理函数。在函数fpsgo_notifier_wq_cb_adpf_hint中 依然可以看到fpsgo调用私有的函数将上报的关键线程添加到fpsgo的依赖线程列表depency list里面可以认为是fpsgo跟踪的关键线程做后续的关键线程的负载跟踪以及uclamp针对关键线程的迁核与提频的处理。对于fpsgo的细节本文不展开进行细节讨论可以认为是一种针对绘制链路的关键线程的负载跟踪与调频调度的方案。 5、对ADPF的一点感想 本文以google的ADPF简单的串联了一下在MTK平台上的相关代码。我们知道linux操作系统的一些底层机制存在一些机制上的弱点这些弱点包括普通CFS进程无法保障调度延迟PELT/WALT负载跟踪在负载波动时存在滞后性DCVS调频依赖于历史统计数据。这些弱点在面向交互式设备上无法快速的对用户的操作进行及时的响应。因此ADPF框架可以有效的将业务跟操作系统的机制连接在一起通过主动的告诉参与到业务的核心线程、业务的工作周期以及业务的资源述求等等hint来让操作系统的底层机制更好的为业务目标而服务。 从ADPF中可以看到google在流畅性与功耗热上的一些探索尝试将android的业务与linux的底层机制揉合成一个整体的这种意图与期望。从中我们也可以看到它借鉴了ios上的thread group与WIOwork interval object的思路。当前ADPF的推广接入并不是十分理想如webview、flutter等场景参与绘制链路的并不仅仅是应用主线程以及render渲染线程更加需要通过ADPF框架来提供性能hint做好优化。与此同时这样比较开发的接口也可能导致被”有意“的使用带来适得其反的效果这也是需要注意的。 名词缩写 DCVSDynamic Clock and Voltage Scaling ADPFAndroid Dynamic Performance Framework PELT:Per-entity Load tracing WALTWindow assist load tracing WIOwork interval object 参考 1.https://developer.android.com/games/optimize/adpf 2.https://github.com/oppo-source/android_kernel_modules_oppo_mt6989/tree/oppo_mt6989_u_14.0.1_oppo_find_x7 3.https://docs.unity3d.com/Packages/com.unity.adaptiveperformance.google.android1.2/manual/index.html 往 期 推 荐 Google VINTF机制经验总结 10分钟了解OPPO中间件容器化实践 2024年Arm最新处理器架构分析——X925和A725