温度控制
做过性能专项项目的同学肯定会有这样的体会,在做了几次冷启动或者重复某个场景之后,手机就会发热。手机发热会影响手机CPU的处理频率,温度过高CPU就会降频,影响运算效率。所以我们需要保持手机的温度恒定。还有一点就是不要用太旧的手机,尤其是电池比较弱的手机,如果手机处于充电状态,有些手机CPU也会降频,优先快充,电池也会发热。在温控方面我们也做了很多尝试,最开始用的是冰袋和后台小风扇+空调,现在用的是专业游戏玩家用的降温设备,这种手机背夹控温效果就很好。
手机温控示例图
CPU锁定频率
还有一种控制手机温度的方法,就是锁定CPU频率,不过需要手机root,这里就不多说了,有兴趣的可以去看看。
分阶段收集数据
支付宝冷启动场景分为2个大阶段,90+个小阶段。有同学会问为什么要分成几个小阶段呢?场景阶段是按照代码功能模块来划分的,为了更好的识别到底是哪些代码导致了性能下降,我们采用了拆分阶段的方式。
支付宝冷启动场景阶段拆分将冷启动场景拆分为两个大阶段,在版本场景阶段对比时,先对比两个大场景是否劣化,如果某个大场景劣化,再查看其子阶段是否劣化,快速定位劣化代码。
场景阶段对比
性能数据采集解决方案
现在我们面临一个问题:如何在不影响线上的情况下,提取场景表现阶段数据?冷启动场景是应用最早的启动时刻,常规手段无法在启动时刻进行初始化。考虑到以后兼容其他场景,有离线重新包装的技术方案,可以灵活地将抽象和实现分离。线上调用的是一个空方法,只有离线录入实现代码时,才会将具体方法的实现录入到支付宝中。当然这里也需要用到SDK,这里先简单提一下,后面再详细介绍。接下来我来介绍一下我们的黑科技,重新包装技术。
首先我们准备一个独立的apk,并给它起个名字叫apk,这个apk会和其他apk一样打包在支付宝主apk中,主要功能有:
1、进行初始化工作,包括SDK初始化、性能诊断逻辑初始化、配置初始化;
2、性能数据采集逻辑和离线数据采集逻辑的实现;
3、性能诊断逻辑及数据采集逻辑。这里的性能诊断数据包括线程、交换机配置、动态加载等。
APK内部实现图
那我们先看看这个APK是怎么插入到支付宝主APK中的,首先将两个APK解压,然后分别进行对应的资源文件1.替换原来的并使用代理;2.so和Dex,读取配置并进行Dex AOP收集诊断数据;3.最后一步就是重新打包并签名APK,生成需要测试的APK。
APK 流程图
重打包机制为获取离线性能数据(包括耗时、诊断数据)提供了极大的便利,线上线下分离,互不干扰,通过重打包的过程,可以随心所欲的获取场景所需要的测量数据和诊断数据。
提高工程性能
在提高工程效率方面,我们这里主要做了两件事:改进CI流程和改进代码变更查看功能。
首先完善了构建流程,对于每个业务集成,都是基于当前基线+业务集成代码构建安装包,后续安装包的基线都是按顺序递增的,只有保证基线按顺序递增,才能一步步的做好性能测试,也就是综合CI能力。
第二,展示每次集成的详细信息,包括每个开发人员的代码、code diff信息,以便更好的定位问题。
问题:
开发代码集成会将其他开发人员的代码带入集成,但是看不到其他开发人员的代码变更信息。
解决方案:
在每个集成应用列表中,增加代码变更信息条目,开启后会展示当前基线与主集成基线之间的所有代码 diff 信息,方便定位问题。该功能不仅方便用户排查性能问题,也方便研发同事一劳永逸地排查功能和稳定性问题。
3. 场景性能诊断
我们引入了场景的度量能力,如果场景耗时恶化,就需要定位问题的原因。将场景拆分为阶段性问题的目的是为了缩小问题范围。但缩小问题范围还不够,性能体验问题比功能 Bug 难解决得多。比如冷启动慢了 20ms,业务方也会很困扰,不知道为什么慢了 20ms。问题分析速度也慢,所以我们也在想有没有办法辅助定位性能问题。
3.1 通用维度性能诊断支付宝场景通用性能诊断
常规的性能诊断维度有线程、IO、动态加载、开关读取等,具体时间是通过AOP切分对应接口来获取对应的诊断数据,这部分在APK中也有实现。
1.对于线程,Hook run方法,创建新实例,获取线程的时间、名称、运行次数;
2. 读取,Hook,获取对应的SP,读取值。mock也是同样的原理,获取对应的sp,通过的key写入即可。
3.动态主线程加载,只需Hook,判断是否在主线程,获取名称和堆栈;
4、为支付宝钱包的服务,Hook e,获取初始化时间和调用链;
5.IO主要涉及Hook read/接口,检查是否存在读写小,读写漏等IO问题。
APK及内部实现原理图
3.2 AOP技术简介
AOP是AOP的缩写,意为面向切向编程,我们在支付宝中用到了它,原理就是在打包构建过程中读取需要hook的类和方法,生成对应的代理函数,我们只想带上目标函数,在代理函数中实现Hook。
其他的Hook工具还有APT、ASM、、、等等,如果想详细了解可以看看,它们都有相应的优缺点,这里就不详细介绍了。这些工具在APK构建的不同时刻的时机是不一样的,下面是 APK构建流程以及不同工具的时机。
APK 构建过程
常见AOP工具及Hook时机
不同的AOP工具在不同的构建阶段实现注入,转换成dex后直接操作dex,添加代理函数,支持函数、函数体切面、实例创建切面,切面类型包括方法切面、方法体切面、对象new切面。
3.3 代码变更性能诊断
在研发过程中,所有的问题都是由代码变更引起的,代码变更信息是定位问题最重要、最有效的途径。回到耗时降级问题,场景耗时降级,或者说某个子阶段的降级,无非就是新增代码对原有功能的改变,导致的耗时增加;另一种就是新增功能方法,导致场景耗时降级。从精细化问题分析的角度,我们可以把整个场景细化成几个阶段,那么能不能做功能级别的耗时分析呢?这是一个技术挑战,我们尝试了几种解决这个问题的方法,幸运的是,我们成功了。接下来,我会介绍代码变更诊断的技术方案。
这期间也尝试了很多技术手段,比如利用AOP对代码功能进行全面插桩,在运行时获取所有函数执行前后的回调等。
第一种方法不适合分段所有函数,生成的代码功能会超出限制。它是对外提供调试接口的虚拟机,全称是Java VM Tool,底层是C++实现,对外接口也是。经过多次尝试,终于完成了demo,实际尝试之后还是失败了,支付宝运行时函数太多,启动时直接卡屏。后来想还是把问题简单化点比较好,不需要全函数数据,只要计算出更改相关代码的耗时和影响其他函数的耗时,就能定位到这个代码改动是哪个函数导致了场景降级。
第一步通过版本基线比对,获取两个版本之间变更的代码,变更的代码信息包括信息、类、方法名、参数和返回值类型,以及是否有新增、变更、删除等。
第二步,针对代码变更进行插桩,各种AOP技术手段在前面章节已经提到过,这里我们采用ASM插桩技术,整体技术方案为:ASM+ASM。
1.我们来回顾一下APK的构建过程,过程中会插入ASM。
APK 构建流程图
2.应用都是构建的,所以需要了解构建的生命周期以及构建插件,在构建的时候我提供了相应的回调时机,大家可以在构建的初始化、配置、执行的时候进行初始化和配置。
构建生命周期接下来,让我们看看提供的机制。
机制过程
其实每一个都是一个任务,编译器把每一个都串联起来,第一个会收到编译的结果,以及本地已经拉取的第三方依赖(jar.aar),资源等。这些编译的中间产物在链条中流动,每个节点都可以处理它们,并传递给下一个节点。我们常见的混淆等逻辑现在都被一个一个地封装进去了,而定制化的逻辑则会被插在这个链条的最前面。
自定义原理图,字节码插入的过程就是通过代码插入的机制,找到对应的类和函数。
机制
支付宝改码插入原理
1.配置
可以配置是否启用插件,主要配置对哪些代码进行插桩、插件版本、构建插桩输出目录、以及需要依赖的jar包。
2. 部分
提供函数运行前后的回调函数,在需要插入的代码执行前后插入回调静态方法,这样可以获取代码函数的执行时间,记录时间戳,计算函数时间。
3.
最核心的部分是自定义性能插件,通过上面提到的机制,在构造过程中找到对应的目标函数,并通过ASM字节码操作在目标函数执行前后插入静态回调函数。
+ ASM 仪器结构示意图
4. ASM字节码操作
在构造时,通过实现并重写方法,在方法访问流中添加ASM切面适配器,通过实现ASM,可以通过回调函数访问方法进入和方法退出的时机,此时插入需要返回的代码,通过此实例来操作字节码。
APM性能平台代码变更诊断项目
接下来是整个平台之间的交互和请求流程,总共涉及3个系统和一个构建插件配合完成。当性能平台发现集成导致的性能下降问题时,首先触发常规性能诊断任务,判断是否是线程、切换等导致的性能问题,然后触发代码变更检测任务。首先请求code diff系统计算变更的代码。将变更的代码存储起来,请求合作的构建系统,通过构建插件的配合,将变更的代码插入到构建系统中。最后输出两个APK,一个是带有插入APK的基线版本,一个是带有插入APK的目标版本。将两个APK返回给APM性能平台。通过场景覆盖可以知道变更代码的变更是否影响到场景的耗时性能。
代码变更诊断解决方案
案件
步骤 1:版本 10.1.92.4310 的集成导致冷启动阶段减慢 60 毫秒
第 2 步:总体性能诊断报告显示,运行了一个额外 486.4 毫秒的线程。
步骤3:代码变更诊断任务报告,可以定位问题代码(整合变更文件4310个,14个文件,更改了538行代码)
4. SDK4.1原理SDK实现原理详解
为了将冷启动能力扩展到其他场景,我们将场景拆分能力和数据转储能力抽象成了 SDK,也就是现在的 SDK。其他业务场景只要接入 SDK,就可以拥有冷启动度量和诊断能力,比如扫码、首页等业务。以下是场景拆分的示例:
SDK 场景分割示例
一个场景比如冷启动、扫码、首页渲染等,可以分为几个大阶段,比如图中有3个大阶段,分别为1,2,,而每个大阶段又可以分为若干个子阶段,需要按照业务逻辑模块进行划分。每个业务或者阶段又分为开始()和结束(end),开始和结束要一一对应,也就是要有开始和结束,如果不对应,那么最终生成的数据中将不包含该阶段的数据统计。注意:子阶段是在业务之后,结束之前,如果超出范围,则不统计。业务结束后,需要用户调用()进行接口回调。此时可以记录离线性能数据,作为可扩展的字段,根据业务需求,可以自定义数据,用于告知离线数据统计。
SDK 实现
SDK 功能
1、具备场景拆分、度量能力,并能收集性能诊断数据;
2、具有场景还原功能,通过标记时间,可以现场还原整个场景代码模块的执行顺序;
3.支持线上场景时耗度量+线程诊断能力,辅助线上问题定位;
4、数据采集模块实现线上线下分离,不影响在线用户。
5. APM 性能平台
有了终端上的度量、诊断能力、SDK的能力,当然少不了平台能力的支持,它贯穿了整个研发、期中、发布过程。下面是APM性能平台整体架构图,主要包括对接研发流程的持续集成能力,以及与合作伙伴代码diff系统、构建系统、真机平台任务调度系统的请求和交互。
APM性能平台架构图
通过持续集成能力,可以针对每一次集成实现性能维度的度量与诊断,同时提供手动触发任务,方便开发者在研发项目中尝试性能优化以及验证代码变更是否对性能产生影响。
各个版本大量的持续集成任务、人工验证任务,都离不开平台的任务调度能力和任务队列管理。采用任务状态+设备锁的机制,保证任务有序执行。真机实验采用场景设备分组的方式,让特定场景在特定的设备组上运行任务,巧妙地分散了任务集中的问题。
有了SDK客户端上的扩展能力,平台的扩展性支持也必不可少。平台的配置中心已经自动化了驱动脚本的扩展性支持,为新场景的接入提供了便利。新场景的接入只需要在平台上进行配置,通过配置场景、对应的设备组以及驱动脚本,即可完成新场景的接入,平台无需更改任务代码,新场景的接入仅需2小时。
六、结论
支付宝APM性能平台已支撑支付场景及链路性能体验优化、调用端及拉新用户性能优化、端内首跳及线程管理、功耗管理、低端机优化等多项性能体验优化活动,保障各端场景性能体验优化顺利完成,维护优化成果,零回归,提供的SDK及性能诊断能力赋能研发同仁。
支付宝内的APM将逐步从重点场景覆盖端的全方位性能监控,内存、卡顿、线程等维度的性能检测、测量和诊断也将纳入APM。
支付宝的APM平台也在不断升级,拥有独立的系统和域名,采用+OB存储,数据存储能力和效率都有了很大的提升,UI设计和报表展示也变得更加人性化。客户至上,为了给用户提供更好的使用体验,我们会继续努力优化低端机,在发现细微的性能问题上继续探索和深挖。
七、相关技术信息
#
#()