一、提升性能核心要素
1、将OPENGL 接口进行穿透调用,下面对opengl穿透做个小结;
2、在arm开发板上打开kvm特性,这个qcom&mtk都是实现了的,只需要打开开关即可。
二、ANDROID OPENGL 业务实现细节解释
1、 OPENGL命令队列是确定了,可是命令的参数,有的是系统给的,有的是上一个命令计算的结果,例如纹理操作,首先调用API创建一个纹理,得到纹理标记,然后后面再使用API操作该纹理时,就是使用这个纹理标记的。因此如果遇到这个创建纹理的API,则要把以前积累的API队列传到host端,依次执行,最后得到这个API的结果,然后回传,这个过程是循环执行,直到遇到最终API后,把剩余的API队列传到HOST端,这一帧才算完;
2、 OPENGL命令队列有时候根据一个API的结果会有变化的,APP的四个绘制过程只是把系统给的参数计算完,如果遇到需要API计算参数的,同样会先把积压的API计算完,然后根据结果选择分支路径。所以ANDROID系统的那四个过程并不是完全独立的,它们之间有一些重叠。最好的APP,就要把这种重叠降低到最少。APP想要运行效率高,就是要非常利索的一次生成命令队列,减少打断。
三、opengl 远程调用技术小结。
A:业务层面
1、 本来是一帧的命令队列一次性传递,但由于有打断,所以实际情况是一帧的命令队列分批传递。
2、 一些特殊的API耗时比较严重;一些接口并不需要回传参数;一些接口是远程调用特有的,例如合成过程都综合在一个远程“接口”中,后端一遇到这种标记就知道要合成了。
3、 一些特殊的API会由于业务约束被分解为数个API进行远程调用,这个情况会在opengl 1.0中非常常见,后续的版本则会少一些。
4、 API1.0 = 271 API2.0=208 EGLAPI=43 远程调用API=25 总共547个接口,只熟悉其中核心的43+25+50?+50?来个接口,生僻或者看名字就知道干啥的就没有细细研究。
B:技术层面
1、 每个API中通过包装API标记、参数,得到字节序列,写入PIPE驱动。
2、 由于VM内存页分配不是连续的,PIPE驱动会把远程数据地址分几次传递给QEMU。
3、 QEMU得到地址后,经过地址转换,获得远程数据,也是分批写入socket的。
4、 OPENGL THREAD也会分几次接收到远程数据,解析得到API标记和参数。
5、 依次根据API标记调用API。
6、 得到结果后由OPENGL THREAD写入socket。
7、 QEMU从socket得到结果,经过地址转换,将数值写入相关内存区域。
8、 VM读PIPE驱动得到结果后,一次远程调用结束。(其中VM读PIPE驱动和OPENGL THREAD 执行是并行运行的)
C:性能层面
1、 普通应用一帧的耗时在10-30毫秒,特殊应用一帧的耗时就非常差了。
2、 一次远程调用的耗时在3571.9微秒,去掉OPENGL API执行时间耗时在2367.8微秒。
D:优化层面
1、 业务方面:检查每个API是否有无效操作,去掉无效操作,应该能大幅提升性能。
2、 技术方面:去掉socket技术,去掉一个进程,将OPENGL THREAD合进QEMU,应该能较小的提升性能。
四、性能测试:
1、 测试办法:采用android系统工具gfxinfo提取一段时间内APP每一帧所消耗的时间;
2、 测试条件:kvm预设FPS=60(每秒提交60帧 同开发板) w*h=1080*1920(图像宽度和高度 同开发板) x_dpi*y_dpi=72*72(像素密度 开发板是480*480);
3、 测试标准:密集操作一个APP核心功能,然后提取系统数据;
4、 测试结果:普通应用kvm的性能比真机延时10-30ms左右,人感觉不到卡顿;游戏应用kvm的性能延时厉害,没有提取到有效数据,每秒大概5-10帧,人能明显感觉卡顿;
5、 结果分析:Draw->Prepare->Process->Execute 是任何应用都要经历的四个绘制过程;
Draw准备opengl指令列表、Prepare提交opengl指令列表、Process执行opengl指令列表、Execute提交最终像素帧;
数据是每过程所消耗的时间,单位是毫秒,如果四个过程总时间消耗小于16ms,则认为应用流畅性比较好;
Draw过程kvm性能优于真机,说明qemu模拟CPU性能较好;
Prepare、Process过程kvm和真机相当;
Execute过程kvm有较大延时,因为kvm在这一过程把opengl指令列表传递给真机,真机执行opengl指令,获取、合成最终图像;
此外游戏应用由于采用的API接口,参数不好传递,远程调用时分解为数个普通接口,导致指令列表臃肿,造成了较大延时;
整体分析过程符合代码逻辑,数据情理之中;
6、 测试结论:由于远程发送的是一帧的绘制指令集,而不是单个指令,所以kvm画面应该延时略小于一帧的时间;远程调用的过程略有耗时,但如果绘制指令列表特别长,则会严重影响性能;
1)、 系统桌面
2)、 折纸应用
3)、 CS场景
4)、 系统计算器
5)、 系统时钟应用
五、总结
性能效果:
1、操作桌面、一般的app都是比较流畅的;
2、操作复杂的游戏APP比较卡,会出现丢帧现象;
3、使用gfxinfo工具检测性能,会看见15~20MS的延迟每一帧。
粗略移植过程:
1、需要实体机的代码,调通kvm特性;
2、下载google android源码,最好是android 5.0 ,本文只在5.0版本上实验过,这份代码是vm android,内核使用goldfish版本;
3、将qemu交叉编译到实体机上,尝试跑通android 虚拟机,这个过程有很多BUG要解,最好使用本文提供的qemu版本,本文的qemu是从标准qemu分支拉出来的,最重要的这个qemu能穿透opengl接口,有GPU虚拟化方案和input虚拟化办法,并没有使用android模拟器的qemu,可以试一试android的qemu;
4、将提供的opengl代码编出来,运行在实体机中,它通过socket与qemu通信,执行一系列的opengl操作,并将虚拟机显示在一张surface中,最终虚拟机界面会出现在实体机中;
5、arm虚拟机双系统论文地址:https://systems.cs.columbia.edu/projects/kvm-arm/
6、GitHub地址:https://github.com/jianglin-code/qemu-of-arm-android